1 /***************************************************************************
3 * Copyright 2010,2011 BMW Car IT GmbH
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 ****************************************************************************/
20 #include "WindowSystems/X11WindowSystem.h"
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29 #include <X11/extensions/Xcomposite.h>
30 #include <X11/extensions/Xdamage.h>
37 int X11WindowSystem::composite_opcode;
38 int X11WindowSystem::damage_opcode;
39 const char X11WindowSystem::CompositorWindowTitle[] = "LayerManager";
40 bool X11WindowSystem::m_xerror = false;
42 X11WindowSystem::X11WindowSystem(const char* displayname,
46 InputManager* pInputManager,
47 GetVisualInfoFunction func)
48 : BaseWindowSystem(pScene, pInputManager)
49 , takeScreenshot(ScreenShotNone)
51 , screenShotSurfaceID(0)
53 , displayname(displayname)
56 , resolutionWidth(width)
57 , resolutionHeight(height)
67 /*, m_initialized(false)*/
69 , m_systemState(IDLE_STATE)
70 , m_displayEnvironment(NULL)
74 , windowHeight(height)
77 , m_fpsinterval(10.0f)
81 LOG_DEBUG("X11WindowSystem", "creating X11WindowSystem");
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);
90 X11WindowSystem::~X11WindowSystem()
98 XVisualInfo* X11WindowSystem::getDefaultVisual(Display *dpy)
100 XVisualInfo* windowVis = new XVisualInfo();
103 windowVis->depth = DefaultDepth(dpy, DefaultScreen(dpy));
104 if (!XMatchVisualInfo(dpy, 0, windowVis->depth, TrueColor, windowVis))
106 LOG_ERROR("X11WindowSystem", "Error: Required visual not found\n");
113 LOG_ERROR("X11WindowSystem", "Error: Unable to acquire visual\n");
118 bool X11WindowSystem::OpenDisplayConnection()
120 m_displayEnvironment = getenv("DISPLAY");
122 if (m_displayEnvironment == NULL)
124 m_displayEnvironment = ":0.0";
125 setenv("DISPLAY", m_displayEnvironment, 1);
128 x11Display = XOpenDisplay(m_displayEnvironment);
131 LOG_ERROR("X11WindowSystem", "Couldn't open default display!");
134 LOG_DEBUG("X11WindowSystem", "Display connection: " << x11Display);
138 bool X11WindowSystem::checkForCompositeExtension()
140 if (x11Display == NULL || !XQueryExtension(x11Display, COMPOSITE_NAME, &composite_opcode, &composite_event, &composite_error))
142 LOG_ERROR("X11WindowSystem", "No composite extension");
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);
152 bool X11WindowSystem::checkForDamageExtension()
154 if (x11Display == NULL || !XQueryExtension(x11Display, DAMAGE_NAME, &damage_opcode,
155 &damage_event, &damage_error))
157 LOG_ERROR("X11WindowSystem", "No damage extension");
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);
168 void X11WindowSystem::printDebug()
170 // print stuff about layerlist
171 std::stringstream debugmessage;
172 debugmessage << "Layer: ID | X | Y | W | H | Al. \n";
174 LayerList list = m_pScene->getCurrentRenderOrder(0);
177 LayerListConstIterator iter = list.begin();
178 LayerListConstIterator iterEnd = list.end();
180 for (; iter != iterEnd; ++iter)
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";
185 debugmessage << " Surface: ID |Al.| SVP: X | Y | W | H DVP: X | Y | W | H \n";
187 // loop the surfaces of within each layer
188 SurfaceList surfaceList = (*iter)->getAllSurfaces();
189 SurfaceListIterator surfaceIter = surfaceList.begin();
190 SurfaceListIterator surfaceIterEnd = surfaceList.end();
192 for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
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";
199 LOG_DEBUG("X11WindowSystem", debugmessage.str());
202 Window * getListOfAllTopLevelWindows(Display *disp, unsigned int *len)
204 LOG_DEBUG("X11WindowSystem", "Getting list of all windows");
207 Window parent_return;
208 Window root = XDefaultRootWindow(disp);
209 XQueryTree(disp, root, &root_return, &parent_return, &children, len);
213 bool X11WindowSystem::isWindowValid(Window w)
215 // skip our own two windows
216 return (w != None && w != CompositorWindow);
219 Surface* X11WindowSystem::getSurfaceForWindow(Window w)
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)
225 Surface* currentSurface = (*currentS).second;
230 if (currentSurface->getNativeContent() == static_cast<int>(w))
232 return currentSurface;
235 LOG_DEBUG("X11WindowSystem", "could not find surface for window " << w);
239 void X11WindowSystem::checkForNewSurfaceNativeContent()
241 m_pScene->lockScene();
242 LayerList layers = m_pScene->getCurrentRenderOrder(0);
243 for (LayerListConstIterator current = layers.begin(); current != layers.end(); current++)
245 SurfaceList surfaces = (*current)->getAllSurfaces();
246 for (SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
248 if ((*currentS)->hasNativeContent())
250 allocatePlatformSurface(*currentS);
252 else // While we are at it, also cleanup any stale native content
254 deallocatePlatformSurface(*currentS);
258 m_pScene->unlockScene();
261 void X11WindowSystem::configureSurfaceWindow(Window window)
263 if (isWindowValid(window))
265 LOG_DEBUG("X11WindowSystem", "Updating window " << window);
268 XWindowAttributes att;
269 XGetWindowAttributes(x11Display, window, &att);
270 int winWidth = att.width;
271 int winHeight = att.height;
273 Surface* surface = getSurfaceForWindow(window);
276 LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
279 if (!surface->platform)
281 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
285 LOG_DEBUG("X11WindowSystem", "Updating surface " << surface->getID());
287 surface->OriginalSourceHeight = winHeight;
288 surface->OriginalSourceWidth = winWidth;
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);
296 void X11WindowSystem::MapWindow(Window window)
298 LOG_DEBUG("X11WindowSystem", "Map window begin");
299 if (isWindowValid(window))
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)
308 LOG_DEBUG("X11WindowSystem", "Mapping surface to window " << window);
309 Surface* surface = getSurfaceForWindow(window);
312 LOG_WARNING("X11WindowSystem", "Could not map surface to window " << window);
315 if (!surface->platform)
317 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
321 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
322 if (x11surf->isMapped)
324 LOG_WARNING("X11WindowSystem", "Platform surface already mapped");
327 x11surf->isMapped = true;
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));
340 int winWidth = att.width;
341 int winHeight = att.height;
343 surface->OriginalSourceHeight = winHeight;
344 surface->OriginalSourceWidth = winWidth;
345 surface->renderPropertyChanged = true;
347 graphicSystem->getTextureBinder()->createClientBuffer(surface);
348 x11surf->enableRendering();
349 XSync(x11Display, 0);
351 LOG_DEBUG("X11WindowSystem", "Mapping Surface " << surface->getID() << " to window " << window);
352 LOG_DEBUG("X11WindowSystem", "Mapping successfull");
355 LOG_DEBUG("X11WindowSystem", "Map window end");
358 void X11WindowSystem::UnMapWindow(Window window)
360 LOG_DEBUG("X11WindowSystem", "Unmap begin");
361 if (isWindowValid(window))
363 LOG_DEBUG("X11WindowSystem", "Unmapping surface from window " << window);
364 Surface* surface = getSurfaceForWindow(window);
367 LOG_WARNING("X11WindowSystem", "Could not unmap window " << window);
370 if (!surface->platform)
372 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
375 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
376 x11surf->disableRendering();
377 LOG_DEBUG("X11WindowSystem", "Unmapping surface " << surface->getID());
378 if (!x11surf->isMapped)
380 LOG_WARNING("X11WindowSystem", "Platform surface already unmapped");
383 x11surf->isMapped = false;
385 LOG_DEBUG("X11WindowSystem", "Destroying ClientBuffer");
386 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
387 XSync(x11Display, 0);
389 LOG_DEBUG("X11WindowSystem", "Removing X Pixmap");
392 int result = XFreePixmap(x11Display, x11surf->pixmap);
393 LOG_DEBUG("X11WindowSystem", "XFreePixmap() returned " << result);
396 surface->renderPropertyChanged = true;
398 LOG_DEBUG("X11WindowSystem", "Unmap finished");
401 void X11WindowSystem::NewWindow(Surface* surface, Window window)
403 if (isWindowValid(window))
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");
411 status = XFetchName(x11Display, window, &name);
412 LOG_DEBUG("X11WindowSystem", "Got window name");
413 if (status >= Success && name)
415 LOG_DEBUG("X11WindowSystem", "Found window: " << window << " " << name);
416 char GuiTitle[] = "Layermanager Remote GUI\0";
417 if (strcmp(name, GuiTitle) == 0)
419 LOG_DEBUG("X11WindowSystem", "Found gui window: repositioning it");
420 XCompositeUnredirectWindow(x11Display, window, CompositeRedirectManual);
421 XMoveWindow(x11Display, window, 50, 500);
422 XMapRaised(x11Display, window);
427 LOG_DEBUG("X11WindowSystem", "Error fetching window name");
430 if (att.c_class == InputOutput)
432 LOG_DEBUG("X11WindowSystem", "Creating New Damage for window - " << window);
433 XDamageCreate(x11Display, window, XDamageReportNonEmpty);
437 XLowerWindow(x11Display, window);
439 surface->setNativeContent(window);
440 XPlatformSurface * platformSurface = (XPlatformSurface*)graphicSystem->getTextureBinder()->createPlatformSurface(surface);
441 platformSurface->isMapped = false;
443 LOG_DEBUG("X11WindowSystem", "Created native Surface for X11 Window id " << window);
445 surface->platform = platformSurface;
447 int winWidth = att.width;
448 int winHeight = att.height;
450 surface->OriginalSourceHeight = winHeight;
451 surface->OriginalSourceWidth = winWidth;
453 LOG_DEBUG("X11WindowSystem", "Original width " << surface->OriginalSourceWidth);
454 LOG_DEBUG("X11WindowSystem", "Original heigth " << surface->OriginalSourceHeight);
458 LOG_DEBUG("X11WindowSystem", "skipping window");
460 LOG_DEBUG("X11WindowSystem", "created the new surface");
463 void X11WindowSystem::DestroyWindow(Window window)
465 if (isWindowValid(window))
467 LOG_DEBUG("X11WindowSystem", "Destroying Surface for window " << window);
468 Surface* surface = getSurfaceForWindow(window);
471 LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
474 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
475 LOG_DEBUG("X11WindowSystem", "Unmapping window " << 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;
486 bool X11WindowSystem::CreatePixmapsForAllWindows()
489 LOG_DEBUG("X11WindowSystem", "redirecting all windows");
490 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
491 XCompositeRedirectSubwindows(x11Display, root, CompositeRedirectManual);
492 XSync(x11Display, 0);
496 bool X11WindowSystem::CreateCompositorWindow()
498 LOG_DEBUG("X11WindowSystem", "Get root window");
500 CompositorWindow = None;
501 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
503 LOG_DEBUG("X11WindowSystem", "Creating Compositor Window");
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
515 attr.background_pixel = 0;
516 attr.border_pixel = 0;
517 windowVis = getVisualFunc(x11Display);
522 attr.colormap = XCreateColormap(x11Display, root, windowVis->visual, AllocNone);
523 attr.override_redirect = True;
525 Window compManager = XGetSelectionOwner(x11Display, XInternAtom(x11Display, "_NET_WM_CM_S0", 0));
526 if (None != compManager)
528 LOG_ERROR("X11WindowSystem", "Could not create compositor window, annother compisite manager is already running");
532 CompositorWindow = XCreateWindow(x11Display, root, 0, 0, windowWidth, windowHeight,
533 0, windowVis->depth, InputOutput,
534 windowVis->visual, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &attr);
536 if (None == CompositorWindow)
538 LOG_ERROR("X11WindowSystem", "Could not create window");
542 LOG_DEBUG("X11WindowSystem", "Created the Compositor Window");
543 XSelectInput(x11Display, root,
544 SubstructureNotifyMask|
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);
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;
569 void X11WindowSystem::calculateSurfaceFps(Surface *currentSurface, float time)
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);
582 void X11WindowSystem::calculateFps()
584 // we have rendered a 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));
591 if (timeSinceLastCalc > m_fpsinterval)
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)
598 SurfaceList surfaceList = (*current)->getAllSurfaces();
599 SurfaceListIterator surfaceIter = surfaceList.begin();
600 SurfaceListIterator surfaceIterEnd = surfaceList.end();
601 for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
603 calculateSurfaceFps((*surfaceIter), timeSinceLastCalc);
606 LOG_INFO("X11WindowSystem", floatStringBuffer);
612 void X11WindowSystem::RedrawAllLayers(bool clear, bool swap)
614 LayerList layers = m_pScene->getCurrentRenderOrder(0);
617 // Refresh HW Layers, find SW Layers
618 for (LayerListConstIterator current = layers.begin(); current != layers.end(); ++current)
620 if ((*current)->getLayerType() == Hardware)
622 // Redraw HW layers independently of other layers
623 if (m_forceComposition || graphicSystem->needsRedraw(*current))
625 renderHWLayer(*current);
630 swLayers.push_back(*current);
634 if (m_forceComposition || graphicSystem->needsRedraw(swLayers))
636 graphicSystem->renderSWLayers(swLayers, clear);
640 graphicSystem->swapBuffers();
652 void X11WindowSystem::renderHWLayer(Layer *layer)
657 void X11WindowSystem::Redraw()
659 // draw all the layers
660 /*LOG_INFO("X11WindowSystem","Locking List");*/
661 m_pScene->lockScene();
663 RedrawAllLayers(true, true); // Clear and Swap
666 m_pScene->unlockScene();
668 m_forceComposition = false;
671 void X11WindowSystem::Screenshot()
673 /*LOG_INFO("X11WindowSystem","Locking List");*/
674 m_pScene->lockScene();
675 if (takeScreenshot == ScreenshotOfDisplay)
677 LOG_DEBUG("X11WindowSystem", "Taking screenshot");
678 RedrawAllLayers(true, false); // Do clear, Don't swap
680 else if (takeScreenshot == ScreenshotOfLayer)
682 LOG_DEBUG("X11WindowSystem", "Taking screenshot of layer");
683 Layer* layer = m_pScene->getLayer(screenShotLayerID);
687 graphicSystem->renderSWLayer(layer, true); // Do clear
690 else if (takeScreenshot == ScreenshotOfSurface)
692 LOG_DEBUG("X11WindowSystem", "Taking screenshot of surface");
693 Layer* layer = m_pScene->getLayer(screenShotLayerID);
694 Surface* surface = m_pScene->getSurface(screenShotSurfaceID);
696 graphicSystem->clearBackground();
697 if (layer != NULL && surface != NULL)
699 graphicSystem->beginLayer(layer);
700 graphicSystem->renderSurface(surface);
701 graphicSystem->endLayer();
705 graphicSystem->saveScreenShotOfFramebuffer(screenShotFile);
706 takeScreenshot = ScreenShotNone;
707 LOG_DEBUG("X11WindowSystem", "Done taking screenshot");
708 m_pScene->unlockScene();
709 /*LOG_INFO("X11WindowSystem","UnLocking List");*/
713 X11WindowSystem::error(Display *dpy, XErrorEvent *ev)
715 const char* name = NULL;
716 static char buffer[256];
718 if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows)
720 LOG_ERROR("X11WindowSystem", "Maybe another composite manager is already running");
726 XGetErrorText(dpy, ev->error_code, buffer, sizeof(buffer));
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);
735 bool X11WindowSystem::initXServer()
737 LOG_DEBUG("X11WindowSystem", "Initialising XServer connection");
741 if (!CreateCompositorWindow())
743 LOG_ERROR("X11WindowSystem", "Compositor Window creation failed ");
747 LOG_DEBUG("X11WindowSystem", "Compositor Window ID: " << CompositorWindow);
749 if (CreatePixmapsForAllWindows())
751 //unredirect our window
753 XCompositeUnredirectWindow(x11Display, background, CompositeRedirectManual);
755 XCompositeUnredirectWindow(x11Display, CompositorWindow, CompositeRedirectManual);
756 LOG_DEBUG("X11WindowSystem", "Initialised XServer connection complete");
760 LOG_ERROR("X11WindowSystem", "Initialised XServer connection failed");
768 * Thread in charge of the CompositorWindow eventloop
769 * Friend function of class X11WindowSystem
771 void * X11eventLoopCallback(void *ptr)
773 X11WindowSystem *windowsys = static_cast<X11WindowSystem*>((X11WindowSystem*) ptr);
774 return windowsys->EventLoop();
777 void* X11WindowSystem::EventLoop()
780 LOG_INFO("X11WindowSystem", "XServer initialisation");
781 pthread_mutex_lock(&this->init_lock);
782 pthread_mutex_lock(&this->run_lock);
784 bool checkRedraw = false;
786 XSetErrorHandler(error);
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");
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;
815 // run the main event loop while rendering
816 gettimeofday(&tv0, NULL);
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);
825 LOG_INFO("X11WindowSystem", "Enter render loop");
827 // clear screen to avoid garbage on startup
828 this->graphicSystem->clearBackground();
829 this->graphicSystem->swapBuffers();
830 XFlush(this->x11Display);
832 while (this->m_running)
835 // blocking wait for event
836 XNextEvent(this->x11Display, &event);
837 this->m_pScene->lockScene();
844 LOG_DEBUG("X11WindowSystem", "CreateNotify Event");
845 Surface* s = this->m_pScene->createSurface(0, 0);
847 this->NewWindow(s, event.xcreatewindow.window);
848 defaultLayer->addSurface(s);
852 case ConfigureNotify:
853 LOG_DEBUG("X11WindowSystem", "Configure notify Event");
854 this->configureSurfaceWindow(event.xconfigure.window);
859 LOG_DEBUG("X11WindowSystem", "Destroy Event");
860 this->DestroyWindow(event.xdestroywindow.window);
864 if (event.xexpose.window == this->CompositorWindow)
867 LOG_DEBUG("X11WindowSystem", "Expose Event triggered by internal Redraw");
871 LOG_DEBUG("X11WindowSystem", "Expose Event triggered by external Application");
875 LOG_DEBUG("X11WindowSystem", "Map Event");
876 this->MapWindow(event.xmap.window);
880 LOG_DEBUG("X11WindowSystem", "Unmap Event");
881 this->UnMapWindow(event.xunmap.window);
885 LOG_DEBUG("X11WindowSystem", "Reparent Event");
886 // if (event.xreparent.parent == root)
887 // renderer->NewWindow(event.xreparent.window);
889 // renderer->DestroyWindow(event.xreparent.window);
894 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_PRESSED, &event);
897 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_RELEASED, &event);
902 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_PRESSED, &event);
905 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_RELEASED, &event);
908 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_MOTION, &event);
912 // TODO. See @ref<X11WindowSystem-MultiTouch> at the end of this file
915 if (event.type == this->damage_event + XDamageNotify)
917 XDamageSubtract(this->x11Display, ((XDamageNotifyEvent*)(&event))->damage, None, x11DamageRegion);
918 Surface* currentSurface = this->getSurfaceForWindow(((XDamageNotifyEvent*)(&event))->drawable);
919 if (currentSurface == NULL)
921 LOG_WARNING("X11WindowSystem", "Surface empty during damage notification");
926 if (currentSurface->platform != NULL)
928 XRectangle* rectangles;
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)
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*/;
944 /* Ignore Damage Events after Resize, the content can be invalid */
945 if (!currentSurface->m_surfaceResized)
947 currentSurface->damaged = true;
948 currentSurface->updateCounter++;
953 LOG_DEBUG("X11WindowSystem", "Skipping Damage Event which was triggered after ConfigureNotify");
954 currentSurface->m_surfaceResized = false;
959 this->m_pScene->unlockScene();
961 if (this->m_systemState == REDRAW_STATE)
963 LOG_DEBUG("X11WindowSystem", "Enter Redraw State");
964 this->m_systemState = IDLE_STATE;
966 // check if we are supposed to take screenshot
967 if (this->takeScreenshot != ScreenShotNone)
973 this->checkForNewSurfaceNativeContent();
977 else if (this->m_systemState == WAKEUP_STATE)
979 LOG_DEBUG("X11WindowSystem", "Enter Wake Up State");
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;
995 LOG_DEBUG("X11WindowSystem", "Renderer thread finished");
1000 void X11WindowSystem::ManageXInputEvent(InputDevice type, InputEventState state, XEvent *pevent)
1006 case INPUT_DEVICE_KEYBOARD:
1008 surf = m_pInputManager->reportKeyboardEvent(state, ((XKeyEvent *) pevent)->keycode);
1011 pevent->xany.window = surf->getNativeContent();
1012 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
1017 case INPUT_DEVICE_POINTER:
1019 Point p = {state, ((XButtonEvent*)pevent)->x, ((XButtonEvent*)pevent)->y};
1020 surf = m_pInputManager->reportPointerEvent(p);
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);
1031 case INPUT_DEVICE_TOUCH:
1036 case INPUT_DEVICE_ALL:
1042 static Display* displaySignal = NULL;
1044 void X11WindowSystem::wakeUpRendererThread()
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)
1050 displaySignal = XOpenDisplay(m_displayEnvironment);
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");
1060 void X11WindowSystem::signalRedrawEvent()
1062 // set flag that redraw is needed
1063 this->m_systemState = REDRAW_STATE;
1064 this->wakeUpRendererThread();
1067 void X11WindowSystem::cleanup()
1069 LOG_DEBUG("X11WindowSystem", "Cleanup");
1070 if (None != CompositorWindow)
1072 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
1073 XCompositeUnredirectSubwindows(x11Display, root, CompositeRedirectManual);
1074 XFixesDestroyRegion(x11Display, x11DamageRegion);
1075 XDestroyWindow(x11Display, CompositorWindow);
1083 if (NULL != displaySignal)
1085 XCloseDisplay(displaySignal);
1088 XCloseDisplay(x11Display);
1089 pthread_mutex_lock(&this->run_lock);
1091 pthread_mutex_unlock(&this->run_lock);
1094 bool X11WindowSystem::init(BaseGraphicSystem<Display*, Window>* base)
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);
1104 pthread_mutex_unlock(&init_lock);
1107 mThreadId = renderThread;
1109 pthread_cond_wait(&init_condition, &init_lock);
1110 pthread_mutex_unlock(&init_lock);
1111 LOG_INFO("X11WindowSystem", "Initialization complete success :" << m_success);
1115 bool X11WindowSystem::start()
1118 pthread_mutex_lock(&this->run_lock);
1119 LOG_DEBUG("X11WindowSystem", "Startup");
1120 // let thread actually run
1121 if (m_xerror == false)
1123 this->m_running = true;
1124 pthread_cond_signal(&this->run_condition);
1125 pthread_mutex_unlock(&this->run_lock);
1129 this->m_running = false;
1130 pthread_cond_signal(&this->run_condition);
1131 pthread_mutex_unlock(&this->run_lock);
1137 void X11WindowSystem::stop()
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);
1149 void X11WindowSystem::allocatePlatformSurface(Surface* surface)
1151 LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface begin");
1152 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
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());
1160 LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface end");
1163 void X11WindowSystem::deallocatePlatformSurface(Surface* surface)
1165 LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface begin");
1166 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1169 LOG_DEBUG("X11WindowSystem", "destroyingnative surface");
1170 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
1172 if (nativeSurface->pixmap)
1174 XFreePixmap(x11Display, nativeSurface->pixmap);
1177 surface->renderPropertyChanged = true;
1178 delete surface->platform;
1179 surface->platform = NULL;
1181 LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface end");
1184 void X11WindowSystem::doScreenShot(std::string fileName)
1186 takeScreenshot = ScreenshotOfDisplay;
1187 screenShotFile = fileName;
1190 void X11WindowSystem::doScreenShotOfLayer(std::string fileName, const uint id)
1192 takeScreenshot = ScreenshotOfLayer;
1193 screenShotFile = fileName;
1194 screenShotLayerID = id;
1197 void X11WindowSystem::doScreenShotOfSurface(std::string fileName, const uint id, const uint layer_id)
1199 takeScreenshot = ScreenshotOfSurface;
1200 screenShotFile = fileName;
1201 screenShotSurfaceID = id;
1202 screenShotLayerID = layer_id;
1208 * @subsection <X11WindowSystem-MultiTouch> (Multi Touch)
1210 * X11 multi touch is not yet supported by Layer Manager.
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()
1223 * + XInput 2.x protocol : ftp://www.x.org/pub/xorg/current/doc/inputproto/XI2proto.txt
1224 * + LWN article : http://lwn.net/Articles/475886/