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"
24 #include "Rectangle.h"
28 #include <X11/Xutil.h>
29 #include <X11/Xatom.h>
30 #include <X11/extensions/Xcomposite.h>
31 #include <X11/extensions/Xdamage.h>
38 int X11WindowSystem::composite_opcode;
39 int X11WindowSystem::damage_opcode;
40 const char X11WindowSystem::CompositorWindowTitle[] = "LayerManager";
41 bool X11WindowSystem::m_xerror = false;
43 X11WindowSystem::X11WindowSystem(const char* displayname,
47 InputManager* pInputManager,
48 GetVisualInfoFunction func)
49 : BaseWindowSystem(pScene, pInputManager)
50 , takeScreenshot(ScreenShotNone)
52 , screenShotSurfaceID(0)
54 , displayname(displayname)
57 , resolutionWidth(width)
58 , resolutionHeight(height)
68 /*, m_initialized(false)*/
70 , m_systemState(IDLE_STATE)
71 , m_displayEnvironment(NULL)
75 , windowHeight(height)
78 , m_fpsinterval(10.0f)
82 LOG_DEBUG("X11WindowSystem", "creating X11WindowSystem");
84 // init and take mutex, so windowsystem only does init phase until mutex is released again
85 pthread_mutex_init(&run_lock, NULL);
86 pthread_cond_init(&run_condition, NULL);
87 pthread_cond_init(&init_condition, NULL);
88 pthread_mutex_init(&init_lock, NULL);
91 X11WindowSystem::~X11WindowSystem()
99 XVisualInfo* X11WindowSystem::getDefaultVisual(Display *dpy)
101 XVisualInfo* windowVis = new XVisualInfo();
104 windowVis->depth = DefaultDepth(dpy, DefaultScreen(dpy));
105 if (!XMatchVisualInfo(dpy, 0, windowVis->depth, TrueColor, windowVis))
107 LOG_ERROR("X11WindowSystem", "Error: Required visual not found\n");
114 LOG_ERROR("X11WindowSystem", "Error: Unable to acquire visual\n");
119 bool X11WindowSystem::OpenDisplayConnection()
121 m_displayEnvironment = getenv("DISPLAY");
123 if (m_displayEnvironment == NULL)
125 m_displayEnvironment = ":0.0";
126 setenv("DISPLAY", m_displayEnvironment, 1);
129 x11Display = XOpenDisplay(m_displayEnvironment);
132 LOG_ERROR("X11WindowSystem", "Couldn't open default display!");
135 LOG_DEBUG("X11WindowSystem", "Display connection: " << x11Display);
139 bool X11WindowSystem::checkForCompositeExtension()
141 if (x11Display == NULL || !XQueryExtension(x11Display, COMPOSITE_NAME, &composite_opcode, &composite_event, &composite_error))
143 LOG_ERROR("X11WindowSystem", "No composite extension");
146 XCompositeQueryVersion(x11Display, &composite_major, &composite_minor);
147 LOG_DEBUG("X11WindowSystem", "Found composite extension: composite opcode: " << composite_opcode);
148 LOG_DEBUG("X11WindowSystem", "composite_major: " << composite_major);
149 LOG_DEBUG("X11WindowSystem", "composite_minor: " << composite_minor);
153 bool X11WindowSystem::checkForDamageExtension()
155 if (x11Display == NULL || !XQueryExtension(x11Display, DAMAGE_NAME, &damage_opcode,
156 &damage_event, &damage_error))
158 LOG_ERROR("X11WindowSystem", "No damage extension");
161 XDamageQueryVersion(x11Display, &damage_major, &damage_minor);
162 x11DamageRegion = XFixesCreateRegion(x11Display, 0, 0);
163 LOG_DEBUG("X11WindowSystem", "Found damage extension: damage opcode: " << damage_opcode);
164 LOG_DEBUG("X11WindowSystem", "damage_major: " << damage_major);
165 LOG_DEBUG("X11WindowSystem", "damage_minor: " << damage_minor);
169 void X11WindowSystem::printDebug()
171 // print stuff about layerlist
172 std::stringstream debugmessage;
173 debugmessage << "Layer: ID | X | Y | W | H | Al. \n";
175 LayerList list = m_pScene->getCurrentRenderOrder(0);
178 LayerListConstIterator iter = list.begin();
179 LayerListConstIterator iterEnd = list.end();
181 for (; iter != iterEnd; ++iter)
183 Rectangle dest = (*iter)->getDestinationRegion();
184 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";
186 debugmessage << " Surface: ID |Al.| SVP: X | Y | W | H DVP: X | Y | W | H \n";
188 // loop the surfaces of within each layer
189 SurfaceList surfaceList = (*iter)->getAllSurfaces();
190 SurfaceListIterator surfaceIter = surfaceList.begin();
191 SurfaceListIterator surfaceIterEnd = surfaceList.end();
193 for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
195 Rectangle src = (*surfaceIter)->getSourceRegion();
196 Rectangle dest = (*surfaceIter)->getDestinationRegion();
197 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";
200 LOG_DEBUG("X11WindowSystem", debugmessage.str());
203 Window * getListOfAllTopLevelWindows(Display *disp, unsigned int *len)
205 LOG_DEBUG("X11WindowSystem", "Getting list of all windows");
208 Window parent_return;
209 Window root = XDefaultRootWindow(disp);
210 XQueryTree(disp, root, &root_return, &parent_return, &children, len);
214 bool X11WindowSystem::isWindowValid(Window w)
216 // skip our own two windows
217 return (w != None && w != CompositorWindow);
220 Surface* X11WindowSystem::getSurfaceForWindow(Window w)
222 // go though all surfaces
223 const std::map<unsigned int, Surface*> surfaces = m_pScene->getAllSurfaces();
224 for (std::map<unsigned int, Surface*>::const_iterator currentS = surfaces.begin(); currentS != surfaces.end(); ++currentS)
226 Surface* currentSurface = (*currentS).second;
231 if (currentSurface->getNativeContent() == static_cast<int>(w))
233 return currentSurface;
236 LOG_DEBUG("X11WindowSystem", "could not find surface for window " << w);
240 void X11WindowSystem::checkForNewSurfaceNativeContent()
242 m_pScene->lockScene();
243 LayerList layers = m_pScene->getCurrentRenderOrder(0);
244 for (LayerListConstIterator current = layers.begin(); current != layers.end(); current++)
246 SurfaceList surfaces = (*current)->getAllSurfaces();
247 for (SurfaceListConstIterator currentS = surfaces.begin(); currentS != surfaces.end(); currentS++)
249 if ((*currentS)->hasNativeContent())
251 allocatePlatformSurface(*currentS);
253 else // While we are at it, also cleanup any stale native content
255 deallocatePlatformSurface(*currentS);
259 m_pScene->unlockScene();
262 void X11WindowSystem::configureSurfaceWindow(Window window)
264 if (isWindowValid(window))
266 LOG_INFO("X11WindowSystem", "Configure surface 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 LOG_INFO("X11WindowSystem", "Configure surface dimension " << surface->getID());
281 if (surface->OriginalSourceHeight != winHeight || surface->OriginalSourceWidth != winWidth)
283 LOG_INFO("X11WindowSystem","Surface dimension differs from creation dimension");
284 unsigned int layerid = surface->getContainingLayerId();
285 surface->OriginalSourceHeight = winHeight;
286 surface->OriginalSourceWidth = winWidth;
288 Rectangle newDestination = surface->getDestinationRegion();
289 newDestination.width = surface->OriginalSourceWidth;
290 newDestination.height = surface->OriginalSourceHeight;
291 surface->setDestinationRegion(newDestination);
292 Rectangle newSource = surface->getSourceRegion();
293 newSource.width = surface->OriginalSourceWidth;
294 newSource.height = surface->OriginalSourceHeight;
295 surface->setSourceRegion(newSource);
297 if ( layerid != Surface::INVALID_ID )
299 surface->calculateTargetDestination(m_pScene->getLayer(layerid)->getSourceRegion()
300 ,m_pScene->getLayer(layerid)->getDestinationRegion());
302 surface->damaged = false; // Waiting for damage event to get updated content
303 surface->m_surfaceResized = true;
304 LOG_INFO("X11WindowSystem", "Dimension : " << surface->OriginalSourceWidth << ", " << surface->OriginalSourceHeight);
305 LOG_INFO("X11WindowSystem", "SourceDim : " << surface->getSourceRegion().width << ", " << surface->getSourceRegion().height);
306 LOG_INFO("X11WindowSystem", "DestDim : " << surface->getDestinationRegion().width << ", " << surface->getDestinationRegion().height);
309 if (!surface->platform)
311 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
317 LOG_INFO("X11WindowSystem", "Done configure surface " << surface->getID() << " for window " << window);
321 void X11WindowSystem::MapWindow(Window window)
323 LOG_DEBUG("X11WindowSystem", "Map window begin");
324 if (isWindowValid(window))
326 XWindowAttributes att;
327 XGetWindowAttributes(x11Display, window, &att);
328 /* LOG_DEBUG("X11WindowSystem", "XCompositeRedirectWindow()");
329 XCompositeRedirectWindow(x11Display, window, CompositeRedirectManual);
330 XSync(x11Display, 0);*/
331 if (att.map_state == IsViewable && att.override_redirect == 0)
333 LOG_DEBUG("X11WindowSystem", "Mapping surface to window " << window);
334 Surface* surface = getSurfaceForWindow(window);
337 LOG_WARNING("X11WindowSystem", "Could not map surface to window " << window);
340 if (!surface->platform)
342 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
346 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
347 if (x11surf->isMapped)
349 LOG_WARNING("X11WindowSystem", "Platform surface already mapped");
352 x11surf->isMapped = true;
354 LOG_DEBUG("X11WindowSystem", "getting pixmap for window");
355 LOG_DEBUG("X11WindowSystem", "window width: " << att.width);
356 LOG_DEBUG("X11WindowSystem", "window height: " << att.height);
357 LOG_DEBUG("X11WindowSystem", "map state: " << att.map_state);
358 LOG_DEBUG("X11WindowSystem", "window x: " << att.x);
359 LOG_DEBUG("X11WindowSystem", "window backing: " << att.backing_pixel);
360 LOG_DEBUG("X11WindowSystem", "window save under: " << att.save_under);
361 LOG_DEBUG("X11WindowSystem", "window orride: " << att.override_redirect);
362 LOG_DEBUG("X11WindowSystem", "parent/root: " << att.root);
363 LOG_DEBUG("X11WindowSystem", "root window: " << DefaultRootWindow(x11Display));
365 int winWidth = att.width;
366 int winHeight = att.height;
368 surface->OriginalSourceHeight = winHeight;
369 surface->OriginalSourceWidth = winWidth;
370 surface->renderPropertyChanged = true;
372 graphicSystem->getTextureBinder()->createClientBuffer(surface);
373 x11surf->enableRendering();
374 XSync(x11Display, 0);
376 LOG_DEBUG("X11WindowSystem", "Mapping Surface " << surface->getID() << " to window " << window);
377 LOG_DEBUG("X11WindowSystem", "Mapping successfull");
380 LOG_DEBUG("X11WindowSystem", "Map window end");
383 void X11WindowSystem::UnMapWindow(Window window)
385 LOG_DEBUG("X11WindowSystem", "Unmap begin");
386 if (isWindowValid(window))
388 LOG_DEBUG("X11WindowSystem", "Unmapping surface from window " << window);
389 Surface* surface = getSurfaceForWindow(window);
392 LOG_WARNING("X11WindowSystem", "Could not unmap window " << window);
395 if (!surface->platform)
397 LOG_WARNING("X11WindowSystem", "Platform surface not available for window " << window);
400 XPlatformSurface* x11surf = (XPlatformSurface*)surface->platform;
401 x11surf->disableRendering();
402 LOG_DEBUG("X11WindowSystem", "Unmapping surface " << surface->getID());
403 if (!x11surf->isMapped)
405 LOG_WARNING("X11WindowSystem", "Platform surface already unmapped");
408 x11surf->isMapped = false;
410 LOG_DEBUG("X11WindowSystem", "Destroying ClientBuffer");
411 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
412 XSync(x11Display, 0);
414 LOG_DEBUG("X11WindowSystem", "Removing X Pixmap");
417 int result = XFreePixmap(x11Display, x11surf->pixmap);
418 LOG_DEBUG("X11WindowSystem", "XFreePixmap() returned " << result);
421 surface->renderPropertyChanged = true;
423 LOG_DEBUG("X11WindowSystem", "Unmap finished");
426 void X11WindowSystem::NewWindow(Surface* surface, Window window)
428 if (isWindowValid(window))
430 LOG_INFO("X11WindowSystem", "Creating Surface for new window " << window);
431 // get the windows attributes
432 XWindowAttributes att;
433 int status = XGetWindowAttributes(x11Display, window, &att);
434 LOG_DEBUG("X11WindowSystem", "Got window attrbutes");
436 status = XFetchName(x11Display, window, &name);
437 LOG_DEBUG("X11WindowSystem", "Got window name");
438 if (status >= Success && name)
440 LOG_DEBUG("X11WindowSystem", "Found window: " << window << " " << name);
441 char GuiTitle[] = "Layermanager Remote GUI\0";
442 if (strcmp(name, GuiTitle) == 0)
444 LOG_DEBUG("X11WindowSystem", "Found gui window: repositioning it");
445 XCompositeUnredirectWindow(x11Display, window, CompositeRedirectManual);
446 XMoveWindow(x11Display, window, 50, 500);
447 XMapRaised(x11Display, window);
452 LOG_DEBUG("X11WindowSystem", "Error fetching window name");
455 if (att.c_class == InputOutput)
457 LOG_DEBUG("X11WindowSystem", "Creating New Damage for window - " << window);
458 XDamageCreate(x11Display, window, XDamageReportNonEmpty);
462 XLowerWindow(x11Display, window);
464 surface->setNativeContent(window);
465 XPlatformSurface * platformSurface = (XPlatformSurface*)graphicSystem->getTextureBinder()->createPlatformSurface(surface);
466 platformSurface->isMapped = false;
468 LOG_DEBUG("X11WindowSystem", "Created native Surface for X11 Window id " << window);
470 surface->platform = platformSurface;
472 int winWidth = att.width;
473 int winHeight = att.height;
475 surface->OriginalSourceHeight = winHeight;
476 surface->OriginalSourceWidth = winWidth;
478 LOG_DEBUG("X11WindowSystem", "Original width " << surface->OriginalSourceWidth);
479 LOG_DEBUG("X11WindowSystem", "Original heigth " << surface->OriginalSourceHeight);
483 LOG_DEBUG("X11WindowSystem", "skipping window");
485 LOG_INFO("X11WindowSystem", "created the new surface");
488 void X11WindowSystem::DestroyWindow(Window window)
490 if (isWindowValid(window))
492 LOG_DEBUG("X11WindowSystem", "Destroying Surface for window " << window);
493 Surface* surface = getSurfaceForWindow(window);
496 LOG_WARNING("X11WindowSystem", "Could not find surface for window " << window);
499 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
500 LOG_DEBUG("X11WindowSystem", "Unmapping window " << window);
502 LOG_DEBUG("X11WindowSystem", "Remove Native Content from Surface " << surface->getID());
503 surface->removeNativeContent();
504 /* To force a recomposition of all surface which are behind of that surface inside the Layer RenderOrder */
505 surface->renderPropertyChanged = true;
506 /* Remove synchronized flag, no damage will occur anymore */
507 surface->setSynchronized(false);
508 surface->m_resizesync = false;
509 delete surface->platform;
510 surface->platform = NULL;
514 bool X11WindowSystem::CreatePixmapsForAllWindows()
517 LOG_DEBUG("X11WindowSystem", "redirecting all windows");
518 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
519 XCompositeRedirectSubwindows(x11Display, root, CompositeRedirectManual);
520 XSync(x11Display, 0);
524 bool X11WindowSystem::CreateCompositorWindow()
526 LOG_DEBUG("X11WindowSystem", "Get root window");
528 CompositorWindow = None;
529 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
531 LOG_DEBUG("X11WindowSystem", "Creating Compositor Window");
533 XSetWindowAttributes attr;
534 // draw a black background the full size of the resolution
535 attr.override_redirect = True;
536 attr.event_mask = ExposureMask
537 | StructureNotifyMask
543 attr.background_pixel = 0;
544 attr.border_pixel = 0;
545 windowVis = getVisualFunc(x11Display);
550 attr.colormap = XCreateColormap(x11Display, root, windowVis->visual, AllocNone);
551 attr.override_redirect = True;
553 Window compManager = XGetSelectionOwner(x11Display, XInternAtom(x11Display, "_NET_WM_CM_S0", 0));
554 if (None != compManager)
556 LOG_ERROR("X11WindowSystem", "Could not create compositor window, annother compisite manager is already running");
560 CompositorWindow = XCreateWindow(x11Display, root, 0, 0, windowWidth, windowHeight,
561 0, windowVis->depth, InputOutput,
562 windowVis->visual, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &attr);
564 if (None == CompositorWindow)
566 LOG_ERROR("X11WindowSystem", "Could not create window");
570 LOG_DEBUG("X11WindowSystem", "Created the Compositor Window");
571 XSelectInput(x11Display, root,
572 SubstructureNotifyMask|
577 LOG_DEBUG("X11WindowSystem", "Created the window");
578 XSizeHints sizehints;
579 sizehints.width = windowWidth;
580 sizehints.height = windowHeight;
581 sizehints.flags = USSize;
582 XSetNormalHints(x11Display, CompositorWindow, &sizehints);
583 XSetStandardProperties(x11Display, CompositorWindow, CompositorWindowTitle, CompositorWindowTitle,
584 None, (char **)NULL, 0, &sizehints);
585 XMapRaised(x11Display, CompositorWindow);
590 static float timeSinceLastCalc = 0.0;
591 static float FPS = 0.0;
592 static struct timeval tv;
593 static struct timeval tv0;
594 static int Frame = 0;
597 void X11WindowSystem::calculateSurfaceFps(Surface *currentSurface, float time)
599 char floatStringBuffer[256];
600 float surfaceUpdateFps = ((float)(currentSurface->updateCounter)) / time;
601 float surfaceDrawFps = ((float)(currentSurface->drawCounter)) / time;
602 sprintf(floatStringBuffer, "0x%08x update fps: %3.2f", currentSurface->getID(), surfaceUpdateFps);
603 currentSurface->updateCounter = 0;
604 LOG_INFO("X11WindowSystem", "Surface " << floatStringBuffer);
605 sprintf(floatStringBuffer, "0x%08x draw fps: %3.2f", currentSurface->getID(), surfaceDrawFps);
606 currentSurface->drawCounter = 0;
607 LOG_INFO("X11WindowSystem", "Surface " << floatStringBuffer);
610 void X11WindowSystem::calculateFps()
612 // we have rendered a frame
614 std::list<Layer*> layers = m_pScene->getCurrentRenderOrder(0);
615 // every 3 seconds, calculate & print fps
616 gettimeofday(&tv, NULL);
617 timeSinceLastCalc = (float)(tv.tv_sec-tv0.tv_sec) + 0.000001*((float)(tv.tv_usec-tv0.tv_usec));
619 if (timeSinceLastCalc > m_fpsinterval)
621 FPS = ((float)(Frame)) / timeSinceLastCalc;
622 char floatStringBuffer[256];
623 sprintf(floatStringBuffer, "Overall fps: %f", FPS);
624 for (std::list<Layer*>::const_iterator current = layers.begin(); current != layers.end(); ++current)
626 SurfaceList surfaceList = (*current)->getAllSurfaces();
627 SurfaceListIterator surfaceIter = surfaceList.begin();
628 SurfaceListIterator surfaceIterEnd = surfaceList.end();
629 for (; surfaceIter != surfaceIterEnd; ++surfaceIter)
631 calculateSurfaceFps((*surfaceIter), timeSinceLastCalc);
634 LOG_INFO("X11WindowSystem", floatStringBuffer);
640 bool X11WindowSystem::RedrawAllLayers(bool clear, bool swap)
643 LayerList layers = m_pScene->getCurrentRenderOrder(0);
646 // Refresh HW Layers, find SW Layers
647 for (LayerListConstIterator current = layers.begin(); current != layers.end(); ++current)
649 if ((*current)->getLayerType() == Hardware)
651 // Redraw HW layers independently of other layers
652 if (m_forceComposition || graphicSystem->needsRedraw(*current))
654 renderHWLayer(*current);
659 swLayers.push_back(*current);
663 if (m_forceComposition || graphicSystem->needsRedraw(swLayers))
665 graphicSystem->renderSWLayers(swLayers, clear);
670 graphicSystem->swapBuffers();
683 void X11WindowSystem::renderHWLayer(Layer *layer)
688 void X11WindowSystem::Redraw()
690 // draw all the layers
691 /*LOG_INFO("X11WindowSystem","Locking List");*/
693 m_pScene->lockScene();
695 clear = RedrawAllLayers(true, true); // Clear and Swap
701 m_pScene->unlockScene();
703 m_forceComposition = false;
706 void X11WindowSystem::Screenshot()
708 /*LOG_INFO("X11WindowSystem","Locking List");*/
709 m_pScene->lockScene();
710 if (takeScreenshot == ScreenshotOfDisplay)
712 LOG_DEBUG("X11WindowSystem", "Taking screenshot");
713 RedrawAllLayers(true, false); // Do clear, Don't swap
715 else if (takeScreenshot == ScreenshotOfLayer)
717 LOG_DEBUG("X11WindowSystem", "Taking screenshot of layer");
718 Layer* layer = m_pScene->getLayer(screenShotLayerID);
722 graphicSystem->renderSWLayer(layer, true); // Do clear
725 else if (takeScreenshot == ScreenshotOfSurface)
727 LOG_DEBUG("X11WindowSystem", "Taking screenshot of surface");
728 Layer* layer = m_pScene->getLayer(screenShotLayerID);
729 Surface* surface = m_pScene->getSurface(screenShotSurfaceID);
731 graphicSystem->clearBackground();
732 if (layer != NULL && surface != NULL)
734 graphicSystem->beginLayer(layer);
735 graphicSystem->renderSurface(surface);
736 graphicSystem->endLayer();
740 graphicSystem->saveScreenShotOfFramebuffer(screenShotFile);
741 takeScreenshot = ScreenShotNone;
742 LOG_DEBUG("X11WindowSystem", "Done taking screenshot");
743 m_pScene->unlockScene();
744 /*LOG_INFO("X11WindowSystem","UnLocking List");*/
748 X11WindowSystem::error(Display *dpy, XErrorEvent *ev)
750 const char* name = NULL;
751 static char buffer[256];
753 if (ev->request_code == composite_opcode && ev->minor_code == X_CompositeRedirectSubwindows)
755 LOG_ERROR("X11WindowSystem", "Maybe another composite manager is already running");
761 XGetErrorText(dpy, ev->error_code, buffer, sizeof(buffer));
764 name = (strlen(name) > 0) ? name : "unknown";
765 LOG_ERROR("X11WindowSystem", "X Error: " << (int)ev->error_code << " " << name << " request : " << (int)ev->request_code << " minor: " << (int)ev->minor_code << " serial: " << (int)ev->serial);
770 bool X11WindowSystem::initXServer()
772 LOG_DEBUG("X11WindowSystem", "Initialising XServer connection");
776 if (!CreateCompositorWindow())
778 LOG_ERROR("X11WindowSystem", "Compositor Window creation failed ");
782 LOG_DEBUG("X11WindowSystem", "Compositor Window ID: " << CompositorWindow);
784 if (CreatePixmapsForAllWindows())
786 //unredirect our window
788 XCompositeUnredirectWindow(x11Display, background, CompositeRedirectManual);
790 XCompositeUnredirectWindow(x11Display, CompositorWindow, CompositeRedirectManual);
791 LOG_DEBUG("X11WindowSystem", "Initialised XServer connection complete");
795 LOG_ERROR("X11WindowSystem", "Initialised XServer connection failed");
803 * Thread in charge of the CompositorWindow eventloop
804 * Friend function of class X11WindowSystem
806 void * X11eventLoopCallback(void *ptr)
808 X11WindowSystem *windowsys = static_cast<X11WindowSystem*>((X11WindowSystem*) ptr);
809 return windowsys->EventLoop();
812 void* X11WindowSystem::EventLoop()
815 LOG_INFO("X11WindowSystem", "XServer initialisation");
816 pthread_mutex_lock(&this->init_lock);
817 pthread_mutex_lock(&this->run_lock);
819 bool checkRedraw = false;
821 XSetErrorHandler(error);
823 LOG_DEBUG("X11WindowSystem", "open display connection");
824 status &= this->OpenDisplayConnection();
825 if (status == false) goto init_complete;
826 LOG_DEBUG("X11WindowSystem", "check for composite extension");
827 status &= this->checkForCompositeExtension();
828 if (status == false) goto init_complete;
829 LOG_DEBUG("X11WindowSystem", "check for damage extension");
830 status &= this->checkForDamageExtension();
831 if (status == false) goto init_complete;
832 LOG_DEBUG("X11WindowSystem", "init xserver");
833 status &= this->initXServer();
834 if (status == false) goto init_complete;
835 LOG_INFO("X11WindowSystem", "XServer initialisation completed");
836 LOG_DEBUG("X11WindowSystem", "Graphicsystem initialisation");
837 status &= this->graphicSystem->init(this->x11Display, this->CompositorWindow);
838 LOG_DEBUG("X11WindowSystem", "Graphicsystem initialisation complete");
840 this->m_success = status;
841 pthread_cond_signal(&this->init_condition);
842 pthread_mutex_unlock(&this->init_lock);
843 // Done with init, wait for lock to actually run (ie start/stop method called)
844 LOG_DEBUG("X11WindowSystem", "Waiting for startup");
845 pthread_cond_wait(&this->run_condition, &this->run_lock);
846 pthread_mutex_unlock(&this->run_lock);
847 LOG_DEBUG("X11WindowSystem", "Starting Event loop");
848 Layer* defaultLayer = 0;
850 // run the main event loop while rendering
851 gettimeofday(&tv0, NULL);
854 defaultLayer = this->m_pScene->createLayer(0, 0);
855 defaultLayer->setOpacity(1.0);
856 defaultLayer->setDestinationRegion(Rectangle(0, 0, this->resolutionWidth, this->resolutionHeight));
857 defaultLayer->setSourceRegion(Rectangle(0, 0, this->resolutionWidth, this->resolutionHeight));
858 this->m_pScene->getCurrentRenderOrder(0).push_back(defaultLayer);
860 LOG_INFO("X11WindowSystem", "Enter render loop");
862 // clear screen to avoid garbage on startup
863 this->graphicSystem->clearBackground();
864 this->graphicSystem->swapBuffers();
865 XFlush(this->x11Display);
867 while (this->m_running)
870 // blocking wait for event
871 XNextEvent(this->x11Display, &event);
872 this->m_pScene->lockScene();
879 LOG_DEBUG("X11WindowSystem", "CreateNotify Event");
880 Surface* s = this->m_pScene->createSurface(0, 0);
882 this->NewWindow(s, event.xcreatewindow.window);
883 defaultLayer->addSurface(s);
887 case ConfigureNotify:
889 LOG_DEBUG("X11WindowSystem", "Configure notify Event");
890 this->configureSurfaceWindow( event.xconfigure.window);
891 Surface* surfaceWindow = this->getSurfaceForWindow( event.xconfigure.window);
892 if (surfaceWindow!=NULL)
894 checkRedraw = !surfaceWindow->m_surfaceResized;
900 LOG_DEBUG("X11WindowSystem", "Destroy Event");
901 this->DestroyWindow(event.xdestroywindow.window);
905 if (event.xexpose.window == this->CompositorWindow)
908 LOG_DEBUG("X11WindowSystem", "Expose Event triggered by internal Redraw");
912 LOG_DEBUG("X11WindowSystem", "Expose Event triggered by external Application");
916 LOG_DEBUG("X11WindowSystem", "Map Event");
917 this->MapWindow(event.xmap.window);
921 LOG_DEBUG("X11WindowSystem", "Unmap Event");
922 this->UnMapWindow(event.xunmap.window);
926 LOG_DEBUG("X11WindowSystem", "Reparent Event");
927 // if (event.xreparent.parent == root)
928 // renderer->NewWindow(event.xreparent.window);
930 // renderer->DestroyWindow(event.xreparent.window);
935 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_PRESSED, &event);
938 ManageXInputEvent(INPUT_DEVICE_KEYBOARD, INPUT_STATE_RELEASED, &event);
943 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_PRESSED, &event);
946 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_RELEASED, &event);
949 ManageXInputEvent(INPUT_DEVICE_POINTER, INPUT_STATE_MOTION, &event);
953 // TODO. See @ref<X11WindowSystem-MultiTouch> at the end of this file
956 if (event.type == this->damage_event + XDamageNotify)
958 XDamageSubtract(this->x11Display, ((XDamageNotifyEvent*)(&event))->damage, None, x11DamageRegion);
959 Surface* currentSurface = this->getSurfaceForWindow(((XDamageNotifyEvent*)(&event))->drawable);
960 if (currentSurface == NULL)
962 LOG_WARNING("X11WindowSystem", "Surface empty during damage notification");
967 if (currentSurface->platform != NULL)
969 XRectangle* rectangles;
974 /* Enable Rendering for Surface, after damage Notification was send successfully */
975 /* This will ensure, that the content is not dirty */
976 ((XPlatformSurface *)(currentSurface->platform))->enableRendering();
977 geometry = ((XDamageNotifyEvent*)(&event))->geometry;
978 area = ((XDamageNotifyEvent*)(&event))->area;
980 LOG_DEBUG("X11WindowSystem","Damaged Geometry : [ " << geometry.x << ", " << geometry.y <<
981 ", " << geometry.width << ", " << geometry.height << " ]");
982 LOG_DEBUG("X11WindowSystem","Damaged Area : [ " << area.x << ", " << area.y <<
983 ", " << area.width << ", " << area.height << " ]");
985 rectangles = XFixesFetchRegionAndBounds (this->x11Display, x11DamageRegion, &numberRects, &bounds);
987 LOG_DEBUG("X11WindowSystem","Damaged Bounds : [ " << bounds.x << ", " << bounds.y <<
988 ", " << bounds.width << ", " << bounds.height << " ]\n");
989 // e->geometry is the geometry of the damaged window
990 // e->area is the bounding rect for the damaged area
991 if ( currentSurface->OriginalSourceWidth != geometry.width || currentSurface->OriginalSourceHeight != geometry.height )
993 LOG_DEBUG("X11WindowSystem","Damaged Geometry differs from size : [ " << geometry.x << ", " << geometry.y <<
994 ", " << geometry.width << ", " << geometry.height << " ]");
995 currentSurface->m_surfaceResized = true;
999 /* Ignore Damage Events after Resize, the content can be invalid */
1000 if (!currentSurface->m_surfaceResized)
1002 currentSurface->damaged = true;
1003 currentSurface->updateCounter++;
1004 currentSurface->m_resizesync = false;
1007 LOG_DEBUG("X11WindowSystem", "Skipping Damage Event which was triggered after ConfigureNotify");
1008 currentSurface->m_resizesync = true;
1009 currentSurface->m_surfaceResized = false;
1015 this->m_pScene->unlockScene();
1017 if (this->m_systemState == REDRAW_STATE)
1019 LOG_DEBUG("X11WindowSystem", "Enter Redraw State");
1020 this->m_systemState = IDLE_STATE;
1022 // check if we are supposed to take screenshot
1023 if (this->takeScreenshot != ScreenShotNone)
1029 this->checkForNewSurfaceNativeContent();
1033 else if (this->m_systemState == WAKEUP_STATE)
1035 LOG_DEBUG("X11WindowSystem", "Enter Wake Up State");
1036 checkRedraw = false;
1037 graphicSystem->releaseGraphicContext();
1038 this->m_systemState = IDLE_STATE;
1039 while (this->m_systemState != WAKEUP_STATE);
1040 graphicSystem->activateGraphicContext();
1041 this->m_systemState = IDLE_STATE;
1047 checkRedraw = false;
1051 LOG_DEBUG("X11WindowSystem", "Renderer thread finished");
1056 void X11WindowSystem::ManageXInputEvent(InputDevice type, InputEventState state, XEvent *pevent)
1062 case INPUT_DEVICE_KEYBOARD:
1064 surf = m_pInputManager->reportKeyboardEvent(state, ((XKeyEvent *) pevent)->keycode);
1067 pevent->xany.window = surf->getNativeContent();
1068 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
1073 case INPUT_DEVICE_POINTER:
1075 Point p = {state, ((XButtonEvent*)pevent)->x, ((XButtonEvent*)pevent)->y};
1076 surf = m_pInputManager->reportPointerEvent(p);
1079 ((XButtonEvent*)pevent)->x = p.x;
1080 ((XButtonEvent*)pevent)->y = p.y;
1081 pevent->xany.window = surf->getNativeContent();
1082 XSendEvent(x11Display, pevent->xany.window, false, 0, pevent);
1087 case INPUT_DEVICE_TOUCH:
1092 case INPUT_DEVICE_ALL:
1098 static Display* displaySignal = NULL;
1100 void X11WindowSystem::wakeUpRendererThread()
1102 // send dummy expose event, to wake up blocking x11 event loop (XNextEvent)
1103 LOG_DEBUG("X11WindowSystem", "Sending dummy event to wake up renderer thread");
1104 if (NULL == displaySignal)
1106 displaySignal = XOpenDisplay(m_displayEnvironment);
1108 XExposeEvent ev = { Expose, 0, 1, displaySignal, CompositorWindow, 0, 0, 100, 100, 0 };
1109 XLockDisplay(displaySignal);
1110 XSendEvent(displaySignal, CompositorWindow, False, ExposureMask, (XEvent *) &ev);
1111 XUnlockDisplay(displaySignal);
1112 XFlush(displaySignal);
1113 LOG_DEBUG("X11WindowSystem", "Event successfully sent to renderer");
1116 void X11WindowSystem::signalRedrawEvent()
1118 // set flag that redraw is needed
1119 this->m_systemState = REDRAW_STATE;
1120 this->wakeUpRendererThread();
1123 void X11WindowSystem::cleanup()
1125 LOG_DEBUG("X11WindowSystem", "Cleanup");
1126 if (None != CompositorWindow)
1128 Window root = RootWindow(x11Display, DefaultScreen(x11Display));
1129 XCompositeUnredirectSubwindows(x11Display, root, CompositeRedirectManual);
1130 XFixesDestroyRegion(x11Display, x11DamageRegion);
1131 XDestroyWindow(x11Display, CompositorWindow);
1139 if (NULL != displaySignal)
1141 XCloseDisplay(displaySignal);
1144 XCloseDisplay(x11Display);
1145 pthread_mutex_lock(&this->run_lock);
1147 pthread_mutex_unlock(&this->run_lock);
1150 bool X11WindowSystem::init(BaseGraphicSystem<Display*, Window>* base)
1153 X11WindowSystem *renderer = this;
1154 graphicSystem = base;
1155 LOG_INFO("X11WindowSystem", "Initialization");
1156 pthread_mutex_lock(&init_lock);
1157 int status = pthread_create(&renderThread, NULL, X11eventLoopCallback, (void*) renderer);
1160 pthread_mutex_unlock(&init_lock);
1163 mThreadId = renderThread;
1165 pthread_cond_wait(&init_condition, &init_lock);
1166 pthread_mutex_unlock(&init_lock);
1167 LOG_INFO("X11WindowSystem", "Initialization complete success :" << m_success);
1171 bool X11WindowSystem::start()
1174 pthread_mutex_lock(&this->run_lock);
1175 LOG_DEBUG("X11WindowSystem", "Startup");
1176 // let thread actually run
1177 if (m_xerror == false)
1179 this->m_running = true;
1180 pthread_cond_signal(&this->run_condition);
1181 pthread_mutex_unlock(&this->run_lock);
1185 this->m_running = false;
1186 pthread_cond_signal(&this->run_condition);
1187 pthread_mutex_unlock(&this->run_lock);
1193 void X11WindowSystem::stop()
1195 LOG_INFO("X11WindowSystem", "Stopping..");
1196 pthread_mutex_lock(&this->run_lock);
1197 this->m_running = false;
1198 // needed if start was never called, we wake up thread, so it can immediatly finish
1199 this->signalRedrawEvent();
1200 pthread_cond_signal(&this->run_condition);
1201 pthread_mutex_unlock(&this->run_lock);
1202 pthread_join(renderThread, NULL);
1205 void X11WindowSystem::allocatePlatformSurface(Surface* surface)
1207 LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface begin");
1208 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1211 LOG_DEBUG("X11WindowSystem", "creating native surface for new window");
1212 // this surface does not have a native platform surface attached yet!
1213 NewWindow(surface, surface->getNativeContent());
1214 MapWindow(surface->getNativeContent());
1216 LOG_DEBUG("X11WindowSystem", "allocatePlatformSurface end");
1219 void X11WindowSystem::deallocatePlatformSurface(Surface* surface)
1221 LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface begin");
1222 XPlatformSurface* nativeSurface = (XPlatformSurface*)surface->platform;
1225 LOG_DEBUG("X11WindowSystem", "destroyingnative surface");
1226 graphicSystem->getTextureBinder()->destroyClientBuffer(surface);
1228 if (nativeSurface->pixmap)
1230 XFreePixmap(x11Display, nativeSurface->pixmap);
1233 surface->renderPropertyChanged = true;
1234 delete surface->platform;
1235 surface->platform = NULL;
1237 LOG_DEBUG("X11WindowSystem", "deallocatePlatformSurface end");
1240 void X11WindowSystem::doScreenShot(std::string fileName)
1242 takeScreenshot = ScreenshotOfDisplay;
1243 screenShotFile = fileName;
1246 void X11WindowSystem::doScreenShotOfLayer(std::string fileName, const uint id)
1248 takeScreenshot = ScreenshotOfLayer;
1249 screenShotFile = fileName;
1250 screenShotLayerID = id;
1253 void X11WindowSystem::doScreenShotOfSurface(std::string fileName, const uint id, const uint layer_id)
1255 takeScreenshot = ScreenshotOfSurface;
1256 screenShotFile = fileName;
1257 screenShotSurfaceID = id;
1258 screenShotLayerID = layer_id;
1264 * @subsection <X11WindowSystem-MultiTouch> (Multi Touch)
1266 * X11 multi touch is not yet supported by Layer Manager.
1268 * TODO to add support:
1269 * - Move all event management to xi2
1270 * - For multi touch, make sure XInput protocol is > 2.2
1271 * -> Via cmake ==> ?
1272 * -> At runtime ==> http://who-t.blogspot.fr/2011/12/multitouch-in-x-getting-events.html
1273 * - Register for XIDirectTouch. (No plan (yet?) to support XIDependentTouch)
1274 * - Call m_pInputManager->reportTouchEvent() from ManageXInputEvent() to translate screen wide touch coordinates
1275 * into surface wide coordinates
1276 * - Forward the event to the native handle of the surface returned by m_pInputManager->reportTouchEvent()
1279 * + XInput 2.x protocol : ftp://www.x.org/pub/xorg/current/doc/inputproto/XI2proto.txt
1280 * + LWN article : http://lwn.net/Articles/475886/