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 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);
167 void X11WindowSystem::printDebug()
169 // print stuff about layerlist
170 std::stringstream debugmessage;
171 debugmessage << "Layer: ID | X | Y | W | H | Al. \n";
173 LayerList list = m_pScene->getCurrentRenderOrder(0);
176 LayerListConstIterator iter = list.begin();
177 LayerListConstIterator iterEnd = list.end();
179 for (; iter != iterEnd; ++iter)
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";
184 debugmessage << " Surface: ID |Al.| SVP: X | Y | W | H DVP: X | Y | W | H \n";
186 // loop the surfaces of within each layer
187 SurfaceList surfaceList = (*iter)->getAllSurfaces();
188 SurfaceListIterator surfaceIter = surfaceList.begin();
189 SurfaceListIterator surfaceIterEnd = surfaceList.end();
191 for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
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";
198 LOG_DEBUG("X11WindowSystem", debugmessage.str());
201 Window * getListOfAllTopLevelWindows(Display *disp, unsigned int *len)
203 LOG_DEBUG("X11WindowSystem", "Getting list of all windows");
206 Window parent_return;
207 Window root = XDefaultRootWindow(disp);
208 XQueryTree(disp, root, &root_return, &parent_return, &children, len);
212 bool X11WindowSystem::isWindowValid(Window w)
214 // skip our own two windows
215 return (w != None && w != CompositorWindow);
218 Surface* X11WindowSystem::getSurfaceForWindow(Window w)
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)
224 Surface* currentSurface = (*currentS).second;
229 if (currentSurface->getNativeContent() == static_cast<int>(w))
231 return currentSurface;
234 LOG_DEBUG("X11WindowSystem", "could not find surface for window " << w);
238 void X11WindowSystem::checkForNewSurfaceNativeContent()
240 m_pScene->lockScene();
241 LayerList layers = m_pScene->getCurrentRenderOrder(0);
242 for (LayerListConstIterator current = layers.begin(); current != layers.end(); current++)
244 SurfaceList surfaces = (*current)->getAllSurfaces();
245 for (SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
247 if ((*currentS)->hasNativeContent())
249 allocatePlatformSurface(*currentS);
251 else // While we are at it, also cleanup any stale native content
253 deallocatePlatformSurface(*currentS);
257 m_pScene->unlockScene();
260 void X11WindowSystem::configureSurfaceWindow(Window window)
262 if (isWindowValid(window))
264 LOG_DEBUG("X11WindowSystem", "Updating window " << window);
267 XWindowAttributes att;
268 XGetWindowAttributes(x11Display, window, &att);
269 int winWidth = att.width;
270 int winHeight = att.height;
272 Surface* surface = getSurfaceForWindow(window);
275 LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
278 if (!surface->platform)
280 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
284 LOG_DEBUG("X11WindowSystem", "Updating surface " << surface->getID());
286 surface->OriginalSourceHeight = winHeight;
287 surface->OriginalSourceWidth = winWidth;
289 LOG_DEBUG("X11WindowSystem", "Done Updating window " << window);
293 void X11WindowSystem::MapWindow(Window window)
295 LOG_DEBUG("X11WindowSystem", "Map window begin");
296 if (isWindowValid(window))
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)
305 LOG_DEBUG("X11WindowSystem", "Mapping surface to window " << window);
306 Surface* surface = getSurfaceForWindow(window);
309 LOG_WARNING("X11WindowSystem", "Could not map surface to window " << window);
312 if (!surface->platform)
314 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
318 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
319 if (x11surf->isMapped)
321 LOG_WARNING("X11WindowSystem", "Platform surface already mapped");
324 x11surf->isMapped = true;
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));
337 int winWidth = att.width;
338 int winHeight = att.height;
340 surface->OriginalSourceHeight = winHeight;
341 surface->OriginalSourceWidth = winWidth;
342 surface->renderPropertyChanged = true;
344 graphicSystem->getTextureBinder()->createClientBuffer(surface);
345 x11surf->enableRendering();
346 XSync(x11Display, 0);
348 LOG_DEBUG("X11WindowSystem", "Mapping Surface " << surface->getID() << " to window " << window);
349 LOG_DEBUG("X11WindowSystem", "Mapping successfull");
352 LOG_DEBUG("X11WindowSystem", "Map window end");
355 void X11WindowSystem::UnMapWindow(Window window)
357 LOG_DEBUG("X11WindowSystem", "Unmap begin");
358 if (isWindowValid(window))
360 LOG_DEBUG("X11WindowSystem", "Unmapping surface from window " << window);
361 Surface* surface = getSurfaceForWindow(window);
364 LOG_WARNING("X11WindowSystem", "Could not unmap window " << window);
367 if (!surface->platform)
369 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
372 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
373 x11surf->disableRendering();
374 LOG_DEBUG("X11WindowSystem", "Unmapping surface " << surface->getID());
375 if (!x11surf->isMapped)
377 LOG_WARNING("X11WindowSystem", "Platform surface already unmapped");
380 x11surf->isMapped = false;
382 LOG_DEBUG("X11WindowSystem", "Destroying ClientBuffer");
383 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
384 XSync(x11Display, 0);
386 LOG_DEBUG("X11WindowSystem", "Removing X Pixmap");
389 int result = XFreePixmap(x11Display, x11surf->pixmap);
390 LOG_DEBUG("X11WindowSystem", "XFreePixmap() returned " << result);
393 surface->renderPropertyChanged = true;
395 LOG_DEBUG("X11WindowSystem", "Unmap finished");
398 void X11WindowSystem::NewWindow(Surface* surface, Window window)
400 if (isWindowValid(window))
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");
408 status = XFetchName(x11Display, window, &name);
409 LOG_DEBUG("X11WindowSystem", "Got window name");
410 if (status >= Success && name)
412 LOG_DEBUG("X11WindowSystem", "Found window: " << window << " " << name);
413 char GuiTitle[] = "Layermanager Remote GUI\0";
414 if (strcmp(name, GuiTitle) == 0)
416 LOG_DEBUG("X11WindowSystem", "Found gui window: repositioning it");
417 XCompositeUnredirectWindow(x11Display, window, CompositeRedirectManual);
418 XMoveWindow(x11Display, window, 50, 500);
419 XMapRaised(x11Display, window);
424 LOG_DEBUG("X11WindowSystem", "Error fetching window name");
427 if (att.c_class == InputOutput)
429 LOG_DEBUG("X11WindowSystem", "Creating New Damage for window - " << window);
430 XDamageCreate(x11Display, window, XDamageReportNonEmpty);
434 XLowerWindow(x11Display, window);
436 surface->setNativeContent(window);
437 XPlatformSurface * platformSurface = (XPlatformSurface*)graphicSystem->getTextureBinder()->createPlatformSurface(surface);
438 platformSurface->isMapped = false;
440 LOG_DEBUG("X11WindowSystem", "Created native Surface for X11 Window id " << window);
442 surface->platform = platformSurface;
444 int winWidth = att.width;
445 int winHeight = att.height;
447 surface->OriginalSourceHeight = winHeight;
448 surface->OriginalSourceWidth = winWidth;
450 LOG_DEBUG("X11WindowSystem", "Original width " << surface->OriginalSourceWidth);
451 LOG_DEBUG("X11WindowSystem", "Original heigth " << surface->OriginalSourceHeight);
455 LOG_DEBUG("X11WindowSystem", "skipping window");
457 LOG_DEBUG("X11WindowSystem", "created the new surface");
460 void X11WindowSystem::DestroyWindow(Window window)
462 if (isWindowValid(window))
464 LOG_DEBUG("X11WindowSystem", "Destroying Surface for window " << window);
465 Surface* surface = getSurfaceForWindow(window);
468 LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
471 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
472 LOG_DEBUG("X11WindowSystem", "Unmapping window " << 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;
483 bool X11WindowSystem::CreatePixmapsForAllWindows()
486 LOG_DEBUG("X11WindowSystem", "redirecting all windows");
487 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
488 XCompositeRedirectSubwindows(x11Display, root, CompositeRedirectManual);
489 XSync(x11Display, 0);
493 bool X11WindowSystem::CreateCompositorWindow()
495 LOG_DEBUG("X11WindowSystem", "Get root window");
497 CompositorWindow = None;
498 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
500 LOG_DEBUG("X11WindowSystem", "Creating Compositor Window");
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
512 attr.background_pixel = 0;
513 attr.border_pixel = 0;
514 windowVis = getVisualFunc(x11Display);
519 attr.colormap = XCreateColormap(x11Display, root, windowVis->visual, AllocNone);
520 attr.override_redirect = True;
522 Window compManager = XGetSelectionOwner(x11Display, XInternAtom(x11Display, "_NET_WM_CM_S0", 0));
523 if (None != compManager)
525 LOG_ERROR("X11WindowSystem", "Could not create compositor window, annother compisite manager is already running");
529 CompositorWindow = XCreateWindow(x11Display, root, 0, 0, windowWidth, windowHeight,
530 0, windowVis->depth, InputOutput,
531 windowVis->visual, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &attr);
533 if (None == CompositorWindow)
535 LOG_ERROR("X11WindowSystem", "Could not create window");
539 LOG_DEBUG("X11WindowSystem", "Created the Compositor Window");
540 XSelectInput(x11Display, root,
541 SubstructureNotifyMask|
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);
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;
566 void X11WindowSystem::calculateSurfaceFps(Surface *currentSurface, float time)
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);
579 void X11WindowSystem::calculateFps()
581 // we have rendered a 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));
588 if (timeSinceLastCalc > m_fpsinterval)
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)
595 SurfaceList surfaceList = (*current)->getAllSurfaces();
596 SurfaceListIterator surfaceIter = surfaceList.begin();
597 SurfaceListIterator surfaceIterEnd = surfaceList.end();
598 for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
600 calculateSurfaceFps((*surfaceIter), timeSinceLastCalc);
603 LOG_INFO("X11WindowSystem", floatStringBuffer);
609 void X11WindowSystem::RedrawAllLayers(bool clear, bool swap)
611 LayerList layers = m_pScene->getCurrentRenderOrder(0);
614 // Refresh HW Layers, find SW Layers
615 for (LayerListConstIterator current = layers.begin(); current != layers.end(); ++current)
617 if ((*current)->getLayerType() == Hardware)
619 // Redraw HW layers independently of other layers
620 if (m_forceComposition || graphicSystem->needsRedraw(*current))
622 renderHWLayer(*current);
627 swLayers.push_back(*current);
631 if (m_forceComposition || graphicSystem->needsRedraw(swLayers))
633 graphicSystem->renderSWLayers(swLayers, clear);
637 graphicSystem->swapBuffers();
649 void X11WindowSystem::renderHWLayer(Layer *layer)
654 void X11WindowSystem::Redraw()
656 // draw all the layers
657 /*LOG_INFO("X11WindowSystem","Locking List");*/
658 m_pScene->lockScene();
660 RedrawAllLayers(true, true); // Clear and Swap
663 m_pScene->unlockScene();
665 m_forceComposition = false;
668 void X11WindowSystem::Screenshot()
670 /*LOG_INFO("X11WindowSystem","Locking List");*/
671 m_pScene->lockScene();
672 if (takeScreenshot == ScreenshotOfDisplay)
674 LOG_DEBUG("X11WindowSystem", "Taking screenshot");
675 RedrawAllLayers(true, false); // Do clear, Don't swap
677 else if (takeScreenshot == ScreenshotOfLayer)
679 LOG_DEBUG("X11WindowSystem", "Taking screenshot of layer");
680 Layer* layer = m_pScene->getLayer(screenShotLayerID);
684 graphicSystem->renderSWLayer(layer, true); // Do clear
687 else if (takeScreenshot == ScreenshotOfSurface)
689 LOG_DEBUG("X11WindowSystem", "Taking screenshot of surface");
690 Layer* layer = m_pScene->getLayer(screenShotLayerID);
691 Surface* surface = m_pScene->getSurface(screenShotSurfaceID);
693 graphicSystem->clearBackground();
694 if (layer != NULL && surface != NULL)
696 graphicSystem->beginLayer(layer);
697 graphicSystem->renderSurface(surface);
698 graphicSystem->endLayer();
702 graphicSystem->saveScreenShotOfFramebuffer(screenShotFile);
703 takeScreenshot = ScreenShotNone;
704 LOG_DEBUG("X11WindowSystem", "Done taking screenshot");
705 m_pScene->unlockScene();
706 /*LOG_INFO("X11WindowSystem","UnLocking List");*/
710 X11WindowSystem::error(Display *dpy, XErrorEvent *ev)
712 const char* name = NULL;
713 static char buffer[256];
715 if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows)
717 LOG_ERROR("X11WindowSystem", "Maybe another composite manager is already running");
723 XGetErrorText(dpy, ev->error_code, buffer, sizeof(buffer));
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);
732 bool X11WindowSystem::initXServer()
734 LOG_DEBUG("X11WindowSystem", "Initialising XServer connection");
738 if (!CreateCompositorWindow())
740 LOG_ERROR("X11WindowSystem", "Compositor Window creation failed ");
744 LOG_DEBUG("X11WindowSystem", "Compositor Window ID: " << CompositorWindow);
746 if (CreatePixmapsForAllWindows())
748 //unredirect our window
750 XCompositeUnredirectWindow(x11Display, background, CompositeRedirectManual);
752 XCompositeUnredirectWindow(x11Display, CompositorWindow, CompositeRedirectManual);
753 LOG_DEBUG("X11WindowSystem", "Initialised XServer connection complete");
757 LOG_ERROR("X11WindowSystem", "Initialised XServer connection failed");
765 * Thread in charge of the CompositorWindow eventloop
766 * Friend function of class X11WindowSystem
768 void * X11eventLoopCallback(void *ptr)
770 X11WindowSystem *windowsys = static_cast<X11WindowSystem*>((X11WindowSystem*) ptr);
771 return windowsys->EventLoop();
774 void* X11WindowSystem::EventLoop()
777 LOG_INFO("X11WindowSystem", "XServer initialisation");
778 pthread_mutex_lock(&this->init_lock);
779 pthread_mutex_lock(&this->run_lock);
781 bool checkRedraw = false;
783 XSetErrorHandler(error);
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");
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;
812 // run the main event loop while rendering
813 gettimeofday(&tv0, NULL);
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);
822 LOG_INFO("X11WindowSystem", "Enter render loop");
824 // clear screen to avoid garbage on startup
825 this->graphicSystem->clearBackground();
826 this->graphicSystem->swapBuffers();
827 XFlush(this->x11Display);
829 while (this->m_running)
832 // blocking wait for event
833 XNextEvent(this->x11Display, &event);
834 this->m_pScene->lockScene();
841 LOG_DEBUG("X11WindowSystem", "CreateNotify Event");
842 Surface* s = this->m_pScene->createSurface(0, 0);
844 this->NewWindow(s, event.xcreatewindow.window);
845 defaultLayer->addSurface(s);
849 case ConfigureNotify:
850 LOG_DEBUG("X11WindowSystem", "Configure notify Event");
851 this->configureSurfaceWindow(event.xconfigure.window);
856 LOG_DEBUG("X11WindowSystem", "Destroy Event");
857 this->DestroyWindow(event.xdestroywindow.window);
861 LOG_DEBUG("X11WindowSystem", "Expose Event");
865 LOG_DEBUG("X11WindowSystem", "Map Event");
866 this->MapWindow(event.xmap.window);
870 LOG_DEBUG("X11WindowSystem", "Unmap Event");
871 this->UnMapWindow(event.xunmap.window);
875 LOG_DEBUG("X11WindowSystem", "Reparent Event");
876 // if (event.xreparent.parent == root)
877 // renderer->NewWindow(event.xreparent.window);
879 // renderer->DestroyWindow(event.xreparent.window);
884 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_PRESSED, &event);
887 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_RELEASED, &event);
892 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_PRESSED, &event);
895 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_RELEASED, &event);
898 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_MOTION, &event);
902 // TODO. See @ref<X11WindowSystem-MultiTouch> at the end of this file
905 if (event.type == this->damage_event + XDamageNotify)
907 XDamageSubtract(this->x11Display, ((XDamageNotifyEvent*)(&event))->damage, None, None);
908 Surface* currentSurface = this->getSurfaceForWindow(((XDamageNotifyEvent*)(&event))->drawable);
909 if (currentSurface == NULL)
911 LOG_WARNING("X11WindowSystem", "Surface empty during damage notification");
916 if (currentSurface->platform != NULL)
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();
923 currentSurface->damaged = true;
924 currentSurface->updateCounter++;
929 this->m_pScene->unlockScene();
931 if (this->m_systemState == REDRAW_STATE)
933 LOG_DEBUG("X11WindowSystem", "Enter Redraw State");
934 this->m_systemState = IDLE_STATE;
936 // check if we are supposed to take screenshot
937 if (this->takeScreenshot != ScreenShotNone)
943 this->checkForNewSurfaceNativeContent();
947 else if (this->m_systemState == WAKEUP_STATE)
949 LOG_DEBUG("X11WindowSystem", "Enter Wake Up State");
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;
965 LOG_DEBUG("X11WindowSystem", "Renderer thread finished");
970 void X11WindowSystem::ManageXInputEvent(InputDevice type, InputEventState state, XEvent *pevent)
976 case INPUT_DEVICE_KEYBOARD:
978 surf = m_pInputManager->reportKeyboardEvent(state, ((XKeyEvent *) pevent)->keycode);
981 pevent->xany.window = surf->getNativeContent();
982 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
987 case INPUT_DEVICE_POINTER:
989 Point p = {state, ((XButtonEvent*)pevent)->x, ((XButtonEvent*)pevent)->y};
990 surf = m_pInputManager->reportPointerEvent(p);
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);
1001 case INPUT_DEVICE_TOUCH:
1006 case INPUT_DEVICE_ALL:
1012 static Display* displaySignal = NULL;
1014 void X11WindowSystem::wakeUpRendererThread()
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)
1020 displaySignal = XOpenDisplay(m_displayEnvironment);
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");
1030 void X11WindowSystem::signalRedrawEvent()
1032 // set flag that redraw is needed
1033 this->m_systemState = REDRAW_STATE;
1034 this->wakeUpRendererThread();
1037 void X11WindowSystem::cleanup()
1039 LOG_DEBUG("X11WindowSystem", "Cleanup");
1040 if (None != CompositorWindow)
1042 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
1043 XCompositeUnredirectSubwindows(x11Display, root, CompositeRedirectManual);
1044 XDestroyWindow(x11Display, CompositorWindow);
1052 if (NULL != displaySignal)
1054 XCloseDisplay(displaySignal);
1057 XCloseDisplay(x11Display);
1058 pthread_mutex_lock(&this->run_lock);
1060 pthread_mutex_unlock(&this->run_lock);
1063 bool X11WindowSystem::init(BaseGraphicSystem<Display*, Window>* base)
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);
1073 pthread_mutex_unlock(&init_lock);
1076 mThreadId = renderThread;
1078 pthread_cond_wait(&init_condition, &init_lock);
1079 /* while (!m_initialized)
1081 usleep(1000); // TODO
1082 LOG_DEBUG("X11WindowSystem","Waiting start complete " << m_initialized);
1085 pthread_mutex_unlock(&init_lock);
1086 LOG_INFO("X11WindowSystem", "Initialization complete success :" << m_success);
1090 bool X11WindowSystem::start()
1093 pthread_mutex_lock(&this->run_lock);
1094 LOG_DEBUG("X11WindowSystem", "Startup");
1095 // let thread actually run
1096 if (m_xerror == false)
1098 this->m_running = true;
1099 pthread_cond_signal(&this->run_condition);
1100 pthread_mutex_unlock(&this->run_lock);
1104 this->m_running = false;
1105 pthread_cond_signal(&this->run_condition);
1106 pthread_mutex_unlock(&this->run_lock);
1112 void X11WindowSystem::stop()
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);
1124 void X11WindowSystem::allocatePlatformSurface(Surface* surface)
1126 LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface begin");
1127 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
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());
1135 LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface end");
1138 void X11WindowSystem::deallocatePlatformSurface(Surface* surface)
1140 LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface begin");
1141 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1144 LOG_DEBUG("X11WindowSystem", "destroyingnative surface");
1145 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
1147 if (nativeSurface->pixmap)
1149 XFreePixmap(x11Display, nativeSurface->pixmap);
1152 surface->renderPropertyChanged = true;
1153 delete surface->platform;
1154 surface->platform = NULL;
1156 LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface end");
1159 void X11WindowSystem::doScreenShot(std::string fileName)
1161 takeScreenshot = ScreenshotOfDisplay;
1162 screenShotFile = fileName;
1165 void X11WindowSystem::doScreenShotOfLayer(std::string fileName, const uint id)
1167 takeScreenshot = ScreenshotOfLayer;
1168 screenShotFile = fileName;
1169 screenShotLayerID = id;
1172 void X11WindowSystem::doScreenShotOfSurface(std::string fileName, const uint id, const uint layer_id)
1174 takeScreenshot = ScreenshotOfSurface;
1175 screenShotFile = fileName;
1176 screenShotSurfaceID = id;
1177 screenShotLayerID = layer_id;
1183 * @subsection <X11WindowSystem-MultiTouch> (Multi Touch)
1185 * X11 multi touch is not yet supported by Layer Manager.
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()
1198 * + XInput 2.x protocol : ftp://www.x.org/pub/xorg/current/doc/inputproto/XI2proto.txt
1199 * + LWN article : http://lwn.net/Articles/475886/