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, int width, int height, Scene* pScene,InputManager* pInputManager,GetVisualInfoFunction func)
43 : BaseWindowSystem(pScene, pInputManager)
44 , takeScreenshot(ScreenShotNone)
46 , screenShotSurfaceID(0)
48 , displayname(displayname)
51 , resolutionWidth(width)
52 , resolutionHeight(height)
62 /*, m_initialized(false)*/
64 , m_systemState(IDLE_STATE)
65 , m_displayEnvironment(NULL)
69 , windowHeight(height)
75 LOG_DEBUG("X11WindowSystem", "creating X11WindowSystem");
77 // init and take mutex, so windowsystem only does init phase until mutex is released again
78 pthread_mutex_init(&run_lock, NULL);
79 pthread_cond_init(&run_condition,NULL);
80 pthread_cond_init(&init_condition,NULL);
81 pthread_mutex_init(&init_lock, NULL);
84 X11WindowSystem::~X11WindowSystem()
92 XVisualInfo* X11WindowSystem::getDefaultVisual(Display *dpy)
94 XVisualInfo* windowVis = new XVisualInfo();
97 windowVis->depth = DefaultDepth(dpy, DefaultScreen(dpy));
98 if (!XMatchVisualInfo( dpy, 0, windowVis->depth, TrueColor, windowVis))
100 LOG_ERROR("X11WindowSystem", "Error: Required visual not found\n");
107 LOG_ERROR("X11WindowSystem", "Error: Unable to acquire visual\n");
112 bool X11WindowSystem::OpenDisplayConnection()
114 m_displayEnvironment = getenv("DISPLAY");
116 if (m_displayEnvironment == NULL )
118 m_displayEnvironment = ":0.0";
119 setenv("DISPLAY",m_displayEnvironment,1);
122 x11Display = XOpenDisplay(m_displayEnvironment);
125 LOG_ERROR("X11WindowSystem", "Couldn't open default display!");
128 LOG_DEBUG("X11WindowSystem", "Display connection: " << x11Display);
132 bool X11WindowSystem::checkForCompositeExtension()
134 if (x11Display == NULL || !XQueryExtension (x11Display, COMPOSITE_NAME, &composite_opcode, &composite_event, &composite_error))
136 LOG_ERROR("X11WindowSystem", "No composite extension");
139 XCompositeQueryVersion (x11Display, &composite_major, &composite_minor);
140 LOG_DEBUG("X11WindowSystem", "Found composite extension: composite opcode: " << composite_opcode);
141 LOG_DEBUG("X11WindowSystem", "composite_major: " << composite_major);
142 LOG_DEBUG("X11WindowSystem", "composite_minor: " << composite_minor);
146 bool X11WindowSystem::checkForDamageExtension(){
147 if (x11Display == NULL || !XQueryExtension (x11Display, DAMAGE_NAME, &damage_opcode,
148 &damage_event, &damage_error))
150 LOG_ERROR("X11WindowSystem", "No damage extension");
153 XDamageQueryVersion (x11Display, &damage_major, &damage_minor);
154 LOG_DEBUG("X11WindowSystem", "Found damage extension: damage opcode: " << damage_opcode);
155 LOG_DEBUG("X11WindowSystem", "damage_major: " << damage_major);
156 LOG_DEBUG("X11WindowSystem", "damage_minor: " << damage_minor);
160 void X11WindowSystem::printDebug(){
161 // print stuff about layerlist
162 std::stringstream debugmessage;
163 debugmessage << "Layer: ID | X | Y | W | H | Al. \n";
165 LayerList list = m_pScene->getCurrentRenderOrder();
168 LayerListConstIterator iter = list.begin();
169 LayerListConstIterator iterEnd = list.end();
171 for(; iter != iterEnd; ++iter)
173 Rectangle dest = (*iter)->getDestinationRegion();
174 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";
176 debugmessage << " Surface: ID |Al.| SVP: X | Y | W | H DVP: X | Y | W | H \n";
178 // loop the surfaces of within each layer
179 SurfaceList surfaceList = (*iter)->getAllSurfaces();
180 SurfaceListIterator surfaceIter = surfaceList.begin();
181 SurfaceListIterator surfaceIterEnd = surfaceList.end();
183 for(; surfaceIter != surfaceIterEnd ; ++surfaceIter)
185 Rectangle src = (*surfaceIter)->getSourceRegion();
186 Rectangle dest = (*surfaceIter)->getDestinationRegion();
187 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";
190 LOG_DEBUG("X11WindowSystem",debugmessage.str());
193 Window * getListOfAllTopLevelWindows (Display *disp, unsigned int *len)
195 LOG_DEBUG("X11WindowSystem", "Getting list of all windows");
197 Window root_return, parent_return;
198 Window root = XDefaultRootWindow(disp);
199 XQueryTree (disp, root, &root_return, &parent_return, &children, len);
203 bool X11WindowSystem::isWindowValid(Window w)
205 // skip our own two windows
206 return (w!=None && w != CompositorWindow);
209 Surface* X11WindowSystem::getSurfaceForWindow(Window w)
211 // go though all surfaces
212 const std::map<unsigned int,Surface*> surfaces = m_pScene->getAllSurfaces();
213 for(std::map<unsigned int, Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); ++currentS)
215 Surface* currentSurface = (*currentS).second;
220 if (currentSurface->getNativeContent() == static_cast<int>(w))
222 return currentSurface;
225 LOG_DEBUG("X11WindowSystem", "could not find surface for window " << w);
229 void X11WindowSystem::checkForNewSurfaceNativeContent()
231 m_pScene->lockScene();
232 LayerList layers = m_pScene->getCurrentRenderOrder();
233 for(LayerListConstIterator current = layers.begin(); current != layers.end(); current++)
235 SurfaceList surfaces = (*current)->getAllSurfaces();
236 for(SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
238 if ((*currentS)->hasNativeContent())
240 allocatePlatformSurface(*currentS);
242 else // While we are at it, also cleanup any stale native content
244 deallocatePlatformSurface(*currentS);
248 m_pScene->unlockScene();
251 void X11WindowSystem::configureSurfaceWindow(Window window)
253 if (isWindowValid(window))
255 LOG_DEBUG("X11WindowSystem", "Updating window " << window);
258 XWindowAttributes att;
259 XGetWindowAttributes (x11Display, window, &att);
260 int winWidth = att.width;
261 int winHeight = att.height;
263 Surface* surface = getSurfaceForWindow(window);
266 LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
269 if (!surface->platform)
271 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
275 LOG_DEBUG("X11WindowSystem", "Updating surface " << surface->getID());
277 surface->OriginalSourceHeight = winHeight;
278 surface->OriginalSourceWidth = winWidth;
280 LOG_DEBUG("X11WindowSystem", "Done Updating window " << window);
284 void X11WindowSystem::MapWindow(Window window)
286 LOG_DEBUG("X11WindowSystem","Map window begin");
287 if (isWindowValid(window))
289 XWindowAttributes att;
290 XGetWindowAttributes (x11Display, window, &att);
291 /* LOG_DEBUG("X11WindowSystem", "XCompositeRedirectWindow()");
292 XCompositeRedirectWindow(x11Display, window, CompositeRedirectManual);
293 XSync(x11Display, 0);*/
294 if (att.map_state == IsViewable && att.override_redirect==0)
296 LOG_DEBUG("X11WindowSystem", "Mapping surface to window " << window);
297 Surface* surface = getSurfaceForWindow(window);
300 LOG_WARNING("X11WindowSystem", "Could not map surface to window " << window);
303 if (!surface->platform)
305 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
309 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
310 if (x11surf->isMapped)
312 LOG_WARNING("X11WindowSystem", "Platform surface already mapped");
315 x11surf->isMapped = true;
318 LOG_DEBUG("X11WindowSystem", "getting pixmap for window");
319 LOG_DEBUG("X11WindowSystem", "window width: " << att.width);
320 LOG_DEBUG("X11WindowSystem", "window height: " << att.height);
321 LOG_DEBUG("X11WindowSystem", "map state: " << att.map_state);
322 LOG_DEBUG("X11WindowSystem", "window x: " << att.x);
323 LOG_DEBUG("X11WindowSystem", "window backing: " << att.backing_pixel);
324 LOG_DEBUG("X11WindowSystem", "window save under: " << att.save_under);
325 LOG_DEBUG("X11WindowSystem", "window orride: " << att.override_redirect);
326 LOG_DEBUG("X11WindowSystem", "parent/root: " << att.root);
327 LOG_DEBUG("X11WindowSystem", "root window: " << DefaultRootWindow(x11Display));
329 int winWidth = att.width;
330 int winHeight = att.height;
332 surface->OriginalSourceHeight = winHeight;
333 surface->OriginalSourceWidth = winWidth;
334 surface->renderPropertyChanged = true;
336 graphicSystem->getTextureBinder()->createClientBuffer(surface);
337 x11surf->enableRendering();
338 XSync(x11Display, 0);
340 LOG_DEBUG("X11WindowSystem", "Mapping Surface " << surface->getID() << " to window " << window);
341 LOG_DEBUG("X11WindowSystem", "Mapping successfull");
344 LOG_DEBUG("X11WindowSystem","Map window end");
347 void X11WindowSystem::UnMapWindow(Window window)
349 LOG_DEBUG("X11WindowSystem", "Unmap begin");
350 if (isWindowValid(window))
352 LOG_DEBUG("X11WindowSystem", "Unmapping surface from window " << window);
353 Surface* surface = getSurfaceForWindow(window);
356 LOG_WARNING("X11WindowSystem", "Could not unmap window " << window);
359 if (!surface->platform)
361 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
364 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
365 x11surf->disableRendering();
366 LOG_DEBUG("X11WindowSystem", "Unmapping surface " << surface->getID());
367 if (!x11surf->isMapped)
369 LOG_WARNING("X11WindowSystem", "Platform surface already unmapped");
372 x11surf->isMapped = false;
375 LOG_DEBUG("X11WindowSystem", "Destroying ClientBuffer");
376 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
377 XSync(x11Display, 0);
379 LOG_DEBUG("X11WindowSystem", "Removing X Pixmap");
382 int result = XFreePixmap(x11Display, x11surf->pixmap);
383 LOG_DEBUG("X11WindowSystem", "XFreePixmap() returned " << result);
386 surface->renderPropertyChanged = true;
388 LOG_DEBUG("X11WindowSystem", "Unmap finished");
391 void X11WindowSystem::NewWindow(Surface* surface, Window window)
393 if (isWindowValid(window))
395 LOG_DEBUG("X11WindowSystem", "Creating Surface for new window " << window);
396 // get the windows attributes
397 XWindowAttributes att;
398 int status = XGetWindowAttributes (x11Display, window, &att);
399 LOG_DEBUG("X11WindowSystem", "Got window attrbutes");
401 status = XFetchName(x11Display, window, &name);
402 LOG_DEBUG("X11WindowSystem", "Got window name");
403 if (status >= Success && name)
405 LOG_DEBUG("X11WindowSystem", "Found window: " << window << " " << name);
406 char GuiTitle[] = "Layermanager Remote GUI\0";
407 if (strcmp(name,GuiTitle)==0)
409 LOG_DEBUG("X11WindowSystem", "Found gui window: repositioning it");
410 XCompositeUnredirectWindow(x11Display,window,CompositeRedirectManual);
411 XMoveWindow(x11Display, window, 50, 500);
412 XMapRaised(x11Display, window);
417 LOG_DEBUG("X11WindowSystem", "Error fetching window name");
420 if (att.c_class == InputOutput)
422 LOG_DEBUG("X11WindowSystem","Creating New Damage for window - " << window);
423 XDamageCreate(x11Display,window,XDamageReportNonEmpty);
427 XLowerWindow(x11Display,window);
429 surface->setNativeContent(window);
430 XPlatformSurface * platformSurface = (XPlatformSurface*)graphicSystem->getTextureBinder()->createPlatformSurface(surface);
431 platformSurface->isMapped = false;
433 LOG_DEBUG("X11WindowSystem", "Created native Surface for X11 Window id " << window);
435 surface->platform = platformSurface;
437 int winWidth = att.width;
438 int winHeight = att.height;
440 surface->OriginalSourceHeight = winHeight;
441 surface->OriginalSourceWidth = winWidth;
443 LOG_DEBUG("X11WindowSystem", "Original width " << surface->OriginalSourceWidth);
444 LOG_DEBUG("X11WindowSystem", "Original heigth " << surface->OriginalSourceHeight);
448 LOG_DEBUG("X11WindowSystem", "skipping window");
450 LOG_DEBUG("X11WindowSystem", "created the new surface");
453 void X11WindowSystem::DestroyWindow(Window window)
455 if (isWindowValid(window))
457 LOG_DEBUG("X11WindowSystem", "Destroying Surface for window " << window);
458 Surface* surface = getSurfaceForWindow(window);
461 LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
464 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
465 LOG_DEBUG("X11WindowSystem", "Unmapping window " << window);
467 LOG_DEBUG("X11WindowSystem", "Remove Native Content from Surface " << surface->getID());
468 surface->removeNativeContent();
469 /* To force a recomposition of all surface which are behind of that surface inside the Layer RenderOrder */
470 surface->renderPropertyChanged = true;
471 delete surface->platform;
472 surface->platform = NULL;
476 bool X11WindowSystem::CreatePixmapsForAllWindows()
479 LOG_DEBUG("X11WindowSystem", "redirecting all windows");
480 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
481 XCompositeRedirectSubwindows(x11Display,root,CompositeRedirectManual);
486 bool X11WindowSystem::CreateCompositorWindow()
488 LOG_DEBUG("X11WindowSystem", "Get root window");
490 CompositorWindow = None;
491 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
493 LOG_DEBUG("X11WindowSystem", "Creating Compositor Window");
495 XSetWindowAttributes attr;
496 // draw a black background the full size of the resolution
497 attr.override_redirect = True;
498 attr.event_mask = ExposureMask
499 | StructureNotifyMask
505 attr.background_pixel = 0;
506 attr.border_pixel = 0;
507 windowVis = getVisualFunc(x11Display);
512 attr.colormap = XCreateColormap(x11Display, root, windowVis->visual, AllocNone);
513 attr.override_redirect = True;
515 Window compManager = XGetSelectionOwner(x11Display,XInternAtom(x11Display,"_NET_WM_CM_S0",0));
516 if ( None != compManager )
518 LOG_ERROR("X11WindowSystem", "Could not create compositor window, annother compisite manager is already running");
522 CompositorWindow = XCreateWindow(x11Display, root, 0, 0, windowWidth, windowHeight,
523 0, windowVis->depth, InputOutput,
524 windowVis->visual, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &attr);
526 if (None == CompositorWindow)
528 LOG_ERROR("X11WindowSystem", "Could not create window");
532 LOG_DEBUG("X11WindowSystem", "Created the Compositor Window");
533 XSelectInput (x11Display, root,
534 SubstructureNotifyMask|
539 LOG_DEBUG("X11WindowSystem", "Created the window");
540 XSizeHints sizehints;
541 sizehints.width = windowWidth;
542 sizehints.height = windowHeight;
543 sizehints.flags = USSize;
544 XSetNormalHints(x11Display, CompositorWindow, &sizehints);
545 XSetStandardProperties(x11Display, CompositorWindow, CompositorWindowTitle, CompositorWindowTitle,
546 None, (char **)NULL, 0, &sizehints);
547 XMapRaised(x11Display, CompositorWindow);
552 static float timeSinceLastCalc = 0.0;
553 static float FPS = 0.0;
554 static struct timeval tv;
555 static struct timeval tv0;
556 static int Frame = 0;
559 void X11WindowSystem::calculateSurfaceFps(Surface *currentSurface, float time )
561 char floatStringBuffer[256];
562 float surfaceUpdateFps = ((float)(currentSurface->updateCounter)) / time ;
563 float surfaceDrawFps = ((float)(currentSurface->drawCounter)) / time ;
564 sprintf(floatStringBuffer, "0x%08x update fps: %3.2f", currentSurface->getID(),surfaceUpdateFps);
565 currentSurface->updateCounter = 0;
566 LOG_INFO("X11WindowSystem", "Surface " << floatStringBuffer);
567 sprintf(floatStringBuffer, "0x%08x draw fps: %3.2f", currentSurface->getID(),surfaceDrawFps);
568 currentSurface->drawCounter = 0;
569 LOG_INFO("X11WindowSystem", "Surface " << floatStringBuffer);
572 void X11WindowSystem::calculateFps()
574 // we have rendered a frame
576 std::list<Layer*> layers = m_pScene->getCurrentRenderOrder();
577 // every 3 seconds, calculate & print fps
578 gettimeofday(&tv, NULL);
579 timeSinceLastCalc = (float)(tv.tv_sec-tv0.tv_sec) + 0.000001*((float)(tv.tv_usec-tv0.tv_usec));
581 if (timeSinceLastCalc > 10.0f)
583 FPS = ((float)(Frame)) / timeSinceLastCalc;
584 char floatStringBuffer[256];
585 sprintf(floatStringBuffer, "Overall fps: %f", FPS);
586 for(std::list<Layer*>::const_iterator current = layers.begin(); current != layers.end(); current++)
588 SurfaceList surfaceList = (*current)->getAllSurfaces();
589 SurfaceListIterator surfaceIter = surfaceList.begin();
590 SurfaceListIterator surfaceIterEnd = surfaceList.end();
591 for(; surfaceIter != surfaceIterEnd ; ++surfaceIter)
593 calculateSurfaceFps((*surfaceIter),timeSinceLastCalc);
596 LOG_INFO("X11WindowSystem", floatStringBuffer);
602 void X11WindowSystem::RedrawAllLayers(bool clear, bool swap)
604 LayerList layers = m_pScene->getCurrentRenderOrder();
607 // Refresh HW Layers, find SW Layers
608 for(LayerListConstIterator current = layers.begin(); current != layers.end(); current++)
610 if ((*current)->getLayerType() == Hardware)
612 // Redraw HW layers independently of other layers
613 if (m_forceComposition || graphicSystem->needsRedraw(*current))
615 renderHWLayer(*current);
620 swLayers.push_back(*current);
624 if (m_forceComposition || graphicSystem->needsRedraw(swLayers))
626 graphicSystem->renderSWLayers(swLayers, clear);
630 graphicSystem->swapBuffers();
642 void X11WindowSystem::renderHWLayer(Layer *layer)
647 void X11WindowSystem::Redraw()
649 // draw all the layers
650 /*LOG_INFO("X11WindowSystem","Locking List");*/
651 m_pScene->lockScene();
653 RedrawAllLayers(true, true); // Clear and Swap
656 m_pScene->unlockScene();
658 m_forceComposition = false;
661 void X11WindowSystem::Screenshot()
663 /*LOG_INFO("X11WindowSystem","Locking List");*/
664 m_pScene->lockScene();
665 if (takeScreenshot == ScreenshotOfDisplay)
667 LOG_DEBUG("X11WindowSystem", "Taking screenshot");
668 RedrawAllLayers(true, false); // Do clear, Don't swap
670 else if(takeScreenshot == ScreenshotOfLayer)
672 LOG_DEBUG("X11WindowSystem", "Taking screenshot of layer");
673 Layer* layer = m_pScene->getLayer(screenShotLayerID);
677 graphicSystem->renderSWLayer(layer, true); // Do clear
680 else if(takeScreenshot == ScreenshotOfSurface)
682 LOG_DEBUG("X11WindowSystem", "Taking screenshot of surface");
683 Layer* layer = m_pScene->getLayer(screenShotLayerID);
684 Surface* surface = m_pScene->getSurface(screenShotSurfaceID);
686 graphicSystem->clearBackground();
687 if (layer != NULL && surface != NULL)
689 graphicSystem->beginLayer(layer);
690 graphicSystem->renderSurface(surface);
691 graphicSystem->endLayer();
695 graphicSystem->saveScreenShotOfFramebuffer(screenShotFile);
696 takeScreenshot = ScreenShotNone;
697 LOG_DEBUG("X11WindowSystem", "Done taking screenshot");
698 m_pScene->unlockScene();
699 /*LOG_INFO("X11WindowSystem","UnLocking List");*/
703 X11WindowSystem::error (Display *dpy, XErrorEvent *ev)
705 const char* name = NULL;
706 static char buffer[256];
708 if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows)
710 LOG_ERROR("X11WindowSystem", "Maybe another composite manager is already running");
716 XGetErrorText (dpy, ev->error_code, buffer, sizeof (buffer));
719 name = (strlen (name) > 0) ? name : "unknown";
720 LOG_ERROR("X11WindowSystem", "X Error: " << (int)ev->error_code << " " << name << " request : " << (int)ev->request_code << " minor: " << (int)ev->minor_code << " serial: " << (int)ev->serial);
725 bool X11WindowSystem::initXServer()
727 LOG_DEBUG("X11WindowSystem", "Initialising XServer connection");
731 if (!CreateCompositorWindow())
733 LOG_ERROR("X11WindowSystem", "Compositor Window creation failed " );
737 LOG_DEBUG("X11WindowSystem", "Compositor Window ID: " << CompositorWindow);
739 if ( CreatePixmapsForAllWindows() )
741 //unredirect our window
743 XCompositeUnredirectWindow(x11Display, background, CompositeRedirectManual);
745 XCompositeUnredirectWindow(x11Display, CompositorWindow, CompositeRedirectManual);
746 LOG_DEBUG("X11WindowSystem", "Initialised XServer connection complete");
748 LOG_ERROR("X11WindowSystem", "Initialised XServer connection failed");
756 * Thread in charge of the CompositorWindow eventloop
757 * Friend function of class X11WindowSystem
759 void * X11eventLoopCallback(void *ptr)
761 X11WindowSystem *windowsys = static_cast<X11WindowSystem*>( (X11WindowSystem*) ptr);
762 return windowsys->EventLoop();
765 void* X11WindowSystem::EventLoop()
768 LOG_INFO("X11WindowSystem", "XServer initialisation");
769 pthread_mutex_lock(&this->init_lock);
770 pthread_mutex_lock(&this->run_lock);
772 bool checkRedraw = false;
774 XSetErrorHandler(error);
776 LOG_DEBUG("X11WindowSystem", "open display connection");
777 status &= this->OpenDisplayConnection();
778 if ( status == false ) goto init_complete;
779 LOG_DEBUG("X11WindowSystem", "check for composite extension");
780 status &= this->checkForCompositeExtension();
781 if ( status == false ) goto init_complete;
782 LOG_DEBUG("X11WindowSystem", "check for damage extension");
783 status &= this->checkForDamageExtension();
784 if ( status == false ) goto init_complete;
785 LOG_DEBUG("X11WindowSystem", "init xserver");
786 status &= this->initXServer();
787 if ( status == false ) goto init_complete;
788 LOG_INFO("X11WindowSystem", "XServer initialisation completed");
789 LOG_DEBUG("X11WindowSystem", "Graphicsystem initialisation");
790 status &= this->graphicSystem->init(this->x11Display,this->CompositorWindow);
791 LOG_DEBUG("X11WindowSystem", "Graphicsystem initialisation complete");
793 this->m_success = status;
794 pthread_cond_signal(&this->init_condition);
795 pthread_mutex_unlock(&this->init_lock);
796 // Done with init, wait for lock to actually run (ie start/stop method called)
797 LOG_DEBUG("X11WindowSystem", "Waiting for startup");
798 pthread_cond_wait(&this->run_condition,&this->run_lock);
799 pthread_mutex_unlock(&this->run_lock);
800 LOG_DEBUG("X11WindowSystem", "Starting Event loop");
801 Layer* defaultLayer = 0;
803 // run the main event loop while rendering
804 gettimeofday(&tv0, NULL);
807 defaultLayer = this->m_pScene->createLayer(0);
808 defaultLayer->setOpacity(1.0);
809 defaultLayer->setDestinationRegion(Rectangle(0,0,this->resolutionWidth,this->resolutionHeight));
810 defaultLayer->setSourceRegion(Rectangle(0,0,this->resolutionWidth,this->resolutionHeight));
811 this->m_pScene->getCurrentRenderOrder().push_back(defaultLayer);
813 LOG_INFO("X11WindowSystem", "Enter render loop");
815 // clear screen to avoid garbage on startup
816 this->graphicSystem->clearBackground();
817 this->graphicSystem->swapBuffers();
818 XFlush(this->x11Display);
820 while (this->m_running)
822 #ifndef WITH_XTHREADS
823 if ( XPending(this->x11Display) > 0) {
824 #endif //WITH_XTHREADS
826 // blocking wait for event
827 XNextEvent(this->x11Display, &event);
828 this->m_pScene->lockScene();
835 LOG_DEBUG("X11WindowSystem", "CreateNotify Event");
836 Surface* s = this->m_pScene->createSurface(0);
838 this->NewWindow(s, event.xcreatewindow.window);
839 defaultLayer->addSurface(s);
843 case ConfigureNotify:
844 LOG_DEBUG("X11WindowSystem", "Configure notify Event");
845 this->configureSurfaceWindow( event.xconfigure.window);
850 LOG_DEBUG("X11WindowSystem", "Destroy Event");
851 this->DestroyWindow(event.xdestroywindow.window);
855 LOG_DEBUG("X11WindowSystem", "Expose Event");
859 LOG_DEBUG("X11WindowSystem", "Map Event");
860 this->MapWindow(event.xmap.window);
864 LOG_DEBUG("X11WindowSystem", "Unmap Event");
865 this->UnMapWindow(event.xunmap.window);
869 LOG_DEBUG("X11WindowSystem", "Reparent Event");
870 // if (event.xreparent.parent == root)
871 // renderer->NewWindow(event.xreparent.window);
873 // renderer->DestroyWindow(event.xreparent.window);
878 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_PRESSED, &event);
881 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_RELEASED, &event);
886 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_PRESSED, &event);
889 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_RELEASED, &event);
892 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_MOTION, &event);
896 // TODO. See @ref<X11WindowSystem-MultiTouch> at the end of this file
900 if (event.type == this->damage_event + XDamageNotify)
902 XDamageSubtract(this->x11Display, ((XDamageNotifyEvent*)(&event))->damage, None, None);
903 Surface* currentSurface = this->getSurfaceForWindow(((XDamageNotifyEvent*)(&event))->drawable);
904 if (currentSurface==NULL)
906 LOG_WARNING("X11WindowSystem", "Surface empty during damage notification");
909 if (currentSurface->platform != NULL)
911 /* Enable Rendering for Surface, after damage Notification was send successfully */
912 /* This will ensure, that the content is not dirty */
913 ((XPlatformSurface *)(currentSurface->platform))->enableRendering();
916 currentSurface->damaged = true;
917 currentSurface->updateCounter++;
922 this->m_pScene->unlockScene();
924 #ifndef WITH_XTHREADS
926 #endif //WITH_XTHREADS
927 if (this->m_systemState == REDRAW_STATE)
929 LOG_DEBUG("X11WindowSystem", "Enter Redraw State");
930 this->m_systemState = IDLE_STATE;
932 // check if we are supposed to take screenshot
933 if (this->takeScreenshot != ScreenShotNone)
939 this->checkForNewSurfaceNativeContent();
944 else if (this->m_systemState == WAKEUP_STATE)
946 LOG_DEBUG("X11WindowSystem", "Enter Wake Up State");
948 graphicSystem->releaseGraphicContext();
949 this->m_systemState = IDLE_STATE;
950 while (this->m_systemState != WAKEUP_STATE);
951 graphicSystem->activateGraphicContext();
952 this->m_systemState = IDLE_STATE;
960 #ifndef WITH_XTHREADS
962 /* put thread in sleep mode for 500 useconds due to safe cpu performance */
969 LOG_DEBUG("X11WindowSystem", "Renderer thread finished");
974 void X11WindowSystem::ManageXInputEvent(InputDevice type, InputEventState state, XEvent *pevent)
980 case INPUT_DEVICE_KEYBOARD:
982 surf = m_pInputManager->reportKeyboardEvent(state, ((XKeyEvent *) pevent)->keycode);
985 pevent->xany.window = surf->getNativeContent();
986 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
991 case INPUT_DEVICE_POINTER:
993 Point p = {state, ((XButtonEvent*)pevent)->x, ((XButtonEvent*)pevent)->y};
994 surf = m_pInputManager->reportPointerEvent(p);
997 ((XButtonEvent*)pevent)->x = p.x;
998 ((XButtonEvent*)pevent)->y = p.y;
999 pevent->xany.window = surf->getNativeContent();
1000 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
1005 case INPUT_DEVICE_TOUCH:
1011 case INPUT_DEVICE_ALL:
1017 #ifdef WITH_XTHREADS
1018 static Display* displaySignal = NULL;
1019 #endif //WITH_XTHREADS
1020 void X11WindowSystem::wakeUpRendererThread()
1022 #ifdef WITH_XTHREADS
1023 // send dummy expose event, to wake up blocking x11 event loop (XNextEvent)
1024 LOG_DEBUG("X11WindowSystem", "Sending dummy event to wake up renderer thread");
1025 if (NULL == displaySignal )
1027 displaySignal = XOpenDisplay(m_displayEnvironment);
1029 XExposeEvent ev = { Expose, 0, 1, displaySignal, CompositorWindow, 0, 0, 100, 100, 0 };
1030 XLockDisplay(displaySignal);
1031 XSendEvent(displaySignal, CompositorWindow, False, ExposureMask, (XEvent *) &ev);
1032 XUnlockDisplay(displaySignal);
1033 XFlush(displaySignal);
1034 LOG_DEBUG("X11WindowSystem", "Event successfully sent to renderer");
1035 #endif //WITH_XTHREADS
1038 void X11WindowSystem::signalRedrawEvent()
1040 // set flag that redraw is needed
1041 this->m_systemState = REDRAW_STATE;
1042 this->wakeUpRendererThread();
1045 void X11WindowSystem::cleanup(){
1046 LOG_DEBUG("X11WindowSystem", "Cleanup");
1047 if (None != CompositorWindow)
1049 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
1050 XCompositeUnredirectSubwindows(x11Display,root,CompositeRedirectManual);
1051 XDestroyWindow(x11Display,CompositorWindow);
1059 #ifdef WITH_XTHREADS
1060 if ( NULL != displaySignal )
1062 XCloseDisplay(displaySignal);
1064 #endif //WITH_XTHREADS
1065 XCloseDisplay(x11Display);
1069 bool X11WindowSystem::init(BaseGraphicSystem<Display*,Window>* base)
1071 #ifdef WITH_XTHREADS
1073 #endif //WITH_XTHREADS
1074 X11WindowSystem *renderer = this;
1075 graphicSystem = base;
1076 LOG_INFO("X11WindowSystem","Initialization");
1077 pthread_mutex_lock(&init_lock);
1078 int status = pthread_create( &renderThread, NULL, X11eventLoopCallback, (void*) renderer);
1081 pthread_mutex_unlock(&init_lock);
1084 pthread_cond_wait(&init_condition,&init_lock);
1085 /* while (!m_initialized)
1087 usleep(1000); // TODO
1088 LOG_DEBUG("X11WindowSystem","Waiting start complete " << m_initialized);
1091 pthread_mutex_unlock(&init_lock);
1092 LOG_INFO("X11WindowSystem","Initialization complete success :" << m_success);
1096 bool X11WindowSystem::start()
1099 pthread_mutex_lock(&this->run_lock);
1100 LOG_DEBUG("X11WindowSystem", "Startup");
1101 // let thread actually run
1102 if ( m_xerror == false )
1104 this->m_running = true;
1105 pthread_cond_signal(&this->run_condition);
1106 pthread_mutex_unlock(&this->run_lock);
1108 this->m_running = false;
1109 pthread_cond_signal(&this->run_condition);
1110 pthread_mutex_unlock(&this->run_lock);
1116 void X11WindowSystem::stop()
1118 LOG_INFO("X11WindowSystem","Stopping..");
1119 pthread_mutex_lock(&this->run_lock);
1120 this->m_running = false;
1121 // needed if start was never called, we wake up thread, so it can immediatly finish
1122 this->signalRedrawEvent();
1123 pthread_cond_signal(&this->run_condition);
1124 pthread_mutex_unlock(&this->run_lock);
1125 pthread_join(renderThread,NULL);
1128 void X11WindowSystem::allocatePlatformSurface(Surface* surface)
1130 LOG_DEBUG("X11WindowSystem","allocatePlatformSurface begin");
1131 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1134 LOG_DEBUG("X11WindowSystem","creating native surface for new window");
1135 // this surface does not have a native platform surface attached yet!
1136 NewWindow(surface, surface->getNativeContent());
1137 MapWindow(surface->getNativeContent());
1139 LOG_DEBUG("X11WindowSystem","allocatePlatformSurface end");
1142 void X11WindowSystem::deallocatePlatformSurface(Surface* surface)
1144 LOG_DEBUG("X11WindowSystem","deallocatePlatformSurface begin");
1145 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1148 LOG_DEBUG("X11WindowSystem","destroyingnative surface");
1149 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
1151 if (nativeSurface->pixmap)
1153 XFreePixmap(x11Display, nativeSurface->pixmap);
1156 surface->renderPropertyChanged = true;
1157 delete surface->platform;
1158 surface->platform = NULL;
1160 LOG_DEBUG("X11WindowSystem","deallocatePlatformSurface end");
1163 void X11WindowSystem::doScreenShot(std::string fileName)
1165 takeScreenshot = ScreenshotOfDisplay;
1166 screenShotFile = fileName;
1169 void X11WindowSystem::doScreenShotOfLayer(std::string fileName, const uint id)
1171 takeScreenshot = ScreenshotOfLayer;
1172 screenShotFile = fileName;
1173 screenShotLayerID = id;
1176 void X11WindowSystem::doScreenShotOfSurface(std::string fileName, const uint id, const uint layer_id)
1178 takeScreenshot = ScreenshotOfSurface;
1179 screenShotFile = fileName;
1180 screenShotSurfaceID = id;
1181 screenShotLayerID = layer_id;
1187 * @subsection <X11WindowSystem-MultiTouch> (Multi Touch)
1189 * X11 multi touch is not yet supported by Layer Manager.
1191 * TODO to add support:
1192 * - Move all event management to xi2
1193 * - For multi touch, make sure XInput protocol is > 2.2
1194 * -> Via cmake ==> ?
1195 * -> At runtime ==> http://who-t.blogspot.fr/2011/12/multitouch-in-x-getting-events.html
1196 * - Register for XIDirectTouch. (No plan (yet?) to support XIDependentTouch)
1197 * - Call m_pInputManager->reportTouchEvent() from ManageXInputEvent() to translate screen wide touch coordinates into surface wide coordinates
1198 * - Forward the event to the native handle of the surface returned by m_pInputManager->reportTouchEvent()
1201 * + XInput 2.x protocol : ftp://www.x.org/pub/xorg/current/doc/inputproto/XI2proto.txt
1202 * + LWN article : http://lwn.net/Articles/475886/