1dc6014cc6373a207b27e007c1aed111ea2dd17c
[profile/ivi/layer-management.git] / LayerManagerPlugins / Renderers / Graphic / src / WindowSystems / X11WindowSystem.cpp
1 /***************************************************************************
2 *
3 * Copyright 2010,2011 BMW Car IT GmbH
4 *
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *        http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ****************************************************************************/
19
20 #include "WindowSystems/X11WindowSystem.h"
21 #include "config.h"
22 #include "Log.h"
23 #include "Layer.h"
24 #include <time.h>
25 #include <sys/time.h>
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29 #include <X11/extensions/Xcomposite.h>
30 #include <X11/extensions/Xdamage.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <iomanip>
36
37 int     X11WindowSystem::composite_opcode;
38 int     X11WindowSystem::damage_opcode;
39 const char X11WindowSystem::CompositorWindowTitle[] = "LayerManager";
40 bool    X11WindowSystem::m_xerror = false;
41
42 X11WindowSystem::X11WindowSystem(const char* displayname,
43                                 int width,
44                                 int height,
45                                 Scene* pScene,
46                                 InputManager* pInputManager,
47                                 GetVisualInfoFunction func)
48 : BaseWindowSystem(pScene, pInputManager)
49 , takeScreenshot(ScreenShotNone)
50 , screenShotFile()
51 , screenShotSurfaceID(0)
52 , screenShotLayerID()
53 , displayname(displayname)
54 , getVisualFunc(func)
55 , debugMode(false)
56 , resolutionWidth(width)
57 , resolutionHeight(height)
58 , composite_event(0)
59 , composite_error(0)
60 , composite_major(0)
61 , composite_minor(0)
62 , damage_event(0)
63 , damage_error(0)
64 , damage_major(0)
65 , damage_minor(0)
66 , m_running(false)
67 /*, m_initialized(false)*/
68 , m_success(false)
69 , m_systemState(IDLE_STATE)
70 , m_displayEnvironment(NULL)
71 , x11Display(0)
72 , renderThread(0)
73 , windowWidth(width)
74 , windowHeight(height)
75 , CompositorWindow(0)
76 , windowVis(0)
77 , m_fpsinterval(10.0f)
78 , run_lock()
79 , graphicSystem(0)
80 {
81     LOG_DEBUG("X11WindowSystem", "creating X11WindowSystem");
82
83     // init and take mutex, so windowsystem only does init phase until mutex is released again
84     pthread_mutex_init(&run_lock, NULL);
85     pthread_cond_init(&run_condition, NULL);
86     pthread_cond_init(&init_condition, NULL);
87     pthread_mutex_init(&init_lock, NULL);
88 }
89
90 X11WindowSystem::~X11WindowSystem()
91 {
92     if (windowVis)
93     {
94         delete windowVis;
95     }
96 }
97
98 XVisualInfo* X11WindowSystem::getDefaultVisual(Display *dpy)
99 {
100     XVisualInfo* windowVis = new XVisualInfo();
101     if (windowVis)
102     {
103         windowVis->depth = DefaultDepth(dpy, DefaultScreen(dpy));
104         if (!XMatchVisualInfo(dpy, 0, windowVis->depth, TrueColor, windowVis))
105         {
106             LOG_ERROR("X11WindowSystem", "Error: Required visual not found\n");
107             delete windowVis;
108             return NULL;
109         }
110     }
111     else
112     {
113         LOG_ERROR("X11WindowSystem", "Error: Unable to acquire visual\n");
114     }
115     return windowVis;
116 }
117
118 bool X11WindowSystem::OpenDisplayConnection()
119 {
120     m_displayEnvironment = getenv("DISPLAY");
121
122     if (m_displayEnvironment == NULL)
123     {
124         m_displayEnvironment = ":0.0";
125         setenv("DISPLAY", m_displayEnvironment, 1);
126     }
127
128     x11Display = XOpenDisplay(m_displayEnvironment);
129     if (!x11Display)
130     {
131         LOG_ERROR("X11WindowSystem", "Couldn't open default display!");
132         return false;
133     }
134     LOG_DEBUG("X11WindowSystem", "Display connection: " << x11Display);
135     return true;
136 }
137
138 bool X11WindowSystem::checkForCompositeExtension()
139 {
140     if (x11Display == NULL || !XQueryExtension(x11Display, COMPOSITE_NAME, &composite_opcode, &composite_event, &composite_error))
141     {
142         LOG_ERROR("X11WindowSystem", "No composite extension");
143         return false;
144     }
145     XCompositeQueryVersion(x11Display, &composite_major, &composite_minor);
146     LOG_DEBUG("X11WindowSystem", "Found composite extension: composite opcode: " << composite_opcode);
147     LOG_DEBUG("X11WindowSystem", "composite_major: " << composite_major);
148     LOG_DEBUG("X11WindowSystem", "composite_minor: " << composite_minor);
149     return true;
150 }
151
152 bool X11WindowSystem::checkForDamageExtension()
153 {
154     if (x11Display == NULL || !XQueryExtension(x11Display, DAMAGE_NAME, &damage_opcode,
155                 &damage_event, &damage_error))
156     {
157         LOG_ERROR("X11WindowSystem", "No damage extension");
158         return false;
159     }
160     XDamageQueryVersion(x11Display, &damage_major, &damage_minor);
161     LOG_DEBUG("X11WindowSystem", "Found damage extension: damage opcode: " << damage_opcode);
162     LOG_DEBUG("X11WindowSystem", "damage_major: " << damage_major);
163     LOG_DEBUG("X11WindowSystem", "damage_minor: " << damage_minor);
164     return true;
165 }
166
167 void X11WindowSystem::printDebug()
168 {
169     // print stuff about layerlist
170     std::stringstream debugmessage;
171     debugmessage << "Layer:  ID |   X  |   Y  |   W  |   H  | Al. \n";
172
173     LayerList list = m_pScene->getCurrentRenderOrder(0);
174
175     // loop the layers
176     LayerListConstIterator iter = list.begin();
177     LayerListConstIterator iterEnd = list.end();
178
179     for (; iter != iterEnd; ++iter)
180     {
181         Rectangle dest = (*iter)->getDestinationRegion();
182         debugmessage << "            " << std::setw(4) << (*iter)->getID() << " " << std::setw(3) << dest.x << " " << std::setw(3) << dest.y << " " << std::setw(3) << dest.width << " " << std::setw(3) << dest.height << " " << std::setw(3) << (*iter)->opacity << "\n";
183
184         debugmessage << "    Surface:  ID |Al.|  SVP: X |  Y |  W |  H     DVP:  X |  Y |  W |  H \n";
185
186         // loop the surfaces of within each layer
187         SurfaceList surfaceList = (*iter)->getAllSurfaces();
188         SurfaceListIterator surfaceIter = surfaceList.begin();
189         SurfaceListIterator surfaceIterEnd = surfaceList.end();
190
191         for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
192         {
193             Rectangle src = (*surfaceIter)->getSourceRegion();
194             Rectangle dest = (*surfaceIter)->getDestinationRegion();
195             debugmessage << "                        " << std::setw(4) << (*surfaceIter)->getID() << " " << std::setprecision(3) << (*surfaceIter)->opacity << " " << std::setw(3) << src.x << " " << std::setw(3) << src.y << " " << std::setw(3) << src.width << " " << std::setw(3) << src.height << " " << std::setw(3) << dest.x << " " << std::setw(3) << dest.y << " " << std::setw(3) << dest.width << " " << std::setw(3) << dest.height << "\n";
196         }
197     }
198     LOG_DEBUG("X11WindowSystem", debugmessage.str());
199 }
200
201 Window * getListOfAllTopLevelWindows(Display *disp, unsigned int *len)
202 {
203     LOG_DEBUG("X11WindowSystem", "Getting list of all windows");
204     Window *children;
205     Window root_return;
206     Window parent_return;
207     Window root = XDefaultRootWindow(disp);
208     XQueryTree(disp, root, &root_return, &parent_return, &children, len);
209     return children;
210 }
211
212 bool X11WindowSystem::isWindowValid(Window w)
213 {
214     // skip our own two windows
215     return (w != None && w != CompositorWindow);
216 }
217
218 Surface* X11WindowSystem::getSurfaceForWindow(Window w)
219 {
220     // go though all surfaces
221     const std::map<unsigned int, Surface*> surfaces = m_pScene->getAllSurfaces();
222     for (std::map<unsigned int, Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); ++currentS)
223     {
224         Surface* currentSurface = (*currentS).second;
225         if (!currentSurface)
226         {
227             continue;
228         }
229         if (currentSurface->getNativeContent() == static_cast<int>(w))
230         {
231             return currentSurface;
232         }
233     }
234     LOG_DEBUG("X11WindowSystem", "could not find surface for window " << w);
235     return NULL;
236 }
237
238 void X11WindowSystem::checkForNewSurfaceNativeContent()
239 {
240     m_pScene->lockScene();
241     LayerList layers = m_pScene->getCurrentRenderOrder(0);
242     for (LayerListConstIterator current = layers.begin(); current != layers.end(); current++)
243     {
244         SurfaceList surfaces = (*current)->getAllSurfaces();
245         for (SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
246         {
247             if ((*currentS)->hasNativeContent())
248             {
249                 allocatePlatformSurface(*currentS);
250             }
251             else // While we are at it, also cleanup any stale native content
252             {
253                 deallocatePlatformSurface(*currentS);
254             }
255         }
256     }
257     m_pScene->unlockScene();
258 }
259
260 void X11WindowSystem::configureSurfaceWindow(Window window)
261 {
262     if (isWindowValid(window))
263     {
264         LOG_DEBUG("X11WindowSystem", "Updating window " << window);
265         UnMapWindow(window);
266         MapWindow(window);
267         XWindowAttributes att;
268         XGetWindowAttributes(x11Display, window, &att);
269         int winWidth = att.width;
270         int winHeight = att.height;
271
272         Surface* surface = getSurfaceForWindow(window);
273         if (!surface)
274         {
275             LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
276             return;
277         }
278         if (!surface->platform)
279         {
280             LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
281             return;
282         }
283
284         LOG_DEBUG("X11WindowSystem", "Updating surface " << surface->getID());
285
286         surface->OriginalSourceHeight = winHeight;
287         surface->OriginalSourceWidth = winWidth;
288
289         LOG_DEBUG("X11WindowSystem", "Done Updating window " << window);
290     }
291 }
292
293 void X11WindowSystem::MapWindow(Window window)
294 {
295     LOG_DEBUG("X11WindowSystem", "Map window begin");
296     if (isWindowValid(window))
297     {
298         XWindowAttributes att;
299         XGetWindowAttributes(x11Display, window, &att);
300 /*      LOG_DEBUG("X11WindowSystem", "XCompositeRedirectWindow()");
301         XCompositeRedirectWindow(x11Display, window, CompositeRedirectManual);
302         XSync(x11Display, 0);*/
303         if (att.map_state == IsViewable && att.override_redirect == 0)
304         {
305             LOG_DEBUG("X11WindowSystem", "Mapping surface to window " << window);
306             Surface* surface = getSurfaceForWindow(window);
307             if (!surface)
308             {
309                 LOG_WARNING("X11WindowSystem", "Could not map surface to window " << window);
310                 return;
311             }
312             if (!surface->platform)
313             {
314                 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
315                 return;
316             }
317
318             XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
319             if (x11surf->isMapped)
320             {
321                 LOG_WARNING("X11WindowSystem", "Platform surface already mapped");
322                 return;
323             }
324             x11surf->isMapped = true;
325
326             LOG_DEBUG("X11WindowSystem", "getting pixmap for window");
327             LOG_DEBUG("X11WindowSystem", "window width: " << att.width);
328             LOG_DEBUG("X11WindowSystem", "window height: " << att.height);
329             LOG_DEBUG("X11WindowSystem", "map state: " << att.map_state);
330             LOG_DEBUG("X11WindowSystem", "window x: " << att.x);
331             LOG_DEBUG("X11WindowSystem", "window backing: " << att.backing_pixel);
332             LOG_DEBUG("X11WindowSystem", "window save under: " << att.save_under);
333             LOG_DEBUG("X11WindowSystem", "window orride: " << att.override_redirect);
334             LOG_DEBUG("X11WindowSystem", "parent/root: " << att.root);
335             LOG_DEBUG("X11WindowSystem", "root window: " << DefaultRootWindow(x11Display));
336
337             int winWidth = att.width;
338             int winHeight = att.height;
339
340             surface->OriginalSourceHeight = winHeight;
341             surface->OriginalSourceWidth = winWidth;
342             surface->renderPropertyChanged = true;
343
344             graphicSystem->getTextureBinder()->createClientBuffer(surface);
345             x11surf->enableRendering();
346             XSync(x11Display, 0);
347
348             LOG_DEBUG("X11WindowSystem", "Mapping Surface " << surface->getID() << " to window " << window);
349             LOG_DEBUG("X11WindowSystem", "Mapping successfull");
350         }
351     }
352     LOG_DEBUG("X11WindowSystem", "Map window end");
353 }
354
355 void X11WindowSystem::UnMapWindow(Window window)
356 {
357     LOG_DEBUG("X11WindowSystem", "Unmap begin");
358     if (isWindowValid(window))
359     {
360         LOG_DEBUG("X11WindowSystem", "Unmapping surface from window " << window);
361         Surface* surface = getSurfaceForWindow(window);
362         if (!surface)
363         {
364             LOG_WARNING("X11WindowSystem", "Could not unmap window " << window);
365             return;
366         }
367         if (!surface->platform)
368         {
369             LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
370             return;
371         }
372         XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
373         x11surf->disableRendering();
374         LOG_DEBUG("X11WindowSystem", "Unmapping surface " << surface->getID());
375         if (!x11surf->isMapped)
376         {
377             LOG_WARNING("X11WindowSystem", "Platform surface already unmapped");
378             return;
379         }
380         x11surf->isMapped = false;
381
382         LOG_DEBUG("X11WindowSystem", "Destroying ClientBuffer");
383         graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
384         XSync(x11Display, 0);
385
386         LOG_DEBUG("X11WindowSystem", "Removing X Pixmap");
387         if (x11surf->pixmap)
388         {
389             int result = XFreePixmap(x11Display, x11surf->pixmap);
390             LOG_DEBUG("X11WindowSystem", "XFreePixmap() returned " << result);
391         }
392
393         surface->renderPropertyChanged = true;
394     }
395     LOG_DEBUG("X11WindowSystem", "Unmap finished");
396 }
397
398 void X11WindowSystem::NewWindow(Surface* surface, Window window)
399 {
400     if (isWindowValid(window))
401     {
402         LOG_DEBUG("X11WindowSystem", "Creating Surface for new window " << window);
403         // get the windows attributes
404         XWindowAttributes att;
405         int status = XGetWindowAttributes(x11Display, window, &att);
406         LOG_DEBUG("X11WindowSystem", "Got window attrbutes");
407         char* name;
408         status = XFetchName(x11Display, window, &name);
409         LOG_DEBUG("X11WindowSystem", "Got window name");
410         if (status >= Success && name)
411         {
412             LOG_DEBUG("X11WindowSystem", "Found window: " << window << " " << name);
413             char GuiTitle[]  = "Layermanager Remote GUI\0";
414             if (strcmp(name, GuiTitle) == 0)
415             {
416                 LOG_DEBUG("X11WindowSystem", "Found gui window: repositioning it");
417                 XCompositeUnredirectWindow(x11Display, window, CompositeRedirectManual);
418                 XMoveWindow(x11Display, window, 50, 500);
419                 XMapRaised(x11Display, window);
420             }
421         }
422         else
423         {
424             LOG_DEBUG("X11WindowSystem", "Error fetching window name");
425         }
426
427         if (att.c_class == InputOutput)
428         {
429             LOG_DEBUG("X11WindowSystem", "Creating New Damage for window - " << window);
430             XDamageCreate(x11Display, window, XDamageReportNonEmpty);
431         }
432
433         XFree(name);
434         XLowerWindow(x11Display, window);
435
436         surface->setNativeContent(window);
437         XPlatformSurface * platformSurface = (XPlatformSurface*)graphicSystem->getTextureBinder()->createPlatformSurface(surface);
438         platformSurface->isMapped = false;
439
440         LOG_DEBUG("X11WindowSystem", "Created native Surface for X11 Window id " << window);
441
442         surface->platform = platformSurface;
443
444         int winWidth = att.width;
445         int winHeight = att.height;
446
447         surface->OriginalSourceHeight = winHeight;
448         surface->OriginalSourceWidth = winWidth;
449
450         LOG_DEBUG("X11WindowSystem", "Original width " << surface->OriginalSourceWidth);
451         LOG_DEBUG("X11WindowSystem", "Original heigth " << surface->OriginalSourceHeight);
452     }
453     else
454     {
455         LOG_DEBUG("X11WindowSystem", "skipping window");
456     }
457     LOG_DEBUG("X11WindowSystem", "created the new surface");
458 }
459
460 void X11WindowSystem::DestroyWindow(Window window)
461 {
462     if (isWindowValid(window))
463     {
464         LOG_DEBUG("X11WindowSystem", "Destroying Surface for window " << window);
465         Surface* surface = getSurfaceForWindow(window);
466         if (!surface)
467         {
468             LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
469             return;
470         }
471         graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
472         LOG_DEBUG("X11WindowSystem", "Unmapping window " << window);
473         UnMapWindow(window);
474         LOG_DEBUG("X11WindowSystem", "Remove Native Content from Surface " << surface->getID());
475         surface->removeNativeContent();
476         /* To force a recomposition of all surface which are behind of that surface inside the Layer RenderOrder */
477         surface->renderPropertyChanged = true;
478         delete surface->platform;
479         surface->platform = NULL;
480     }
481 }
482
483 bool X11WindowSystem::CreatePixmapsForAllWindows()
484 {
485     bool result = true;
486     LOG_DEBUG("X11WindowSystem", "redirecting all windows");
487     Window root = RootWindow(x11Display, DefaultScreen(x11Display));
488     XCompositeRedirectSubwindows(x11Display, root, CompositeRedirectManual);
489     XSync(x11Display, 0);
490     return result;
491 }
492
493 bool X11WindowSystem::CreateCompositorWindow()
494 {
495     LOG_DEBUG("X11WindowSystem", "Get root window");
496     bool result = true;
497     CompositorWindow = None;
498     Window root = RootWindow(x11Display, DefaultScreen(x11Display));
499
500     LOG_DEBUG("X11WindowSystem", "Creating Compositor Window");
501
502     XSetWindowAttributes attr;
503     // draw a black background the full size of the resolution
504     attr.override_redirect = True;
505     attr.event_mask = ExposureMask
506                         | StructureNotifyMask
507                         | ButtonPressMask
508                         | ButtonReleaseMask
509                         | Button1MotionMask
510                         | KeyPressMask
511                         | KeyReleaseMask;
512     attr.background_pixel = 0;
513     attr.border_pixel = 0;
514     windowVis = getVisualFunc(x11Display);
515     if (!windowVis)
516     {
517         return false;
518     }
519     attr.colormap = XCreateColormap(x11Display, root, windowVis->visual, AllocNone);
520     attr.override_redirect = True;
521
522     Window compManager = XGetSelectionOwner(x11Display, XInternAtom(x11Display, "_NET_WM_CM_S0", 0));
523     if (None != compManager)
524     {
525         LOG_ERROR("X11WindowSystem", "Could not create compositor window, annother compisite manager is already running");
526         return false;
527     }
528
529     CompositorWindow = XCreateWindow(x11Display, root, 0, 0, windowWidth, windowHeight,
530             0, windowVis->depth, InputOutput,
531             windowVis->visual, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &attr);
532
533     if (None == CompositorWindow)
534     {
535         LOG_ERROR("X11WindowSystem", "Could not create window");
536         return false;
537     }
538
539     LOG_DEBUG("X11WindowSystem", "Created the Compositor Window");
540     XSelectInput(x11Display, root,
541             SubstructureNotifyMask|
542             ExposureMask|
543             StructureNotifyMask|
544             PropertyChangeMask);
545
546     LOG_DEBUG("X11WindowSystem", "Created the window");
547     XSizeHints sizehints;
548     sizehints.width = windowWidth;
549     sizehints.height = windowHeight;
550     sizehints.flags = USSize;
551     XSetNormalHints(x11Display, CompositorWindow, &sizehints);
552     XSetStandardProperties(x11Display, CompositorWindow, CompositorWindowTitle, CompositorWindowTitle,
553             None, (char **)NULL, 0, &sizehints);
554     XMapRaised(x11Display, CompositorWindow);
555     XFlush(x11Display);
556     return result;
557 }
558
559 static float timeSinceLastCalc = 0.0;
560 static float FPS = 0.0;
561 static struct timeval tv;
562 static struct timeval tv0;
563 static int Frame = 0;
564
565
566 void X11WindowSystem::calculateSurfaceFps(Surface *currentSurface, float time)
567 {
568     char floatStringBuffer[256];
569     float surfaceUpdateFps = ((float)(currentSurface->updateCounter)) / time;
570     float surfaceDrawFps = ((float)(currentSurface->drawCounter)) / time;
571     sprintf(floatStringBuffer, "0x%08x update fps: %3.2f", currentSurface->getID(), surfaceUpdateFps);
572     currentSurface->updateCounter = 0;
573     LOG_INFO("X11WindowSystem", "Surface " << floatStringBuffer);
574     sprintf(floatStringBuffer, "0x%08x draw fps: %3.2f", currentSurface->getID(), surfaceDrawFps);
575     currentSurface->drawCounter = 0;
576     LOG_INFO("X11WindowSystem", "Surface " << floatStringBuffer);
577 }
578
579 void X11WindowSystem::calculateFps()
580 {
581     // we have rendered a frame
582     Frame ++;
583     std::list<Layer*> layers = m_pScene->getCurrentRenderOrder(0);
584     // every 3 seconds, calculate & print fps
585     gettimeofday(&tv, NULL);
586     timeSinceLastCalc = (float)(tv.tv_sec-tv0.tv_sec) + 0.000001*((float)(tv.tv_usec-tv0.tv_usec));
587
588     if (timeSinceLastCalc > m_fpsinterval)
589     {
590         FPS = ((float)(Frame)) / timeSinceLastCalc;
591         char floatStringBuffer[256];
592         sprintf(floatStringBuffer, "Overall fps: %f", FPS);
593         for (std::list<Layer*>::const_iterator current = layers.begin(); current != layers.end(); ++current)
594         {
595             SurfaceList surfaceList = (*current)->getAllSurfaces();
596             SurfaceListIterator surfaceIter = surfaceList.begin();
597             SurfaceListIterator surfaceIterEnd = surfaceList.end();
598             for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
599             {
600                 calculateSurfaceFps((*surfaceIter), timeSinceLastCalc);
601             }
602         }
603         LOG_INFO("X11WindowSystem", floatStringBuffer);
604         tv0 = tv;
605         Frame = 0;
606     }
607 }
608
609 void X11WindowSystem::RedrawAllLayers(bool clear, bool swap)
610 {
611     LayerList layers = m_pScene->getCurrentRenderOrder(0);
612     LayerList swLayers;
613
614     // Refresh HW Layers, find SW Layers
615     for (LayerListConstIterator current = layers.begin(); current != layers.end(); ++current)
616     {
617         if ((*current)->getLayerType() == Hardware)
618         {
619             // Redraw HW layers independently of other layers
620             if (m_forceComposition || graphicSystem->needsRedraw(*current))
621             {
622                 renderHWLayer(*current);
623             }
624         }
625         else
626         {
627             swLayers.push_back(*current);
628         }
629     }
630
631     if (m_forceComposition || graphicSystem->needsRedraw(swLayers))
632     {
633         graphicSystem->renderSWLayers(swLayers, clear);
634
635         if (swap)
636         {
637             graphicSystem->swapBuffers();
638         }
639
640         if (debugMode)
641         {
642             printDebug();
643         }
644
645         calculateFps();
646     }
647 }
648
649 void X11WindowSystem::renderHWLayer(Layer *layer)
650 {
651     (void)layer;
652 }
653
654 void X11WindowSystem::Redraw()
655 {
656     // draw all the layers
657     /*LOG_INFO("X11WindowSystem","Locking List");*/
658     m_pScene->lockScene();
659
660     RedrawAllLayers(true, true);  // Clear and Swap
661     ClearDamage();
662
663     m_pScene->unlockScene();
664
665     m_forceComposition = false;
666 }
667
668 void X11WindowSystem::Screenshot()
669 {
670     /*LOG_INFO("X11WindowSystem","Locking List");*/
671     m_pScene->lockScene();
672     if (takeScreenshot == ScreenshotOfDisplay)
673     {
674         LOG_DEBUG("X11WindowSystem", "Taking screenshot");
675         RedrawAllLayers(true, false);  // Do clear, Don't swap
676     }
677     else if (takeScreenshot == ScreenshotOfLayer)
678     {
679         LOG_DEBUG("X11WindowSystem", "Taking screenshot of layer");
680         Layer* layer = m_pScene->getLayer(screenShotLayerID);
681
682         if (layer != NULL)
683         {
684             graphicSystem->renderSWLayer(layer, true); // Do clear
685         }
686     }
687     else if (takeScreenshot == ScreenshotOfSurface)
688     {
689         LOG_DEBUG("X11WindowSystem", "Taking screenshot of surface");
690         Layer* layer = m_pScene->getLayer(screenShotLayerID);
691         Surface* surface = m_pScene->getSurface(screenShotSurfaceID);
692
693         graphicSystem->clearBackground();
694         if (layer != NULL && surface != NULL)
695         {
696             graphicSystem->beginLayer(layer);
697             graphicSystem->renderSurface(surface);
698             graphicSystem->endLayer();
699         }
700     }
701
702     graphicSystem->saveScreenShotOfFramebuffer(screenShotFile);
703     takeScreenshot = ScreenShotNone;
704     LOG_DEBUG("X11WindowSystem", "Done taking screenshot");
705     m_pScene->unlockScene();
706     /*LOG_INFO("X11WindowSystem","UnLocking List");*/
707 }
708
709 int
710 X11WindowSystem::error(Display *dpy, XErrorEvent *ev)
711 {
712     const char* name = NULL;
713     static char buffer[256];
714
715     if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows)
716     {
717         LOG_ERROR("X11WindowSystem", "Maybe another composite manager is already running");
718     }
719
720     if (!name)
721     {
722         buffer[0] = '\0';
723         XGetErrorText(dpy, ev->error_code, buffer, sizeof(buffer));
724         name = buffer;
725     }
726     name = (strlen(name) > 0) ? name : "unknown";
727     LOG_ERROR("X11WindowSystem", "X Error: " << (int)ev->error_code << " " << name << " request : " << (int)ev->request_code << " minor: " <<  (int)ev->minor_code << " serial: " << (int)ev->serial);
728     m_xerror = true;
729     return 0;
730 }
731
732 bool X11WindowSystem::initXServer()
733 {
734     LOG_DEBUG("X11WindowSystem", "Initialising XServer connection");
735     bool result = true;
736
737     //setDisplayMode();
738     if (!CreateCompositorWindow())
739     {
740         LOG_ERROR("X11WindowSystem", "Compositor Window creation failed ");
741         return false;
742     }
743
744     LOG_DEBUG("X11WindowSystem", "Compositor Window ID: " << CompositorWindow);
745
746     if (CreatePixmapsForAllWindows())
747     {
748             //unredirect our window
749 #ifdef FULLSCREEN
750         XCompositeUnredirectWindow(x11Display, background, CompositeRedirectManual);
751 #endif
752         XCompositeUnredirectWindow(x11Display, CompositorWindow, CompositeRedirectManual);
753         LOG_DEBUG("X11WindowSystem", "Initialised XServer connection complete");
754     }
755     else
756     {
757         LOG_ERROR("X11WindowSystem", "Initialised XServer connection failed");
758         result = false;
759     }
760
761     return result;
762 }
763
764 /**
765  * Thread in charge of the CompositorWindow eventloop
766  * Friend function of class X11WindowSystem
767  */
768 void * X11eventLoopCallback(void *ptr)
769 {
770     X11WindowSystem *windowsys = static_cast<X11WindowSystem*>((X11WindowSystem*) ptr);
771     return windowsys->EventLoop();
772 }
773
774 void* X11WindowSystem::EventLoop()
775 {
776     // INITALIZATION
777     LOG_INFO("X11WindowSystem", "XServer initialisation");
778     pthread_mutex_lock(&this->init_lock);
779     pthread_mutex_lock(&this->run_lock);
780     bool status = true;
781     bool checkRedraw = false;
782
783     XSetErrorHandler(error);
784     // init own stuff
785     LOG_DEBUG("X11WindowSystem", "open display connection");
786     status &= this->OpenDisplayConnection();
787     if (status == false) goto init_complete;
788     LOG_DEBUG("X11WindowSystem", "check for composite extension");
789     status &= this->checkForCompositeExtension();
790     if (status == false) goto init_complete;
791     LOG_DEBUG("X11WindowSystem", "check for damage extension");
792     status &= this->checkForDamageExtension();
793     if (status == false) goto init_complete;
794     LOG_DEBUG("X11WindowSystem", "init xserver");
795     status &= this->initXServer();
796     if (status == false) goto init_complete;
797     LOG_INFO("X11WindowSystem", "XServer initialisation completed");
798     LOG_DEBUG("X11WindowSystem", "Graphicsystem initialisation");
799     status &= this->graphicSystem->init(this->x11Display, this->CompositorWindow);
800     LOG_DEBUG("X11WindowSystem", "Graphicsystem initialisation complete");
801 init_complete:
802     this->m_success = status;
803     pthread_cond_signal(&this->init_condition);
804     pthread_mutex_unlock(&this->init_lock);
805     // Done with init, wait for lock to actually run (ie start/stop method called)
806     LOG_DEBUG("X11WindowSystem", "Waiting for startup");
807     pthread_cond_wait(&this->run_condition, &this->run_lock);
808     pthread_mutex_unlock(&this->run_lock);
809     LOG_DEBUG("X11WindowSystem", "Starting Event loop");
810     Layer* defaultLayer = 0;
811
812     // run the main event loop while rendering
813     gettimeofday(&tv0, NULL);
814     if (this->debugMode)
815     {
816         defaultLayer = this->m_pScene->createLayer(0, 0);
817         defaultLayer->setOpacity(1.0);
818         defaultLayer->setDestinationRegion(Rectangle(0, 0, this->resolutionWidth, this->resolutionHeight));
819         defaultLayer->setSourceRegion(Rectangle(0, 0, this->resolutionWidth, this->resolutionHeight));
820         this->m_pScene->getCurrentRenderOrder(0).push_back(defaultLayer);
821     }
822     LOG_INFO("X11WindowSystem", "Enter render loop");
823
824     // clear screen to avoid garbage on startup
825     this->graphicSystem->clearBackground();
826     this->graphicSystem->swapBuffers();
827     XFlush(this->x11Display);
828
829     while (this->m_running)
830     {
831         XEvent event;
832         // blocking wait for event
833         XNextEvent(this->x11Display, &event);
834         this->m_pScene->lockScene();
835         switch (event.type)
836         {
837         case CreateNotify:
838             {
839                 if (this->debugMode)
840                 {
841                     LOG_DEBUG("X11WindowSystem", "CreateNotify Event");
842                     Surface* s = this->m_pScene->createSurface(0, 0);
843                     s->setOpacity(1.0);
844                     this->NewWindow(s, event.xcreatewindow.window);
845                     defaultLayer->addSurface(s);
846                 }
847                 break;
848             }
849         case ConfigureNotify:
850             LOG_DEBUG("X11WindowSystem", "Configure notify Event");
851             this->configureSurfaceWindow(event.xconfigure.window);
852             checkRedraw = true;
853             break;
854
855         case DestroyNotify:
856             LOG_DEBUG("X11WindowSystem", "Destroy  Event");
857             this->DestroyWindow(event.xdestroywindow.window);
858             checkRedraw = true;
859             break;
860         case Expose:
861             LOG_DEBUG("X11WindowSystem", "Expose Event");
862             checkRedraw = true;
863             break;
864         case MapNotify:
865             LOG_DEBUG("X11WindowSystem", "Map Event");
866             this->MapWindow(event.xmap.window);
867             checkRedraw = true;
868             break;
869         case UnmapNotify:
870             LOG_DEBUG("X11WindowSystem", "Unmap Event");
871             this->UnMapWindow(event.xunmap.window);
872             checkRedraw = true;
873             break;
874         case ReparentNotify:
875             LOG_DEBUG("X11WindowSystem", "Reparent Event");
876             //           if (event.xreparent.parent == root)
877             //               renderer->NewWindow(event.xreparent.window);
878             //           else
879             //               renderer->DestroyWindow(event.xreparent.window);
880             break;
881
882         // Keyboard
883         case KeyPress:
884             ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_PRESSED, &event);
885             break;
886         case KeyRelease:
887             ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_RELEASED, &event);
888             break;
889
890         // Pointer
891         case ButtonPress:
892             ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_PRESSED, &event);
893             break;
894         case ButtonRelease:
895             ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_RELEASED, &event);
896             break;
897         case MotionNotify:
898             ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_MOTION, &event);
899             break;
900
901         // Touch
902         // TODO. See @ref<X11WindowSystem-MultiTouch> at the end of this file
903
904         default:
905             if (event.type == this->damage_event + XDamageNotify)
906             {
907                 XDamageSubtract(this->x11Display, ((XDamageNotifyEvent*)(&event))->damage, None, None);
908                 Surface* currentSurface = this->getSurfaceForWindow(((XDamageNotifyEvent*)(&event))->drawable);
909                 if (currentSurface == NULL)
910                 {
911                     LOG_WARNING("X11WindowSystem", "Surface empty during damage notification");
912                     break;
913                 }
914                 else
915                 {
916                     if (currentSurface->platform != NULL)
917                     {
918                         /* Enable Rendering for Surface, after damage Notification was send successfully */
919                         /* This will ensure, that the content is not dirty */
920                         ((XPlatformSurface *)(currentSurface->platform))->enableRendering();
921                     }
922                 }
923                 currentSurface->damaged = true;
924                 currentSurface->updateCounter++;
925                 checkRedraw = true;
926             }
927             break;
928         }
929         this->m_pScene->unlockScene();
930
931         if (this->m_systemState == REDRAW_STATE)
932         {
933             LOG_DEBUG("X11WindowSystem", "Enter Redraw State");
934             this->m_systemState = IDLE_STATE;
935
936             // check if we are supposed to take screenshot
937             if (this->takeScreenshot != ScreenShotNone)
938             {
939                 this->Screenshot();
940             }
941             else
942             {
943                 this->checkForNewSurfaceNativeContent();
944                 checkRedraw = true;
945             }
946         }
947         else if (this->m_systemState == WAKEUP_STATE)
948         {
949             LOG_DEBUG("X11WindowSystem", "Enter Wake Up State");
950             checkRedraw = false;
951             graphicSystem->releaseGraphicContext();
952             this->m_systemState = IDLE_STATE;
953             while (this->m_systemState != WAKEUP_STATE);
954             graphicSystem->activateGraphicContext();
955             this->m_systemState = IDLE_STATE;
956         }
957
958         if (checkRedraw)
959         {
960             this->Redraw();
961             checkRedraw = false;
962         }
963     }
964     this->cleanup();
965     LOG_DEBUG("X11WindowSystem", "Renderer thread finished");
966     return NULL;
967 }
968
969
970 void X11WindowSystem::ManageXInputEvent(InputDevice type, InputEventState state, XEvent *pevent)
971 {
972     Surface * surf;
973
974     switch (type)
975     {
976     case INPUT_DEVICE_KEYBOARD:
977         {
978             surf = m_pInputManager->reportKeyboardEvent(state, ((XKeyEvent *) pevent)->keycode);
979             if (surf != NULL)
980             {
981                 pevent->xany.window = surf->getNativeContent();
982                 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
983             }
984         }
985         break;
986
987     case INPUT_DEVICE_POINTER:
988         {
989             Point p = {state, ((XButtonEvent*)pevent)->x, ((XButtonEvent*)pevent)->y};
990             surf = m_pInputManager->reportPointerEvent(p);
991             if (surf != NULL)
992             {
993                 ((XButtonEvent*)pevent)->x = p.x;
994                 ((XButtonEvent*)pevent)->y = p.y;
995                 pevent->xany.window = surf->getNativeContent();
996                 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
997             }
998         }
999         break;
1000
1001     case INPUT_DEVICE_TOUCH:
1002         /* TODO */
1003         break;
1004
1005     default:
1006     case INPUT_DEVICE_ALL:
1007         break;
1008     }
1009 }
1010
1011
1012 static Display* displaySignal = NULL;
1013
1014 void X11WindowSystem::wakeUpRendererThread()
1015 {
1016     // send dummy expose event, to wake up blocking x11 event loop (XNextEvent)
1017     LOG_DEBUG("X11WindowSystem", "Sending dummy event to wake up renderer thread");
1018     if (NULL == displaySignal)
1019     {
1020         displaySignal = XOpenDisplay(m_displayEnvironment);
1021     }
1022     XExposeEvent ev = { Expose, 0, 1, displaySignal, CompositorWindow, 0, 0, 100, 100, 0 };
1023     XLockDisplay(displaySignal);
1024     XSendEvent(displaySignal, CompositorWindow, False, ExposureMask, (XEvent *) &ev);
1025     XUnlockDisplay(displaySignal);
1026     XFlush(displaySignal);
1027     LOG_DEBUG("X11WindowSystem", "Event successfully sent to renderer");
1028 }
1029
1030 void X11WindowSystem::signalRedrawEvent()
1031 {
1032     // set flag that redraw is needed
1033     this->m_systemState = REDRAW_STATE;
1034     this->wakeUpRendererThread();
1035 }
1036
1037 void X11WindowSystem::cleanup()
1038 {
1039     LOG_DEBUG("X11WindowSystem", "Cleanup");
1040     if (None != CompositorWindow)
1041     {
1042         Window root = RootWindow(x11Display, DefaultScreen(x11Display));
1043         XCompositeUnredirectSubwindows(x11Display, root, CompositeRedirectManual);
1044         XDestroyWindow(x11Display, CompositorWindow);
1045     }
1046
1047     if (windowVis)
1048     {
1049         delete windowVis;
1050     }
1051
1052     if (NULL != displaySignal)
1053     {
1054         XCloseDisplay(displaySignal);
1055     }
1056
1057     XCloseDisplay(x11Display);
1058     pthread_mutex_lock(&this->run_lock);
1059     m_running = false;
1060     pthread_mutex_unlock(&this->run_lock);
1061 }
1062
1063 bool X11WindowSystem::init(BaseGraphicSystem<Display*, Window>* base)
1064 {
1065     XInitThreads();
1066     X11WindowSystem *renderer = this;
1067     graphicSystem = base;
1068     LOG_INFO("X11WindowSystem", "Initialization");
1069     pthread_mutex_lock(&init_lock);
1070     int status = pthread_create(&renderThread, NULL, X11eventLoopCallback, (void*) renderer);
1071     if (0 != status)
1072     {
1073         pthread_mutex_unlock(&init_lock);
1074         return false;
1075     }
1076     mThreadId = renderThread;
1077
1078     pthread_cond_wait(&init_condition, &init_lock);
1079 /*  while (!m_initialized)
1080     {
1081         usleep(1000); // TODO
1082         LOG_DEBUG("X11WindowSystem","Waiting start complete " << m_initialized);
1083     }
1084 */
1085     pthread_mutex_unlock(&init_lock);
1086     LOG_INFO("X11WindowSystem", "Initialization complete success :" << m_success);
1087     return m_success;
1088 }
1089
1090 bool X11WindowSystem::start()
1091 {
1092     bool result = true;
1093     pthread_mutex_lock(&this->run_lock);
1094     LOG_DEBUG("X11WindowSystem", "Startup");
1095     // let thread actually run
1096     if (m_xerror == false)
1097     {
1098         this->m_running = true;
1099         pthread_cond_signal(&this->run_condition);
1100         pthread_mutex_unlock(&this->run_lock);
1101     }
1102     else
1103     {
1104         this->m_running = false;
1105         pthread_cond_signal(&this->run_condition);
1106         pthread_mutex_unlock(&this->run_lock);
1107         result = false;
1108     }
1109     return result;
1110 }
1111
1112 void X11WindowSystem::stop()
1113 {
1114     LOG_INFO("X11WindowSystem", "Stopping..");
1115     pthread_mutex_lock(&this->run_lock);
1116     this->m_running = false;
1117     // needed if start was never called, we wake up thread, so it can immediatly finish
1118     this->signalRedrawEvent();
1119     pthread_cond_signal(&this->run_condition);
1120     pthread_mutex_unlock(&this->run_lock);
1121     pthread_join(renderThread, NULL);
1122 }
1123
1124 void X11WindowSystem::allocatePlatformSurface(Surface* surface)
1125 {
1126     LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface begin");
1127     XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1128     if (!nativeSurface)
1129     {
1130         LOG_DEBUG("X11WindowSystem", "creating native surface for new window");
1131         // this surface does not have a native platform surface attached yet!
1132         NewWindow(surface, surface->getNativeContent());
1133         MapWindow(surface->getNativeContent());
1134     }
1135     LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface end");
1136 }
1137
1138 void X11WindowSystem::deallocatePlatformSurface(Surface* surface)
1139 {
1140     LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface begin");
1141     XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1142     if (nativeSurface)
1143     {
1144         LOG_DEBUG("X11WindowSystem", "destroyingnative surface");
1145         graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
1146
1147         if (nativeSurface->pixmap)
1148         {
1149             XFreePixmap(x11Display, nativeSurface->pixmap);
1150         }
1151
1152         surface->renderPropertyChanged = true;
1153         delete surface->platform;
1154         surface->platform = NULL;
1155     }
1156     LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface end");
1157 }
1158
1159 void X11WindowSystem::doScreenShot(std::string fileName)
1160 {
1161     takeScreenshot = ScreenshotOfDisplay;
1162     screenShotFile = fileName;
1163 }
1164
1165 void X11WindowSystem::doScreenShotOfLayer(std::string fileName, const uint id)
1166 {
1167     takeScreenshot = ScreenshotOfLayer;
1168     screenShotFile = fileName;
1169     screenShotLayerID = id;
1170 }
1171
1172 void X11WindowSystem::doScreenShotOfSurface(std::string fileName, const uint id, const uint layer_id)
1173 {
1174     takeScreenshot = ScreenshotOfSurface;
1175     screenShotFile = fileName;
1176     screenShotSurfaceID = id;
1177     screenShotLayerID = layer_id;
1178 }
1179
1180
1181
1182 /**
1183  * @subsection <X11WindowSystem-MultiTouch> (Multi Touch)
1184  *
1185  *   X11 multi touch is not yet supported by Layer Manager.
1186  *
1187  *   TODO to add support:
1188  *     - Move all event management to xi2
1189  *     - For multi touch, make sure XInput protocol is > 2.2
1190  *         -> Via cmake ==> ?
1191  *         -> At runtime ==> http://who-t.blogspot.fr/2011/12/multitouch-in-x-getting-events.html
1192  *     - Register for XIDirectTouch. (No plan (yet?) to support XIDependentTouch)
1193  *     - Call m_pInputManager->reportTouchEvent() from ManageXInputEvent() to translate screen wide touch coordinates
1194  *      into surface wide coordinates
1195  *     - Forward the event to the native handle of the surface returned by m_pInputManager->reportTouchEvent()
1196  *
1197  *   Further reading:
1198  *     + XInput 2.x protocol : ftp://www.x.org/pub/xorg/current/doc/inputproto/XI2proto.txt
1199  *     + LWN article : http://lwn.net/Articles/475886/
1200  *
1201  */
1202