/* * Copyright © 2000 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include #include #include "scrnintstr.h" #include "windowstr.h" #include "dixfontstr.h" #include "mi.h" #include "regionstr.h" #include "globals.h" #include "gcstruct.h" #include "shadow.h" static DevPrivateKeyRec shadowScrPrivateKeyRec; #define shadowScrPrivateKey (&shadowScrPrivateKeyRec) #define wrap(priv, real, mem) {\ priv->mem = real->mem; \ real->mem = shadow##mem; \ } #define unwrap(priv, real, mem) {\ real->mem = priv->mem; \ } static void shadowRedisplay(ScreenPtr pScreen) { shadowBuf(pScreen); RegionPtr pRegion; if (!pBuf || !pBuf->pDamage || !pBuf->update) return; pRegion = DamageRegion(pBuf->pDamage); if (RegionNotEmpty(pRegion)) { (*pBuf->update) (pScreen, pBuf); DamageEmpty(pBuf->pDamage); } } static void shadowBlockHandler(void *data, OSTimePtr pTimeout, void *pRead) { ScreenPtr pScreen = (ScreenPtr) data; shadowRedisplay(pScreen); } static void shadowWakeupHandler(void *data, int i, void *LastSelectMask) { } static void shadowGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h, unsigned int format, unsigned long planeMask, char *pdstLine) { ScreenPtr pScreen = pDrawable->pScreen; shadowBuf(pScreen); /* Many apps use GetImage to sync with the visable frame buffer */ if (pDrawable->type == DRAWABLE_WINDOW) shadowRedisplay(pScreen); unwrap(pBuf, pScreen, GetImage); pScreen->GetImage(pDrawable, sx, sy, w, h, format, planeMask, pdstLine); wrap(pBuf, pScreen, GetImage); } #define BACKWARDS_COMPATIBILITY static Bool shadowCloseScreen(ScreenPtr pScreen) { shadowBuf(pScreen); unwrap(pBuf, pScreen, GetImage); unwrap(pBuf, pScreen, CloseScreen); shadowRemove(pScreen, pBuf->pPixmap); DamageDestroy(pBuf->pDamage); #ifdef BACKWARDS_COMPATIBILITY RegionUninit(&pBuf->damage); /* bc */ #endif if (pBuf->pPixmap) pScreen->DestroyPixmap(pBuf->pPixmap); free(pBuf); return pScreen->CloseScreen(pScreen); } #ifdef BACKWARDS_COMPATIBILITY static void shadowReportFunc(DamagePtr pDamage, RegionPtr pRegion, void *closure) { ScreenPtr pScreen = closure; shadowBufPtr pBuf = (shadowBufPtr) dixLookupPrivate(&pScreen->devPrivates, shadowScrPrivateKey); /* Register the damaged region, use DamageReportNone below when we * want to break BC below... */ RegionUnion(&pDamage->damage, &pDamage->damage, pRegion); /* * BC hack. In 7.0 and earlier several drivers would inspect the * 'damage' member directly, so we have to keep it existing. */ RegionCopy(&pBuf->damage, pRegion); } #endif Bool shadowSetup(ScreenPtr pScreen) { shadowBufPtr pBuf; if (!dixRegisterPrivateKey(&shadowScrPrivateKeyRec, PRIVATE_SCREEN, 0)) return FALSE; if (!DamageSetup(pScreen)) return FALSE; pBuf = malloc(sizeof(shadowBufRec)); if (!pBuf) return FALSE; #ifdef BACKWARDS_COMPATIBILITY pBuf->pDamage = DamageCreate((DamageReportFunc) shadowReportFunc, (DamageDestroyFunc) NULL, DamageReportRawRegion, TRUE, pScreen, pScreen); #else pBuf->pDamage = DamageCreate((DamageReportFunc) NULL, (DamageDestroyFunc) NULL, DamageReportNone, TRUE, pScreen, pScreen); #endif if (!pBuf->pDamage) { free(pBuf); return FALSE; } wrap(pBuf, pScreen, CloseScreen); wrap(pBuf, pScreen, GetImage); pBuf->update = 0; pBuf->window = 0; pBuf->pPixmap = 0; pBuf->closure = 0; pBuf->randr = 0; #ifdef BACKWARDS_COMPATIBILITY RegionNull(&pBuf->damage); /* bc */ #endif dixSetPrivate(&pScreen->devPrivates, shadowScrPrivateKey, pBuf); return TRUE; } Bool shadowAdd(ScreenPtr pScreen, PixmapPtr pPixmap, ShadowUpdateProc update, ShadowWindowProc window, int randr, void *closure) { shadowBuf(pScreen); if (!RegisterBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, (void *) pScreen)) return FALSE; /* * Map simple rotation values to bitmasks; fortunately, * these are all unique */ switch (randr) { case 0: randr = SHADOW_ROTATE_0; break; case 90: randr = SHADOW_ROTATE_90; break; case 180: randr = SHADOW_ROTATE_180; break; case 270: randr = SHADOW_ROTATE_270; break; } pBuf->update = update; pBuf->window = window; pBuf->randr = randr; pBuf->closure = closure; pBuf->pPixmap = pPixmap; DamageRegister(&pPixmap->drawable, pBuf->pDamage); return TRUE; } void shadowRemove(ScreenPtr pScreen, PixmapPtr pPixmap) { shadowBuf(pScreen); if (pBuf->pPixmap) { DamageUnregister(pBuf->pDamage); pBuf->update = 0; pBuf->window = 0; pBuf->randr = 0; pBuf->closure = 0; pBuf->pPixmap = 0; } RemoveBlockAndWakeupHandlers(shadowBlockHandler, shadowWakeupHandler, (void *) pScreen); } Bool shadowInit(ScreenPtr pScreen, ShadowUpdateProc update, ShadowWindowProc window) { PixmapPtr pPixmap; pPixmap = pScreen->CreatePixmap(pScreen, pScreen->width, pScreen->height, pScreen->rootDepth, 0); if (!pPixmap) return FALSE; if (!shadowSetup(pScreen)) { pScreen->DestroyPixmap(pPixmap); return FALSE; } shadowAdd(pScreen, pPixmap, update, window, SHADOW_ROTATE_0, 0); return TRUE; }