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;
	}
    }
}
Ejemplo n.º 2
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);
}