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