719 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			719 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Screen routines for generic rootless X server
 | |
|  */
 | |
| /*
 | |
|  * Copyright (c) 2001 Greg Parker. All Rights Reserved.
 | |
|  * Copyright (c) 2002-2003 Torrey T. Lyons. All Rights Reserved.
 | |
|  * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a
 | |
|  * copy of this software and associated documentation files (the "Software"),
 | |
|  * to deal in the Software without restriction, including without limitation
 | |
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, subject to the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be included in
 | |
|  * all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 | |
|  * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
|  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
|  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | |
|  * DEALINGS IN THE SOFTWARE.
 | |
|  *
 | |
|  * Except as contained in this notice, the name(s) of the above copyright
 | |
|  * holders shall not be used in advertising or otherwise to promote the sale,
 | |
|  * use or other dealings in this Software without prior written authorization.
 | |
|  */
 | |
| 
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include "mi.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "gcstruct.h"
 | |
| #include "pixmapstr.h"
 | |
| #include "windowstr.h"
 | |
| #include "propertyst.h"
 | |
| #include "mivalidate.h"
 | |
| #include "picturestr.h"
 | |
| #include "colormapst.h"
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include "rootlessCommon.h"
 | |
| #include "rootlessWindow.h"
 | |
| 
 | |
| /* In milliseconds */
 | |
| #ifndef ROOTLESS_REDISPLAY_DELAY
 | |
| #define ROOTLESS_REDISPLAY_DELAY 10
 | |
| #endif
 | |
| 
 | |
| extern int RootlessMiValidateTree(WindowPtr pRoot, WindowPtr pChild,
 | |
|                                   VTKind kind);
 | |
| extern Bool RootlessCreateGC(GCPtr pGC);
 | |
| 
 | |
| // Initialize globals
 | |
| DevPrivateKey rootlessGCPrivateKey = &rootlessGCPrivateKey;
 | |
| DevPrivateKey rootlessScreenPrivateKey = &rootlessScreenPrivateKey;
 | |
| DevPrivateKey rootlessWindowPrivateKey = &rootlessWindowPrivateKey;
 | |
| DevPrivateKey rootlessWindowOldPixmapPrivateKey = &rootlessWindowOldPixmapPrivateKey;
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessUpdateScreenPixmap
 | |
|  *  miCreateScreenResources does not like a null framebuffer pointer,
 | |
|  *  it leaves the screen pixmap with an uninitialized data pointer.
 | |
|  *  Thus, rootless implementations typically set the framebuffer width
 | |
|  *  to zero so that miCreateScreenResources does not allocate a screen
 | |
|  *  pixmap for us. We allocate our own screen pixmap here since we need
 | |
|  *  the screen pixmap to be valid (e.g. CopyArea from the root window).
 | |
|  */
 | |
| void
 | |
| RootlessUpdateScreenPixmap(ScreenPtr pScreen)
 | |
| {
 | |
|     RootlessScreenRec *s = SCREENREC(pScreen);
 | |
|     PixmapPtr pPix;
 | |
|     unsigned int rowbytes;
 | |
| 
 | |
|     pPix = (*pScreen->GetScreenPixmap)(pScreen);
 | |
|     if (pPix == NULL) {
 | |
|         pPix = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0);
 | |
|         (*pScreen->SetScreenPixmap)(pPix);
 | |
|     }
 | |
| 
 | |
|     rowbytes = PixmapBytePad(pScreen->width, pScreen->rootDepth);
 | |
| 
 | |
|     if (s->pixmap_data_size < rowbytes) {
 | |
|         if (s->pixmap_data != NULL)
 | |
|             xfree(s->pixmap_data);
 | |
| 
 | |
|         s->pixmap_data_size = rowbytes;
 | |
|         s->pixmap_data = xalloc(s->pixmap_data_size);
 | |
|         if (s->pixmap_data == NULL)
 | |
|             return;
 | |
| 
 | |
|         memset(s->pixmap_data, 0xFF, s->pixmap_data_size);
 | |
| 
 | |
|         pScreen->ModifyPixmapHeader(pPix, pScreen->width, pScreen->height,
 | |
|                                     pScreen->rootDepth,
 | |
|                                     BitsPerPixel(pScreen->rootDepth),
 | |
|                                     0, s->pixmap_data);
 | |
|         /* ModifyPixmapHeader ignores zero arguments, so install rowbytes
 | |
|            by hand. */
 | |
|         pPix->devKind = 0;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessCreateScreenResources
 | |
|  *  Rootless implementations typically set a null framebuffer pointer, which
 | |
|  *  causes problems with miCreateScreenResources. We fix things up here.
 | |
|  */
 | |
| static Bool
 | |
| RootlessCreateScreenResources(ScreenPtr pScreen)
 | |
| {
 | |
|     Bool ret = TRUE;
 | |
| 
 | |
|     SCREEN_UNWRAP(pScreen, CreateScreenResources);
 | |
| 
 | |
|     if (pScreen->CreateScreenResources != NULL)
 | |
|         ret = (*pScreen->CreateScreenResources)(pScreen);
 | |
| 
 | |
|     SCREEN_WRAP(pScreen, CreateScreenResources);
 | |
| 
 | |
|     if (!ret)
 | |
|         return ret;
 | |
| 
 | |
|     /* Make sure we have a valid screen pixmap. */
 | |
| 
 | |
|     RootlessUpdateScreenPixmap(pScreen);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| 
 | |
| static Bool
 | |
| RootlessCloseScreen(int i, ScreenPtr pScreen)
 | |
| {
 | |
|     RootlessScreenRec *s;
 | |
| 
 | |
|     s = SCREENREC(pScreen);
 | |
| 
 | |
|     // fixme unwrap everything that was wrapped?
 | |
|     pScreen->CloseScreen = s->CloseScreen;
 | |
| 
 | |
|     if (s->pixmap_data != NULL) {
 | |
|         xfree (s->pixmap_data);
 | |
|         s->pixmap_data = NULL;
 | |
|         s->pixmap_data_size = 0;
 | |
|     }
 | |
| 
 | |
|     xfree(s);
 | |
|     return pScreen->CloseScreen(i, pScreen);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| RootlessGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
 | |
|                  unsigned int format, unsigned long planeMask, char *pdstLine)
 | |
| {
 | |
|     ScreenPtr pScreen = pDrawable->pScreen;
 | |
|     SCREEN_UNWRAP(pScreen, GetImage);
 | |
| 
 | |
|     if (pDrawable->type == DRAWABLE_WINDOW) {
 | |
|         int x0, y0, x1, y1;
 | |
|         RootlessWindowRec *winRec;
 | |
| 
 | |
|         // Many apps use GetImage to sync with the visible frame buffer
 | |
|         // FIXME: entire screen or just window or all screens?
 | |
|         RootlessRedisplayScreen(pScreen);
 | |
| 
 | |
|         // RedisplayScreen stops drawing, so we need to start it again
 | |
|         RootlessStartDrawing((WindowPtr)pDrawable);
 | |
| 
 | |
|         /* Check that we have some place to read from. */
 | |
|         winRec = WINREC(TopLevelParent((WindowPtr) pDrawable));
 | |
|         if (winRec == NULL)
 | |
|             goto out;
 | |
| 
 | |
|         /* Clip to top-level window bounds. */
 | |
|         /* FIXME: fbGetImage uses the width parameter to calculate the
 | |
|            stride of the destination pixmap. If w is clipped, the data
 | |
|            returned will be garbage, although we will not crash. */
 | |
| 
 | |
|         x0 = pDrawable->x + sx;
 | |
|         y0 = pDrawable->y + sy;
 | |
|         x1 = x0 + w;
 | |
|         y1 = y0 + h;
 | |
| 
 | |
|         x0 = MAX (x0, winRec->x);
 | |
|         y0 = MAX (y0, winRec->y);
 | |
|         x1 = MIN (x1, winRec->x + winRec->width);
 | |
|         y1 = MIN (y1, winRec->y + winRec->height);
 | |
| 
 | |
|         sx = x0 - pDrawable->x;
 | |
|         sy = y0 - pDrawable->y;
 | |
|         w = x1 - x0;
 | |
|         h = y1 - y0;
 | |
| 
 | |
|         if (w <= 0 || h <= 0)
 | |
|             goto out;
 | |
|     }
 | |
| 
 | |
|     pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine);
 | |
| 
 | |
| out:
 | |
|     SCREEN_WRAP(pScreen, GetImage);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessSourceValidate
 | |
|  *  CopyArea and CopyPlane use a GC tied to the destination drawable.
 | |
|  *  StartDrawing/StopDrawing wrappers won't be called if source is
 | |
|  *  a visible window but the destination isn't. So, we call StartDrawing
 | |
|  *  here and leave StopDrawing for the block handler.
 | |
|  */
 | |
| static void
 | |
| RootlessSourceValidate(DrawablePtr pDrawable, int x, int y, int w, int h)
 | |
| {
 | |
|     SCREEN_UNWRAP(pDrawable->pScreen, SourceValidate);
 | |
|     if (pDrawable->type == DRAWABLE_WINDOW) {
 | |
|         WindowPtr pWin = (WindowPtr)pDrawable;
 | |
|         RootlessStartDrawing(pWin);
 | |
|     }
 | |
|     if (pDrawable->pScreen->SourceValidate) {
 | |
|         pDrawable->pScreen->SourceValidate(pDrawable, x, y, w, h);
 | |
|     }
 | |
|     SCREEN_WRAP(pDrawable->pScreen, SourceValidate);
 | |
| }
 | |
| 
 | |
| #ifdef RENDER
 | |
| 
 | |
| static void
 | |
| RootlessComposite(CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
 | |
|                   INT16 xSrc, INT16 ySrc, INT16  xMask, INT16  yMask,
 | |
|                   INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
 | |
| {
 | |
|     ScreenPtr pScreen = pDst->pDrawable->pScreen;
 | |
|     PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
|     WindowPtr srcWin, dstWin, maskWin = NULL;
 | |
| 
 | |
|     if (pMask) {                        // pMask can be NULL
 | |
|         maskWin = (pMask->pDrawable->type == DRAWABLE_WINDOW) ?
 | |
|                   (WindowPtr)pMask->pDrawable :  NULL;
 | |
|     }
 | |
|     srcWin  = (pSrc->pDrawable->type  == DRAWABLE_WINDOW) ?
 | |
|               (WindowPtr)pSrc->pDrawable  :  NULL;
 | |
|     dstWin  = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
 | |
|               (WindowPtr)pDst->pDrawable  :  NULL;
 | |
| 
 | |
|     // SCREEN_UNWRAP(ps, Composite);
 | |
|     ps->Composite = SCREENREC(pScreen)->Composite;
 | |
| 
 | |
|     if (srcWin  && IsFramedWindow(srcWin))
 | |
|         RootlessStartDrawing(srcWin);
 | |
|     if (maskWin && IsFramedWindow(maskWin))
 | |
|         RootlessStartDrawing(maskWin);
 | |
|     if (dstWin  && IsFramedWindow(dstWin))
 | |
|         RootlessStartDrawing(dstWin);
 | |
| 
 | |
|     ps->Composite(op, pSrc, pMask, pDst,
 | |
|                   xSrc, ySrc, xMask, yMask,
 | |
|                   xDst, yDst, width, height);
 | |
| 
 | |
|     if (dstWin  && IsFramedWindow(dstWin)) {
 | |
|         RootlessDamageRect(dstWin, xDst, yDst, width, height);
 | |
|     }
 | |
| 
 | |
|     ps->Composite = RootlessComposite;
 | |
|     // SCREEN_WRAP(ps, Composite);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| RootlessGlyphs(CARD8 op, PicturePtr pSrc, PicturePtr pDst,
 | |
|                PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc,
 | |
|                int nlist, GlyphListPtr list, GlyphPtr *glyphs)
 | |
| {
 | |
|     ScreenPtr pScreen = pDst->pDrawable->pScreen;
 | |
|     PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
|     int x, y;
 | |
|     int n;
 | |
|     GlyphPtr glyph;
 | |
|     WindowPtr srcWin, dstWin;
 | |
| 
 | |
|     srcWin = (pSrc->pDrawable->type == DRAWABLE_WINDOW) ?
 | |
|              (WindowPtr)pSrc->pDrawable  :  NULL;
 | |
|     dstWin = (pDst->pDrawable->type == DRAWABLE_WINDOW) ?
 | |
|              (WindowPtr)pDst->pDrawable  :  NULL;
 | |
| 
 | |
|     if (srcWin && IsFramedWindow(srcWin)) RootlessStartDrawing(srcWin);
 | |
|     if (dstWin && IsFramedWindow(dstWin)) RootlessStartDrawing(dstWin);
 | |
| 
 | |
|     //SCREEN_UNWRAP(ps, Glyphs);
 | |
|     ps->Glyphs = SCREENREC(pScreen)->Glyphs;
 | |
|     ps->Glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
 | |
|     ps->Glyphs = RootlessGlyphs;
 | |
|     //SCREEN_WRAP(ps, Glyphs);
 | |
| 
 | |
|     if (dstWin && IsFramedWindow(dstWin)) {
 | |
|         x = xSrc;
 | |
|         y = ySrc;
 | |
| 
 | |
|         while (nlist--) {
 | |
|             x += list->xOff;
 | |
|             y += list->yOff;
 | |
|             n = list->len;
 | |
| 
 | |
|             /* Calling DamageRect for the bounding box of each glyph is
 | |
|                inefficient. So compute the union of all glyphs in a list
 | |
|                and damage that. */
 | |
| 
 | |
|             if (n > 0) {
 | |
|                 BoxRec box;
 | |
| 
 | |
|                 glyph = *glyphs++;
 | |
| 
 | |
|                 box.x1 = x - glyph->info.x;
 | |
|                 box.y1 = y - glyph->info.y;
 | |
|                 box.x2 = box.x1 + glyph->info.width;
 | |
|                 box.y2 = box.y2 + glyph->info.height;
 | |
| 
 | |
|                 x += glyph->info.xOff;
 | |
|                 y += glyph->info.yOff;
 | |
| 
 | |
|                 while (--n > 0) {
 | |
|                     short x1, y1, x2, y2;
 | |
| 
 | |
|                     glyph = *glyphs++;
 | |
| 
 | |
|                     x1 = x - glyph->info.x;
 | |
|                     y1 = y - glyph->info.y;
 | |
|                     x2 = x1 + glyph->info.width;
 | |
|                     y2 = y1 + glyph->info.height;
 | |
| 
 | |
|                     box.x1 = MAX (box.x1, x1);
 | |
|                     box.y1 = MAX (box.y1, y1);
 | |
|                     box.x2 = MAX (box.x2, x2);
 | |
|                     box.y2 = MAX (box.y2, y2);
 | |
| 
 | |
|                     x += glyph->info.xOff;
 | |
|                     y += glyph->info.yOff;
 | |
|                 }
 | |
| 
 | |
|                 RootlessDamageBox(dstWin, &box);
 | |
|             }
 | |
|             list++;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif // RENDER
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessValidateTree
 | |
|  *  ValidateTree is modified in two ways:
 | |
|  *   - top-level windows don't clip each other
 | |
|  *   - windows aren't clipped against root.
 | |
|  *  These only matter when validating from the root.
 | |
|  */
 | |
| static int
 | |
| RootlessValidateTree(WindowPtr pParent, WindowPtr pChild, VTKind kind)
 | |
| {
 | |
|     int result;
 | |
|     RegionRec saveRoot;
 | |
|     ScreenPtr pScreen = pParent->drawable.pScreen;
 | |
| 
 | |
|     SCREEN_UNWRAP(pScreen, ValidateTree);
 | |
|     RL_DEBUG_MSG("VALIDATETREE start ");
 | |
| 
 | |
|     // Use our custom version to validate from root
 | |
|     if (IsRoot(pParent)) {
 | |
|         RL_DEBUG_MSG("custom ");
 | |
|         result = RootlessMiValidateTree(pParent, pChild, kind);
 | |
|     } else {
 | |
|         HUGE_ROOT(pParent);
 | |
|         result = pScreen->ValidateTree(pParent, pChild, kind);
 | |
|         NORMAL_ROOT(pParent);
 | |
|     }
 | |
| 
 | |
|     SCREEN_WRAP(pScreen, ValidateTree);
 | |
|     RL_DEBUG_MSG("VALIDATETREE end\n");
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessMarkOverlappedWindows
 | |
|  *  MarkOverlappedWindows is modified to ignore overlapping
 | |
|  *  top-level windows.
 | |
|  */
 | |
| static Bool
 | |
| RootlessMarkOverlappedWindows(WindowPtr pWin, WindowPtr pFirst,
 | |
|                               WindowPtr *ppLayerWin)
 | |
| {
 | |
|     RegionRec saveRoot;
 | |
|     Bool result;
 | |
|     ScreenPtr pScreen = pWin->drawable.pScreen;
 | |
|     SCREEN_UNWRAP(pScreen, MarkOverlappedWindows);
 | |
|     RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS start ");
 | |
| 
 | |
|     HUGE_ROOT(pWin);
 | |
|     if (IsRoot(pWin)) {
 | |
|         // root - mark nothing
 | |
|         RL_DEBUG_MSG("is root not marking ");
 | |
|         result = FALSE;
 | |
|     }
 | |
|     else if (! IsTopLevel(pWin)) {
 | |
|         // not top-level window - mark normally
 | |
|         result = pScreen->MarkOverlappedWindows(pWin, pFirst, ppLayerWin);
 | |
|     }
 | |
|     else {
 | |
|         //top-level window - mark children ONLY - NO overlaps with sibs (?)
 | |
|         // This code copied from miMarkOverlappedWindows()
 | |
| 
 | |
|         register WindowPtr pChild;
 | |
|         Bool anyMarked = FALSE;
 | |
|         void (* MarkWindow)() = pScreen->MarkWindow;
 | |
| 
 | |
|         RL_DEBUG_MSG("is top level! ");
 | |
|         /* single layered systems are easy */
 | |
|         if (ppLayerWin) *ppLayerWin = pWin;
 | |
| 
 | |
|         if (pWin == pFirst) {
 | |
|             /* Blindly mark pWin and all of its inferiors.   This is a slight
 | |
|              * overkill if there are mapped windows that outside pWin's border,
 | |
|              * but it's better than wasting time on RectIn checks.
 | |
|              */
 | |
|             pChild = pWin;
 | |
|             while (1) {
 | |
|                 if (pChild->viewable) {
 | |
|                     if (REGION_BROKEN (pScreen, &pChild->winSize))
 | |
|                         SetWinSize (pChild);
 | |
|                     if (REGION_BROKEN (pScreen, &pChild->borderSize))
 | |
|                         SetBorderSize (pChild);
 | |
|                     (* MarkWindow)(pChild);
 | |
|                     if (pChild->firstChild) {
 | |
|                         pChild = pChild->firstChild;
 | |
|                         continue;
 | |
|                     }
 | |
|                 }
 | |
|                 while (!pChild->nextSib && (pChild != pWin))
 | |
|                     pChild = pChild->parent;
 | |
|                 if (pChild == pWin)
 | |
|                     break;
 | |
|                 pChild = pChild->nextSib;
 | |
|             }
 | |
|             anyMarked = TRUE;
 | |
|             pFirst = pFirst->nextSib;
 | |
|         }
 | |
|         if (anyMarked)
 | |
|             (* MarkWindow)(pWin->parent);
 | |
|         result = anyMarked;
 | |
|     }
 | |
|     NORMAL_ROOT(pWin);
 | |
|     SCREEN_WRAP(pScreen, MarkOverlappedWindows);
 | |
|     RL_DEBUG_MSG("MARKOVERLAPPEDWINDOWS end\n");
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| ColormapPtr
 | |
| RootlessGetColormap (ScreenPtr pScreen)
 | |
| {
 | |
|   RootlessScreenRec *s = SCREENREC (pScreen);
 | |
| 
 | |
|   return s->colormap;
 | |
| }
 | |
| 
 | |
| static void
 | |
| RootlessInstallColormap (ColormapPtr pMap)
 | |
| {
 | |
|   ScreenPtr pScreen = pMap->pScreen;
 | |
|   RootlessScreenRec *s = SCREENREC (pScreen);
 | |
| 
 | |
|   SCREEN_UNWRAP(pScreen, InstallColormap);
 | |
| 
 | |
|   if (s->colormap != pMap) {
 | |
|     s->colormap = pMap;
 | |
|     s->colormap_changed = TRUE;
 | |
|     RootlessQueueRedisplay (pScreen);
 | |
|   }
 | |
| 
 | |
|   pScreen->InstallColormap (pMap);
 | |
| 
 | |
|   SCREEN_WRAP (pScreen, InstallColormap);
 | |
| }
 | |
| 
 | |
| static void
 | |
| RootlessUninstallColormap (ColormapPtr pMap)
 | |
| {
 | |
|   ScreenPtr pScreen = pMap->pScreen;
 | |
|   RootlessScreenRec *s = SCREENREC (pScreen);
 | |
| 
 | |
|   SCREEN_UNWRAP(pScreen, UninstallColormap);
 | |
| 
 | |
|   if (s->colormap == pMap)
 | |
|     s->colormap = NULL;
 | |
| 
 | |
|   pScreen->UninstallColormap (pMap);
 | |
| 
 | |
|   SCREEN_WRAP(pScreen, UninstallColormap);
 | |
| }
 | |
| 
 | |
| static void
 | |
| RootlessStoreColors (ColormapPtr pMap, int ndef, xColorItem *pdef)
 | |
| {
 | |
|   ScreenPtr pScreen = pMap->pScreen;
 | |
|   RootlessScreenRec *s = SCREENREC (pScreen);
 | |
| 
 | |
|   SCREEN_UNWRAP(pScreen, StoreColors);
 | |
| 
 | |
|   if (s->colormap == pMap && ndef > 0) {
 | |
|     s->colormap_changed = TRUE;
 | |
|     RootlessQueueRedisplay (pScreen);
 | |
|   }
 | |
| 
 | |
|   pScreen->StoreColors (pMap, ndef, pdef);
 | |
| 
 | |
|   SCREEN_WRAP(pScreen, StoreColors);
 | |
| }
 | |
| 
 | |
| 
 | |
| static CARD32
 | |
| RootlessRedisplayCallback(OsTimerPtr timer, CARD32 time, void *arg)
 | |
| {
 | |
|     RootlessScreenRec *screenRec = arg;
 | |
| 
 | |
|     if (!screenRec->redisplay_queued) {
 | |
|         /* No update needed. Stop the timer. */
 | |
| 
 | |
|         screenRec->redisplay_timer_set = FALSE;
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     screenRec->redisplay_queued = FALSE;
 | |
| 
 | |
|     /* Mark that we should redisplay before waiting for I/O next time */
 | |
|     screenRec->redisplay_expired = TRUE;
 | |
| 
 | |
|     /* Reinstall the timer immediately, so we get as close to our
 | |
|        redisplay interval as possible. */
 | |
| 
 | |
|     return ROOTLESS_REDISPLAY_DELAY;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessQueueRedisplay
 | |
|  *  Queue a redisplay after a timer delay to ensure we do not redisplay
 | |
|  *  too frequently.
 | |
|  */
 | |
| void
 | |
| RootlessQueueRedisplay(ScreenPtr pScreen)
 | |
| {
 | |
|     RootlessScreenRec *screenRec = SCREENREC(pScreen);
 | |
| 
 | |
|     screenRec->redisplay_queued = TRUE;
 | |
| 
 | |
|     if (screenRec->redisplay_timer_set)
 | |
|         return;
 | |
| 
 | |
|     screenRec->redisplay_timer = TimerSet(screenRec->redisplay_timer,
 | |
|                                           0, ROOTLESS_REDISPLAY_DELAY,
 | |
|                                           RootlessRedisplayCallback,
 | |
|                                           screenRec);
 | |
|     screenRec->redisplay_timer_set = TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessBlockHandler
 | |
|  *  If the redisplay timer has expired, flush drawing before blocking
 | |
|  *  on select().
 | |
|  */
 | |
| static void
 | |
| RootlessBlockHandler(pointer pbdata, OSTimePtr pTimeout, pointer pReadmask)
 | |
| {
 | |
|     ScreenPtr pScreen = pbdata;
 | |
|     RootlessScreenRec *screenRec = SCREENREC(pScreen);
 | |
| 
 | |
|     if (screenRec->redisplay_expired) {
 | |
|         screenRec->redisplay_expired = FALSE;
 | |
| 
 | |
|         RootlessRedisplayScreen(pScreen);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| RootlessWakeupHandler(pointer data, int i, pointer LastSelectMask)
 | |
| {
 | |
|     // nothing here
 | |
| }
 | |
| 
 | |
| 
 | |
| static Bool
 | |
| RootlessAllocatePrivates(ScreenPtr pScreen)
 | |
| {
 | |
|     RootlessScreenRec *s;
 | |
| 
 | |
|     // no allocation needed for screen privates
 | |
|     if (!dixRequestPrivate(rootlessGCPrivateKey, sizeof(RootlessGCRec)))
 | |
|         return FALSE;
 | |
| 
 | |
|     s = xalloc(sizeof(RootlessScreenRec));
 | |
|     if (! s) return FALSE;
 | |
|     SETSCREENREC(pScreen, s);
 | |
| 
 | |
|     s->pixmap_data = NULL;
 | |
|     s->pixmap_data_size = 0;
 | |
| 
 | |
|     s->redisplay_timer = NULL;
 | |
|     s->redisplay_timer_set = FALSE;
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| RootlessWrap(ScreenPtr pScreen)
 | |
| {
 | |
|     RootlessScreenRec *s = SCREENREC(pScreen);
 | |
| 
 | |
| #define WRAP(a) \
 | |
|     if (pScreen->a) { \
 | |
|         s->a = pScreen->a; \
 | |
|     } else { \
 | |
|         RL_DEBUG_MSG("null screen fn " #a "\n"); \
 | |
|         s->a = NULL; \
 | |
|     } \
 | |
|     pScreen->a = Rootless##a
 | |
| 
 | |
|     WRAP(CreateScreenResources);
 | |
|     WRAP(CloseScreen);
 | |
|     WRAP(CreateGC);
 | |
|     WRAP(CopyWindow);
 | |
|     WRAP(GetImage);
 | |
|     WRAP(SourceValidate);
 | |
|     WRAP(CreateWindow);
 | |
|     WRAP(DestroyWindow);
 | |
|     WRAP(RealizeWindow);
 | |
|     WRAP(UnrealizeWindow);
 | |
|     WRAP(MoveWindow);
 | |
|     WRAP(PositionWindow);
 | |
|     WRAP(ResizeWindow);
 | |
|     WRAP(RestackWindow);
 | |
|     WRAP(ReparentWindow);
 | |
|     WRAP(ChangeBorderWidth);
 | |
|     WRAP(MarkOverlappedWindows);
 | |
|     WRAP(ValidateTree);
 | |
|     WRAP(ChangeWindowAttributes);
 | |
|     WRAP(InstallColormap);
 | |
|     WRAP(UninstallColormap);
 | |
|     WRAP(StoreColors);
 | |
| 
 | |
| #ifdef SHAPE
 | |
|     WRAP(SetShape);
 | |
| #endif
 | |
| 
 | |
| #ifdef RENDER
 | |
|     {
 | |
|         // Composite and Glyphs don't use normal screen wrapping
 | |
|         PictureScreenPtr ps = GetPictureScreen(pScreen);
 | |
|         s->Composite = ps->Composite;
 | |
|         ps->Composite = RootlessComposite;
 | |
|         s->Glyphs = ps->Glyphs;
 | |
|         ps->Glyphs = RootlessGlyphs;
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     // WRAP(ClearToBackground); fixme put this back? useful for shaped wins?
 | |
| 
 | |
| #undef WRAP
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * RootlessInit
 | |
|  *  Called by the rootless implementation to initialize the rootless layer.
 | |
|  *  Rootless wraps lots of stuff and needs a bunch of devPrivates.
 | |
|  */
 | |
| Bool RootlessInit(ScreenPtr pScreen, RootlessFrameProcsPtr procs)
 | |
| {
 | |
|     RootlessScreenRec *s;
 | |
| 
 | |
|     if (!RootlessAllocatePrivates(pScreen))
 | |
|         return FALSE;
 | |
| 
 | |
|     s = SCREENREC(pScreen);
 | |
| 
 | |
|     s->imp = procs;
 | |
|     s->colormap = NULL;
 | |
|     s->redisplay_expired = FALSE;
 | |
| 
 | |
|     RootlessWrap(pScreen);
 | |
| 
 | |
|     if (!RegisterBlockAndWakeupHandlers(RootlessBlockHandler,
 | |
|                                         RootlessWakeupHandler,
 | |
|                                         (pointer) pScreen))
 | |
|     {
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 |