void eventLoop (void) { XEvent event; struct pollfd ufd; int timeDiff; struct timeval tv; Region tmpRegion; CompDisplay *display = compDisplays; CompScreen *s = display->screens; int timeToNextRedraw = 0; CompWindow *move = 0; int px = 0, py = 0; CompTimeout *t; tmpRegion = XCreateRegion (); if (!tmpRegion) { fprintf (stderr, "%s: Couldn't create region\n", programName); return; } ufd.fd = ConnectionNumber (display->display); ufd.events = POLLIN; for (;;) { if (display->dirtyPluginList) updatePlugins (display); if (restartSignal) { execvp (programName, programArgv); exit (1); } while (XPending (display->display)) { XNextEvent (display->display, &event); /* translate root window */ if (testMode) { Window root, child; switch (event.type) { case ButtonPress: if (!move) { px = event.xbutton.x; py = event.xbutton.y; move = findWindowAt (display, event.xbutton.window, px, py); if (move) { XRaiseWindow (display->display, move->id); continue; } } case ButtonRelease: move = 0; root = translateToRootWindow (display, event.xbutton.window); XTranslateCoordinates (display->display, event.xbutton.root, root, event.xbutton.x_root, event.xbutton.y_root, &event.xbutton.x_root, &event.xbutton.y_root, &child); event.xbutton.root = root; break; case KeyPress: case KeyRelease: root = translateToRootWindow (display, event.xkey.window); XTranslateCoordinates (display->display, event.xkey.root, root, event.xkey.x_root, event.xkey.y_root, &event.xkey.x_root, &event.xkey.y_root, &child); event.xkey.root = root; break; case MotionNotify: if (move) { XMoveWindow (display->display, move->id, move->attrib.x + event.xbutton.x - px, move->attrib.y + event.xbutton.y - py); px = event.xbutton.x; py = event.xbutton.y; continue; } root = translateToRootWindow (display, event.xmotion.window); XTranslateCoordinates (display->display, event.xmotion.root, root, event.xmotion.x_root, event.xmotion.y_root, &event.xmotion.x_root, &event.xmotion.y_root, &child); event.xmotion.root = root; default: break; } } /* add virtual modifiers */ switch (event.type) { case ButtonPress: event.xbutton.state |= CompPressMask; event.xbutton.state = realToVirtualModMask (display, event.xbutton.state); break; case ButtonRelease: event.xbutton.state |= CompReleaseMask; event.xbutton.state = realToVirtualModMask (display, event.xbutton.state); break; case KeyPress: event.xkey.state |= CompPressMask; event.xkey.state = realToVirtualModMask (display, event.xkey.state); break; case KeyRelease: event.xkey.state |= CompReleaseMask; event.xkey.state = realToVirtualModMask (display, event.xkey.state); break; case MotionNotify: event.xmotion.state = realToVirtualModMask (display, event.xmotion.state); break; default: break; } (*display->handleEvent) (display, &event); } if (s->allDamaged || REGION_NOT_EMPTY (s->damage)) { if (timeToNextRedraw == 0) { /* wait for X drawing requests to finish glXWaitX (); */ gettimeofday (&tv, 0); timeDiff = TIMEVALDIFF (&tv, &s->lastRedraw); (*s->preparePaintScreen) (s, timeDiff); if (s->allDamaged) { EMPTY_REGION (s->damage); s->allDamaged = 0; (*s->paintScreen) (s, &defaultScreenPaintAttrib, &defaultWindowPaintAttrib, &s->region, PAINT_SCREEN_REGION_MASK | PAINT_SCREEN_FULL_MASK); glXSwapBuffers (s->display->display, s->root); } else { XIntersectRegion (s->damage, &s->region, tmpRegion); EMPTY_REGION (s->damage); if ((*s->paintScreen) (s, &defaultScreenPaintAttrib, &defaultWindowPaintAttrib, tmpRegion, PAINT_SCREEN_REGION_MASK)) { BoxPtr pBox; int nBox, y; glEnable (GL_SCISSOR_TEST); glDrawBuffer (GL_FRONT); pBox = tmpRegion->rects; nBox = tmpRegion->numRects; while (nBox--) { y = s->height - pBox->y2; glBitmap (0, 0, 0, 0, pBox->x1 - s->rasterX, y - s->rasterY, NULL); s->rasterX = pBox->x1; s->rasterY = y; glScissor (pBox->x1, y, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1); glCopyPixels (pBox->x1, y, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1, GL_COLOR); pBox++; } glDrawBuffer (GL_BACK); glDisable (GL_SCISSOR_TEST); glFlush (); } else { (*s->paintScreen) (s, &defaultScreenPaintAttrib, &defaultWindowPaintAttrib, &s->region, PAINT_SCREEN_FULL_MASK); glXSwapBuffers (s->display->display, s->root); } } s->lastRedraw = tv; (*s->donePaintScreen) (s); /* remove destroyed windows */ while (s->pendingDestroys) { CompWindow *w; for (w = s->windows; w; w = w->next) { if (w->destroyed) { addWindowDamage (w); removeWindow (w); break; } } s->pendingDestroys--; } } timeToNextRedraw = getTimeToNextRedraw (s, &s->lastRedraw); if (timeToNextRedraw) timeToNextRedraw = poll (&ufd, 1, timeToNextRedraw); } else { if (timeouts) { if (timeouts->left > 0) poll (&ufd, 1, timeouts->left); gettimeofday (&tv, 0); timeDiff = TIMEVALDIFF (&tv, &lastTimeout); for (t = timeouts; t; t = t->next) t->left -= timeDiff; while (timeouts && timeouts->left <= 0) { t = timeouts; if ((*t->callBack) (t->closure)) { timeouts = t->next; addTimeout (t); } else { timeouts = t->next; free (t); } } s->lastRedraw = lastTimeout = tv; } else { poll (&ufd, 1, 1000); gettimeofday (&s->lastRedraw, 0); } /* just redraw immediately */ timeToNextRedraw = 0; } } }
/* This function currently always performs occlusion detection to minimize paint regions. OpenGL precision requirements are no good enough to guarantee that the results from using occlusion detection is the same as without. It's likely not possible to see any difference with most hardware but occlusion detection in the transformed screen case should be made optional for those who do see a difference. */ static void paintOutputRegion (CompScreen *screen, const CompTransform *transform, Region region, CompOutput *output, unsigned int mask) { static Region tmpRegion = NULL; CompWindow *w; CompCursor *c; int count, windowMask, odMask, i; CompWindow *fullscreenWindow = NULL; CompWalker walk; Bool status; Bool withOffset = FALSE; CompTransform vTransform; int offX, offY; Region clip = region; int dontcare; if (!tmpRegion) { tmpRegion = XCreateRegion (); if (!tmpRegion) return; } if (mask & PAINT_SCREEN_TRANSFORMED_MASK) { windowMask = PAINT_WINDOW_ON_TRANSFORMED_SCREEN_MASK; count = 1; } else { windowMask = 0; count = 0; } XSubtractRegion (region, &emptyRegion, tmpRegion); (*screen->initWindowWalker) (screen, &walk); if (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK)) { /* detect occlusions */ for (w = (*walk.last) (screen); w; w = (*walk.prev) (w)) { if (w->destroyed) continue; if (!w->shaded) { if (w->attrib.map_state != IsViewable || !w->damaged) continue; } /* copy region */ XSubtractRegion (tmpRegion, &emptyRegion, w->clip); odMask = PAINT_WINDOW_OCCLUSION_DETECTION_MASK; if ((screen->windowOffsetX != 0 || screen->windowOffsetY != 0) && !windowOnAllViewports (w)) { withOffset = TRUE; getWindowMovementForOffset (w, screen->windowOffsetX, screen->windowOffsetY, &offX, &offY); vTransform = *transform; matrixTranslate (&vTransform, offX, offY, 0); XOffsetRegion (w->clip, -offX, -offY); odMask |= PAINT_WINDOW_WITH_OFFSET_MASK; status = (*screen->paintWindow) (w, &w->paint, &vTransform, tmpRegion, odMask); } else { withOffset = FALSE; status = (*screen->paintWindow) (w, &w->paint, transform, tmpRegion, odMask); } if (status) { if (withOffset) { XOffsetRegion (w->region, offX, offY); XSubtractRegion (tmpRegion, w->region, tmpRegion); XOffsetRegion (w->region, -offX, -offY); } else XSubtractRegion (tmpRegion, w->region, tmpRegion); /* unredirect top most fullscreen windows. */ /* if the fullscreen window is mate-screensaver and we're on nvidia we want to always unredirect even if this option is disabled to work around LP #160264 */ if (count == 0 && (screen->opt[COMP_SCREEN_OPTION_UNREDIRECT_FS].value.b || (w->resName && !strcmp(w->resName, "mate-screensaver") && XQueryExtension (screen->display->display, "NV-GLX", &dontcare, &dontcare, &dontcare)))) { if (XEqualRegion (w->region, &screen->region) && !REGION_NOT_EMPTY (tmpRegion)) { fullscreenWindow = w; } else { for (i = 0; i < screen->nOutputDev; i++) if (XEqualRegion (w->region, &screen->outputDev[i].region)) fullscreenWindow = w; } } } if (!w->invisible) count++; } } if (fullscreenWindow) unredirectWindow (fullscreenWindow); if (!(mask & PAINT_SCREEN_NO_BACKGROUND_MASK)) paintBackground (screen, tmpRegion, (mask & PAINT_SCREEN_TRANSFORMED_MASK)); /* paint all windows from bottom to top */ for (w = (*walk.first) (screen); w; w = (*walk.next) (w)) { if (w->destroyed) continue; if (w == fullscreenWindow) continue; if (!w->shaded) { if (w->attrib.map_state != IsViewable || !w->damaged) continue; } if (!(mask & PAINT_SCREEN_NO_OCCLUSION_DETECTION_MASK)) clip = w->clip; if ((screen->windowOffsetX != 0 || screen->windowOffsetY != 0) && !windowOnAllViewports (w)) { getWindowMovementForOffset (w, screen->windowOffsetX, screen->windowOffsetY, &offX, &offY); vTransform = *transform; matrixTranslate (&vTransform, offX, offY, 0); (*screen->paintWindow) (w, &w->paint, &vTransform, clip, windowMask | PAINT_WINDOW_WITH_OFFSET_MASK); } else { (*screen->paintWindow) (w, &w->paint, transform, clip, windowMask); } } if (walk.fini) (*walk.fini) (screen, &walk); /* paint cursors */ for (c = screen->cursors; c; c = c->next) (*screen->paintCursor) (c, transform, tmpRegion, 0); }