diff options
Diffstat (limited to 'xorg-server/composite/compalloc.c')
-rw-r--r-- | xorg-server/composite/compalloc.c | 1396 |
1 files changed, 685 insertions, 711 deletions
diff --git a/xorg-server/composite/compalloc.c b/xorg-server/composite/compalloc.c index 745166621..7164c0d3c 100644 --- a/xorg-server/composite/compalloc.c +++ b/xorg-server/composite/compalloc.c @@ -1,711 +1,685 @@ -/*
- * Copyright (c) 2006, Oracle and/or its affiliates. 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 (including the next
- * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
- *
- * Copyright © 2003 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 <dix-config.h>
-#endif
-
-#include "compint.h"
-
-static void
-compScreenUpdate (ScreenPtr pScreen)
-{
- compCheckTree (pScreen);
- compPaintChildrenToWindow (pScreen->root);
-}
-
-static void
-compBlockHandler (int i,
- pointer blockData,
- pointer pTimeout,
- pointer pReadmask)
-{
- ScreenPtr pScreen = screenInfo.screens[i];
- CompScreenPtr cs = GetCompScreen (pScreen);
-
- pScreen->BlockHandler = cs->BlockHandler;
- compScreenUpdate (pScreen);
- (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
-
- /* Next damage will restore the block handler */
- cs->BlockHandler = NULL;
-}
-
-static void
-compReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure)
-{
- WindowPtr pWin = (WindowPtr) closure;
- ScreenPtr pScreen = pWin->drawable.pScreen;
- CompScreenPtr cs = GetCompScreen (pScreen);
- CompWindowPtr cw = GetCompWindow (pWin);
-
- if (!cs->BlockHandler) {
- cs->BlockHandler = pScreen->BlockHandler;
- pScreen->BlockHandler = compBlockHandler;
- }
- cw->damaged = TRUE;
-
- /* Mark the ancestors */
- pWin = pWin->parent;
- while (pWin) {
- if (pWin->damagedDescendants)
- break;
- pWin->damagedDescendants = TRUE;
- pWin = pWin->parent;
- }
-}
-
-static void
-compDestroyDamage (DamagePtr pDamage, void *closure)
-{
- WindowPtr pWin = (WindowPtr) closure;
- CompWindowPtr cw = GetCompWindow (pWin);
-
- cw->damage = 0;
-}
-
-/*
- * Redirect one window for one client
- */
-int
-compRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
-{
- CompWindowPtr cw = GetCompWindow (pWin);
- CompClientWindowPtr ccw;
- Bool wasMapped = pWin->mapped;
- CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
-
- if (pWin == cs->pOverlayWin) {
- return Success;
- }
-
- if (!pWin->parent)
- return BadMatch;
-
- /*
- * Only one Manual update is allowed
- */
- if (cw && update == CompositeRedirectManual)
- for (ccw = cw->clients; ccw; ccw = ccw->next)
- if (ccw->update == CompositeRedirectManual)
- return BadAccess;
-
- /*
- * Allocate per-client per-window structure
- * The client *could* allocate multiple, but while supported,
- * it is not expected to be common
- */
- ccw = malloc(sizeof (CompClientWindowRec));
- if (!ccw)
- return BadAlloc;
- ccw->id = FakeClientID (pClient->index);
- ccw->update = update;
- /*
- * Now make sure there's a per-window structure to hang this from
- */
- if (!cw)
- {
- cw = malloc(sizeof (CompWindowRec));
- if (!cw)
- {
- free(ccw);
- return BadAlloc;
- }
- cw->damage = DamageCreate (compReportDamage,
- compDestroyDamage,
- DamageReportNonEmpty,
- FALSE,
- pWin->drawable.pScreen,
- pWin);
- if (!cw->damage)
- {
- free(ccw);
- free(cw);
- return BadAlloc;
- }
- if (wasMapped)
- {
- DisableMapUnmapEvents (pWin);
- UnmapWindow (pWin, FALSE);
- EnableMapUnmapEvents (pWin);
- }
-
- RegionNull(&cw->borderClip);
- cw->borderClipX = 0;
- cw->borderClipY = 0;
- cw->update = CompositeRedirectAutomatic;
- cw->clients = 0;
- cw->oldx = COMP_ORIGIN_INVALID;
- cw->oldy = COMP_ORIGIN_INVALID;
- cw->damageRegistered = FALSE;
- cw->damaged = FALSE;
- cw->pOldPixmap = NullPixmap;
- dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw);
- }
- ccw->next = cw->clients;
- cw->clients = ccw;
- if (!AddResource (ccw->id, CompositeClientWindowType, pWin))
- return BadAlloc;
- if (ccw->update == CompositeRedirectManual)
- {
- /* If the window was CompositeRedirectAutomatic, then
- * unmap the window so that the parent clip list will
- * be correctly recomputed.
- */
- if (pWin->mapped)
- {
- DisableMapUnmapEvents (pWin);
- UnmapWindow (pWin, FALSE);
- EnableMapUnmapEvents (pWin);
- }
- if (cw->damageRegistered)
- {
- DamageUnregister (&pWin->drawable, cw->damage);
- cw->damageRegistered = FALSE;
- }
- cw->update = CompositeRedirectManual;
- }
-
- if (!compCheckRedirect (pWin))
- {
- FreeResource (ccw->id, RT_NONE);
- return BadAlloc;
- }
- if (wasMapped && !pWin->mapped)
- {
- Bool overrideRedirect = pWin->overrideRedirect;
- pWin->overrideRedirect = TRUE;
- DisableMapUnmapEvents (pWin);
- MapWindow (pWin, pClient);
- EnableMapUnmapEvents (pWin);
- pWin->overrideRedirect = overrideRedirect;
- }
-
- return Success;
-}
-
-/*
- * Free one of the per-client per-window resources, clearing
- * redirect and the per-window pointer as appropriate
- */
-void
-compFreeClientWindow (WindowPtr pWin, XID id)
-{
- CompWindowPtr cw = GetCompWindow (pWin);
- CompClientWindowPtr ccw, *prev;
- Bool wasMapped = pWin->mapped;
-
- if (!cw)
- return;
- for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next)
- {
- if (ccw->id == id)
- {
- *prev = ccw->next;
- if (ccw->update == CompositeRedirectManual)
- cw->update = CompositeRedirectAutomatic;
- free(ccw);
- break;
- }
- }
- if (!cw->clients)
- {
- if (wasMapped)
- {
- DisableMapUnmapEvents (pWin);
- UnmapWindow (pWin, FALSE);
- EnableMapUnmapEvents (pWin);
- }
-
- if (pWin->redirectDraw != RedirectDrawNone)
- compFreePixmap (pWin);
-
- if (cw->damage)
- DamageDestroy (cw->damage);
-
- RegionUninit(&cw->borderClip);
-
- dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL);
- free(cw);
- }
- else if (cw->update == CompositeRedirectAutomatic &&
- !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone)
- {
- DamageRegister (&pWin->drawable, cw->damage);
- cw->damageRegistered = TRUE;
- pWin->redirectDraw = RedirectDrawAutomatic;
- DamageDamageRegion(&pWin->drawable, &pWin->borderSize);
- }
- if (wasMapped && !pWin->mapped)
- {
- Bool overrideRedirect = pWin->overrideRedirect;
- pWin->overrideRedirect = TRUE;
- DisableMapUnmapEvents (pWin);
- MapWindow (pWin, clients[CLIENT_ID(id)]);
- EnableMapUnmapEvents (pWin);
- pWin->overrideRedirect = overrideRedirect;
- }
-}
-
-/*
- * This is easy, just free the appropriate resource.
- */
-
-int
-compUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update)
-{
- CompWindowPtr cw = GetCompWindow (pWin);
- CompClientWindowPtr ccw;
-
- if (!cw)
- return BadValue;
-
- for (ccw = cw->clients; ccw; ccw = ccw->next)
- if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
- {
- FreeResource (ccw->id, RT_NONE);
- return Success;
- }
- return BadValue;
-}
-
-/*
- * Redirect all subwindows for one client
- */
-
-int
-compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
-{
- CompSubwindowsPtr csw = GetCompSubwindows (pWin);
- CompClientWindowPtr ccw;
- WindowPtr pChild;
-
- /*
- * Only one Manual update is allowed
- */
- if (csw && update == CompositeRedirectManual)
- for (ccw = csw->clients; ccw; ccw = ccw->next)
- if (ccw->update == CompositeRedirectManual)
- return BadAccess;
- /*
- * Allocate per-client per-window structure
- * The client *could* allocate multiple, but while supported,
- * it is not expected to be common
- */
- ccw = malloc(sizeof (CompClientWindowRec));
- if (!ccw)
- return BadAlloc;
- ccw->id = FakeClientID (pClient->index);
- ccw->update = update;
- /*
- * Now make sure there's a per-window structure to hang this from
- */
- if (!csw)
- {
- csw = malloc(sizeof (CompSubwindowsRec));
- if (!csw)
- {
- free(ccw);
- return BadAlloc;
- }
- csw->update = CompositeRedirectAutomatic;
- csw->clients = 0;
- dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw);
- }
- /*
- * Redirect all existing windows
- */
- for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
- {
- int ret = compRedirectWindow (pClient, pChild, update);
- if (ret != Success)
- {
- for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib)
- (void) compUnredirectWindow (pClient, pChild, update);
- if (!csw->clients)
- {
- free(csw);
- dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0);
- }
- free(ccw);
- return ret;
- }
- }
- /*
- * Hook into subwindows list
- */
- ccw->next = csw->clients;
- csw->clients = ccw;
- if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin))
- return BadAlloc;
- if (ccw->update == CompositeRedirectManual)
- {
- csw->update = CompositeRedirectManual;
- /*
- * tell damage extension that damage events for this client are
- * critical output
- */
- DamageExtSetCritical (pClient, TRUE);
- }
- return Success;
-}
-
-/*
- * Free one of the per-client per-subwindows resources,
- * which frees one redirect per subwindow
- */
-void
-compFreeClientSubwindows (WindowPtr pWin, XID id)
-{
- CompSubwindowsPtr csw = GetCompSubwindows (pWin);
- CompClientWindowPtr ccw, *prev;
- WindowPtr pChild;
-
- if (!csw)
- return;
- for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next)
- {
- if (ccw->id == id)
- {
- ClientPtr pClient = clients[CLIENT_ID(id)];
-
- *prev = ccw->next;
- if (ccw->update == CompositeRedirectManual)
- {
- /*
- * tell damage extension that damage events for this client are
- * critical output
- */
- DamageExtSetCritical (pClient, FALSE);
- csw->update = CompositeRedirectAutomatic;
- if (pWin->mapped)
- (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE);
- }
-
- /*
- * Unredirect all existing subwindows
- */
- for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
- (void) compUnredirectWindow (pClient, pChild, ccw->update);
-
- free(ccw);
- break;
- }
- }
-
- /*
- * Check if all of the per-client records are gone
- */
- if (!csw->clients)
- {
- dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL);
- free(csw);
- }
-}
-
-/*
- * This is easy, just free the appropriate resource.
- */
-
-int
-compUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
-{
- CompSubwindowsPtr csw = GetCompSubwindows (pWin);
- CompClientWindowPtr ccw;
-
- if (!csw)
- return BadValue;
- for (ccw = csw->clients; ccw; ccw = ccw->next)
- if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index)
- {
- FreeResource (ccw->id, RT_NONE);
- return Success;
- }
- return BadValue;
-}
-
-/*
- * Add redirection information for one subwindow (during reparent)
- */
-
-int
-compRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
-{
- CompSubwindowsPtr csw = GetCompSubwindows (pParent);
- CompClientWindowPtr ccw;
-
- if (!csw)
- return Success;
- for (ccw = csw->clients; ccw; ccw = ccw->next)
- {
- int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)],
- pWin, ccw->update);
- if (ret != Success)
- return ret;
- }
- return Success;
-}
-
-/*
- * Remove redirection information for one subwindow (during reparent)
- */
-
-int
-compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin)
-{
- CompSubwindowsPtr csw = GetCompSubwindows (pParent);
- CompClientWindowPtr ccw;
-
- if (!csw)
- return Success;
- for (ccw = csw->clients; ccw; ccw = ccw->next)
- {
- int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)],
- pWin, ccw->update);
- if (ret != Success)
- return ret;
- }
- return Success;
-}
-
-static int
-bgNoneVisitWindow(WindowPtr pWin, void *null)
-{
- if (pWin->backgroundState != BackgroundPixmap)
- return WT_WALKCHILDREN;
- if (pWin->background.pixmap != None)
- return WT_WALKCHILDREN;
-
- return WT_STOPWALKING;
-}
-
-static PixmapPtr
-compNewPixmap (WindowPtr pWin, int x, int y, int w, int h, Bool map)
-{
- ScreenPtr pScreen = pWin->drawable.pScreen;
- WindowPtr pParent = pWin->parent;
- PixmapPtr pPixmap;
-
- pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth,
- CREATE_PIXMAP_USAGE_BACKING_PIXMAP);
-
- if (!pPixmap)
- return 0;
-
- pPixmap->screen_x = x;
- pPixmap->screen_y = y;
-
- /* resize allocations will update later in compCopyWindow, not here */
- if (!map)
- return pPixmap;
-
- /*
- * If there's no bg=None in the tree, we're done.
- *
- * We could optimize this more by collection the regions of all the
- * bg=None subwindows and feeding that in as the clip for the
- * CopyArea below, but since window trees are shallow these days it
- * might not be worth the effort.
- */
- if (TraverseTree(pWin, bgNoneVisitWindow, NULL) == WT_NOMATCH)
- return pPixmap;
-
- /*
- * Copy bits from the parent into the new pixmap so that it will
- * have "reasonable" contents in case for background None areas.
- */
- if (pParent->drawable.depth == pWin->drawable.depth)
- {
- GCPtr pGC = GetScratchGC (pWin->drawable.depth, pScreen);
-
- if (pGC)
- {
- ChangeGCVal val;
- val.val = IncludeInferiors;
-
- ValidateGC(&pPixmap->drawable, pGC);
- ChangeGC (serverClient, pGC, GCSubwindowMode, &val);
- (*pGC->ops->CopyArea) (&pParent->drawable,
- &pPixmap->drawable,
- pGC,
- x - pParent->drawable.x,
- y - pParent->drawable.y,
- w, h, 0, 0);
- FreeScratchGC (pGC);
- }
- }
- else
- {
- PictFormatPtr pSrcFormat = compWindowFormat (pParent);
- PictFormatPtr pDstFormat = compWindowFormat (pWin);
- XID inferiors = IncludeInferiors;
- int error;
-
- PicturePtr pSrcPicture = CreatePicture (None,
- &pParent->drawable,
- pSrcFormat,
- CPSubwindowMode,
- &inferiors,
- serverClient, &error);
-
- PicturePtr pDstPicture = CreatePicture (None,
- &pPixmap->drawable,
- pDstFormat,
- 0, 0,
- serverClient, &error);
-
- if (pSrcPicture && pDstPicture)
- {
- CompositePicture (PictOpSrc,
- pSrcPicture,
- NULL,
- pDstPicture,
- x - pParent->drawable.x,
- y - pParent->drawable.y,
- 0, 0, 0, 0, w, h);
- }
- if (pSrcPicture)
- FreePicture (pSrcPicture, 0);
- if (pDstPicture)
- FreePicture (pDstPicture, 0);
- }
- return pPixmap;
-}
-
-Bool
-compAllocPixmap (WindowPtr pWin)
-{
- int bw = (int) pWin->borderWidth;
- int x = pWin->drawable.x - bw;
- int y = pWin->drawable.y - bw;
- int w = pWin->drawable.width + (bw << 1);
- int h = pWin->drawable.height + (bw << 1);
- PixmapPtr pPixmap = compNewPixmap (pWin, x, y, w, h, TRUE);
- CompWindowPtr cw = GetCompWindow (pWin);
-
- if (!pPixmap)
- return FALSE;
- if (cw->update == CompositeRedirectAutomatic)
- pWin->redirectDraw = RedirectDrawAutomatic;
- else
- pWin->redirectDraw = RedirectDrawManual;
-
- compSetPixmap (pWin, pPixmap);
- cw->oldx = COMP_ORIGIN_INVALID;
- cw->oldy = COMP_ORIGIN_INVALID;
- cw->damageRegistered = FALSE;
- if (cw->update == CompositeRedirectAutomatic)
- {
- DamageRegister (&pWin->drawable, cw->damage);
- cw->damageRegistered = TRUE;
- }
- return TRUE;
-}
-
-void
-compFreePixmap (WindowPtr pWin)
-{
- ScreenPtr pScreen = pWin->drawable.pScreen;
- PixmapPtr pRedirectPixmap, pParentPixmap;
- CompWindowPtr cw = GetCompWindow (pWin);
-
- if (cw->damageRegistered)
- {
- DamageUnregister (&pWin->drawable, cw->damage);
- cw->damageRegistered = FALSE;
- DamageEmpty (cw->damage);
- }
- /*
- * Move the parent-constrained border clip region back into
- * the window so that ValidateTree will handle the unmap
- * case correctly. Unmap adds the window borderClip to the
- * parent exposed area; regions beyond the parent cause crashes
- */
- RegionCopy(&pWin->borderClip, &cw->borderClip);
- pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin);
- pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
- pWin->redirectDraw = RedirectDrawNone;
- compSetPixmap (pWin, pParentPixmap);
- (*pScreen->DestroyPixmap) (pRedirectPixmap);
-}
-
-/*
- * Make sure the pixmap is the right size and offset. Allocate a new
- * pixmap to change size, adjust origin to change offset, leaving the
- * old pixmap in cw->pOldPixmap so bits can be recovered
- */
-Bool
-compReallocPixmap (WindowPtr pWin, int draw_x, int draw_y,
- unsigned int w, unsigned int h, int bw)
-{
- ScreenPtr pScreen = pWin->drawable.pScreen;
- PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin);
- PixmapPtr pNew;
- CompWindowPtr cw = GetCompWindow (pWin);
- int pix_x, pix_y;
- int pix_w, pix_h;
-
- assert (cw && pWin->redirectDraw != RedirectDrawNone);
- cw->oldx = pOld->screen_x;
- cw->oldy = pOld->screen_y;
- pix_x = draw_x - bw;
- pix_y = draw_y - bw;
- pix_w = w + (bw << 1);
- pix_h = h + (bw << 1);
- if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height)
- {
- pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h, FALSE);
- if (!pNew)
- return FALSE;
- cw->pOldPixmap = pOld;
- compSetPixmap (pWin, pNew);
- }
- else
- {
- pNew = pOld;
- cw->pOldPixmap = 0;
- }
- pNew->screen_x = pix_x;
- pNew->screen_y = pix_y;
- return TRUE;
-}
+/* + * Copyright (c) 2006, Oracle and/or its affiliates. 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 (including the next + * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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. + * + * Copyright © 2003 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 <dix-config.h> +#endif + +#include "compint.h" + +static void +compScreenUpdate (ScreenPtr pScreen) +{ + compCheckTree (pScreen); + compPaintChildrenToWindow (pScreen->root); +} + +static void +compBlockHandler (int i, + pointer blockData, + pointer pTimeout, + pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + CompScreenPtr cs = GetCompScreen (pScreen); + + pScreen->BlockHandler = cs->BlockHandler; + compScreenUpdate (pScreen); + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + + /* Next damage will restore the block handler */ + cs->BlockHandler = NULL; +} + +static void +compReportDamage (DamagePtr pDamage, RegionPtr pRegion, void *closure) +{ + WindowPtr pWin = (WindowPtr) closure; + ScreenPtr pScreen = pWin->drawable.pScreen; + CompScreenPtr cs = GetCompScreen (pScreen); + CompWindowPtr cw = GetCompWindow (pWin); + + if (!cs->BlockHandler) { + cs->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = compBlockHandler; + } + cw->damaged = TRUE; + + /* Mark the ancestors */ + pWin = pWin->parent; + while (pWin) { + if (pWin->damagedDescendants) + break; + pWin->damagedDescendants = TRUE; + pWin = pWin->parent; + } +} + +static void +compDestroyDamage (DamagePtr pDamage, void *closure) +{ + WindowPtr pWin = (WindowPtr) closure; + CompWindowPtr cw = GetCompWindow (pWin); + + cw->damage = 0; +} + +/* + * Redirect one window for one client + */ +int +compRedirectWindow (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompWindowPtr cw = GetCompWindow (pWin); + CompClientWindowPtr ccw; + Bool wasMapped = pWin->mapped; + CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen); + + if (pWin == cs->pOverlayWin) { + return Success; + } + + if (!pWin->parent) + return BadMatch; + + /* + * Only one Manual update is allowed + */ + if (cw && update == CompositeRedirectManual) + for (ccw = cw->clients; ccw; ccw = ccw->next) + if (ccw->update == CompositeRedirectManual) + return BadAccess; + + /* + * Allocate per-client per-window structure + * The client *could* allocate multiple, but while supported, + * it is not expected to be common + */ + ccw = malloc(sizeof (CompClientWindowRec)); + if (!ccw) + return BadAlloc; + ccw->id = FakeClientID (pClient->index); + ccw->update = update; + /* + * Now make sure there's a per-window structure to hang this from + */ + if (!cw) + { + cw = malloc(sizeof (CompWindowRec)); + if (!cw) + { + free(ccw); + return BadAlloc; + } + cw->damage = DamageCreate (compReportDamage, + compDestroyDamage, + DamageReportNonEmpty, + FALSE, + pWin->drawable.pScreen, + pWin); + if (!cw->damage) + { + free(ccw); + free(cw); + return BadAlloc; + } + if (wasMapped) + { + DisableMapUnmapEvents (pWin); + UnmapWindow (pWin, FALSE); + EnableMapUnmapEvents (pWin); + } + + RegionNull(&cw->borderClip); + cw->borderClipX = 0; + cw->borderClipY = 0; + cw->update = CompositeRedirectAutomatic; + cw->clients = 0; + cw->oldx = COMP_ORIGIN_INVALID; + cw->oldy = COMP_ORIGIN_INVALID; + cw->damageRegistered = FALSE; + cw->damaged = FALSE; + cw->pOldPixmap = NullPixmap; + dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, cw); + } + ccw->next = cw->clients; + cw->clients = ccw; + if (!AddResource (ccw->id, CompositeClientWindowType, pWin)) + return BadAlloc; + if (ccw->update == CompositeRedirectManual) + { + /* If the window was CompositeRedirectAutomatic, then + * unmap the window so that the parent clip list will + * be correctly recomputed. + */ + if (pWin->mapped) + { + DisableMapUnmapEvents (pWin); + UnmapWindow (pWin, FALSE); + EnableMapUnmapEvents (pWin); + } + if (cw->damageRegistered) + { + DamageUnregister (&pWin->drawable, cw->damage); + cw->damageRegistered = FALSE; + } + cw->update = CompositeRedirectManual; + } + + if (!compCheckRedirect (pWin)) + { + FreeResource (ccw->id, RT_NONE); + return BadAlloc; + } + if (wasMapped && !pWin->mapped) + { + Bool overrideRedirect = pWin->overrideRedirect; + pWin->overrideRedirect = TRUE; + DisableMapUnmapEvents (pWin); + MapWindow (pWin, pClient); + EnableMapUnmapEvents (pWin); + pWin->overrideRedirect = overrideRedirect; + } + + return Success; +} + +/* + * Free one of the per-client per-window resources, clearing + * redirect and the per-window pointer as appropriate + */ +void +compFreeClientWindow (WindowPtr pWin, XID id) +{ + CompWindowPtr cw = GetCompWindow (pWin); + CompClientWindowPtr ccw, *prev; + Bool wasMapped = pWin->mapped; + + if (!cw) + return; + for (prev = &cw->clients; (ccw = *prev); prev = &ccw->next) + { + if (ccw->id == id) + { + *prev = ccw->next; + if (ccw->update == CompositeRedirectManual) + cw->update = CompositeRedirectAutomatic; + free(ccw); + break; + } + } + if (!cw->clients) + { + if (wasMapped) + { + DisableMapUnmapEvents (pWin); + UnmapWindow (pWin, FALSE); + EnableMapUnmapEvents (pWin); + } + + if (pWin->redirectDraw != RedirectDrawNone) + compFreePixmap (pWin); + + if (cw->damage) + DamageDestroy (cw->damage); + + RegionUninit(&cw->borderClip); + + dixSetPrivate(&pWin->devPrivates, CompWindowPrivateKey, NULL); + free(cw); + } + else if (cw->update == CompositeRedirectAutomatic && + !cw->damageRegistered && pWin->redirectDraw != RedirectDrawNone) + { + DamageRegister (&pWin->drawable, cw->damage); + cw->damageRegistered = TRUE; + pWin->redirectDraw = RedirectDrawAutomatic; + DamageDamageRegion(&pWin->drawable, &pWin->borderSize); + } + if (wasMapped && !pWin->mapped) + { + Bool overrideRedirect = pWin->overrideRedirect; + pWin->overrideRedirect = TRUE; + DisableMapUnmapEvents (pWin); + MapWindow (pWin, clients[CLIENT_ID(id)]); + EnableMapUnmapEvents (pWin); + pWin->overrideRedirect = overrideRedirect; + } +} + +/* + * This is easy, just free the appropriate resource. + */ + +int +compUnredirectWindow (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompWindowPtr cw = GetCompWindow (pWin); + CompClientWindowPtr ccw; + + if (!cw) + return BadValue; + + for (ccw = cw->clients; ccw; ccw = ccw->next) + if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) + { + FreeResource (ccw->id, RT_NONE); + return Success; + } + return BadValue; +} + +/* + * Redirect all subwindows for one client + */ + +int +compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pWin); + CompClientWindowPtr ccw; + WindowPtr pChild; + + /* + * Only one Manual update is allowed + */ + if (csw && update == CompositeRedirectManual) + for (ccw = csw->clients; ccw; ccw = ccw->next) + if (ccw->update == CompositeRedirectManual) + return BadAccess; + /* + * Allocate per-client per-window structure + * The client *could* allocate multiple, but while supported, + * it is not expected to be common + */ + ccw = malloc(sizeof (CompClientWindowRec)); + if (!ccw) + return BadAlloc; + ccw->id = FakeClientID (pClient->index); + ccw->update = update; + /* + * Now make sure there's a per-window structure to hang this from + */ + if (!csw) + { + csw = malloc(sizeof (CompSubwindowsRec)); + if (!csw) + { + free(ccw); + return BadAlloc; + } + csw->update = CompositeRedirectAutomatic; + csw->clients = 0; + dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, csw); + } + /* + * Redirect all existing windows + */ + for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) + { + int ret = compRedirectWindow (pClient, pChild, update); + if (ret != Success) + { + for (pChild = pChild->nextSib; pChild; pChild = pChild->nextSib) + (void) compUnredirectWindow (pClient, pChild, update); + if (!csw->clients) + { + free(csw); + dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, 0); + } + free(ccw); + return ret; + } + } + /* + * Hook into subwindows list + */ + ccw->next = csw->clients; + csw->clients = ccw; + if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin)) + return BadAlloc; + if (ccw->update == CompositeRedirectManual) + { + csw->update = CompositeRedirectManual; + /* + * tell damage extension that damage events for this client are + * critical output + */ + DamageExtSetCritical (pClient, TRUE); + } + return Success; +} + +/* + * Free one of the per-client per-subwindows resources, + * which frees one redirect per subwindow + */ +void +compFreeClientSubwindows (WindowPtr pWin, XID id) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pWin); + CompClientWindowPtr ccw, *prev; + WindowPtr pChild; + + if (!csw) + return; + for (prev = &csw->clients; (ccw = *prev); prev = &ccw->next) + { + if (ccw->id == id) + { + ClientPtr pClient = clients[CLIENT_ID(id)]; + + *prev = ccw->next; + if (ccw->update == CompositeRedirectManual) + { + /* + * tell damage extension that damage events for this client are + * critical output + */ + DamageExtSetCritical (pClient, FALSE); + csw->update = CompositeRedirectAutomatic; + if (pWin->mapped) + (*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE); + } + + /* + * Unredirect all existing subwindows + */ + for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib) + (void) compUnredirectWindow (pClient, pChild, ccw->update); + + free(ccw); + break; + } + } + + /* + * Check if all of the per-client records are gone + */ + if (!csw->clients) + { + dixSetPrivate(&pWin->devPrivates, CompSubwindowsPrivateKey, NULL); + free(csw); + } +} + +/* + * This is easy, just free the appropriate resource. + */ + +int +compUnredirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pWin); + CompClientWindowPtr ccw; + + if (!csw) + return BadValue; + for (ccw = csw->clients; ccw; ccw = ccw->next) + if (ccw->update == update && CLIENT_ID(ccw->id) == pClient->index) + { + FreeResource (ccw->id, RT_NONE); + return Success; + } + return BadValue; +} + +/* + * Add redirection information for one subwindow (during reparent) + */ + +int +compRedirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pParent); + CompClientWindowPtr ccw; + + if (!csw) + return Success; + for (ccw = csw->clients; ccw; ccw = ccw->next) + { + int ret = compRedirectWindow (clients[CLIENT_ID(ccw->id)], + pWin, ccw->update); + if (ret != Success) + return ret; + } + return Success; +} + +/* + * Remove redirection information for one subwindow (during reparent) + */ + +int +compUnredirectOneSubwindow (WindowPtr pParent, WindowPtr pWin) +{ + CompSubwindowsPtr csw = GetCompSubwindows (pParent); + CompClientWindowPtr ccw; + + if (!csw) + return Success; + for (ccw = csw->clients; ccw; ccw = ccw->next) + { + int ret = compUnredirectWindow (clients[CLIENT_ID(ccw->id)], + pWin, ccw->update); + if (ret != Success) + return ret; + } + return Success; +} + +static PixmapPtr +compNewPixmap (WindowPtr pWin, int x, int y, int w, int h, Bool map) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + WindowPtr pParent = pWin->parent; + PixmapPtr pPixmap; + + pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth, + CREATE_PIXMAP_USAGE_BACKING_PIXMAP); + + if (!pPixmap) + return 0; + + pPixmap->screen_x = x; + pPixmap->screen_y = y; + + /* resize allocations will update later in compCopyWindow, not here */ + if (!map) + return pPixmap; + + if (pParent->drawable.depth == pWin->drawable.depth) + { + GCPtr pGC = GetScratchGC (pWin->drawable.depth, pScreen); + + if (pGC) + { + ChangeGCVal val; + val.val = IncludeInferiors; + + ValidateGC(&pPixmap->drawable, pGC); + ChangeGC (serverClient, pGC, GCSubwindowMode, &val); + (*pGC->ops->CopyArea) (&pParent->drawable, + &pPixmap->drawable, + pGC, + x - pParent->drawable.x, + y - pParent->drawable.y, + w, h, 0, 0); + FreeScratchGC (pGC); + } + } + else + { + PictFormatPtr pSrcFormat = compWindowFormat (pParent); + PictFormatPtr pDstFormat = compWindowFormat (pWin); + XID inferiors = IncludeInferiors; + int error; + + PicturePtr pSrcPicture = CreatePicture (None, + &pParent->drawable, + pSrcFormat, + CPSubwindowMode, + &inferiors, + serverClient, &error); + + PicturePtr pDstPicture = CreatePicture (None, + &pPixmap->drawable, + pDstFormat, + 0, 0, + serverClient, &error); + + if (pSrcPicture && pDstPicture) + { + CompositePicture (PictOpSrc, + pSrcPicture, + NULL, + pDstPicture, + x - pParent->drawable.x, + y - pParent->drawable.y, + 0, 0, 0, 0, w, h); + } + if (pSrcPicture) + FreePicture (pSrcPicture, 0); + if (pDstPicture) + FreePicture (pDstPicture, 0); + } + return pPixmap; +} + +Bool +compAllocPixmap (WindowPtr pWin) +{ + int bw = (int) pWin->borderWidth; + int x = pWin->drawable.x - bw; + int y = pWin->drawable.y - bw; + int w = pWin->drawable.width + (bw << 1); + int h = pWin->drawable.height + (bw << 1); + PixmapPtr pPixmap = compNewPixmap (pWin, x, y, w, h, TRUE); + CompWindowPtr cw = GetCompWindow (pWin); + + if (!pPixmap) + return FALSE; + if (cw->update == CompositeRedirectAutomatic) + pWin->redirectDraw = RedirectDrawAutomatic; + else + pWin->redirectDraw = RedirectDrawManual; + + compSetPixmap (pWin, pPixmap); + cw->oldx = COMP_ORIGIN_INVALID; + cw->oldy = COMP_ORIGIN_INVALID; + cw->damageRegistered = FALSE; + if (cw->update == CompositeRedirectAutomatic) + { + DamageRegister (&pWin->drawable, cw->damage); + cw->damageRegistered = TRUE; + } + return TRUE; +} + +void +compFreePixmap (WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + PixmapPtr pRedirectPixmap, pParentPixmap; + CompWindowPtr cw = GetCompWindow (pWin); + + if (cw->damageRegistered) + { + DamageUnregister (&pWin->drawable, cw->damage); + cw->damageRegistered = FALSE; + DamageEmpty (cw->damage); + } + /* + * Move the parent-constrained border clip region back into + * the window so that ValidateTree will handle the unmap + * case correctly. Unmap adds the window borderClip to the + * parent exposed area; regions beyond the parent cause crashes + */ + RegionCopy(&pWin->borderClip, &cw->borderClip); + pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin); + pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent); + pWin->redirectDraw = RedirectDrawNone; + compSetPixmap (pWin, pParentPixmap); + (*pScreen->DestroyPixmap) (pRedirectPixmap); +} + +/* + * Make sure the pixmap is the right size and offset. Allocate a new + * pixmap to change size, adjust origin to change offset, leaving the + * old pixmap in cw->pOldPixmap so bits can be recovered + */ +Bool +compReallocPixmap (WindowPtr pWin, int draw_x, int draw_y, + unsigned int w, unsigned int h, int bw) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + PixmapPtr pOld = (*pScreen->GetWindowPixmap) (pWin); + PixmapPtr pNew; + CompWindowPtr cw = GetCompWindow (pWin); + int pix_x, pix_y; + int pix_w, pix_h; + + assert (cw && pWin->redirectDraw != RedirectDrawNone); + cw->oldx = pOld->screen_x; + cw->oldy = pOld->screen_y; + pix_x = draw_x - bw; + pix_y = draw_y - bw; + pix_w = w + (bw << 1); + pix_h = h + (bw << 1); + if (pix_w != pOld->drawable.width || pix_h != pOld->drawable.height) + { + pNew = compNewPixmap (pWin, pix_x, pix_y, pix_w, pix_h, FALSE); + if (!pNew) + return FALSE; + cw->pOldPixmap = pOld; + compSetPixmap (pWin, pNew); + } + else + { + pNew = pOld; + cw->pOldPixmap = 0; + } + pNew->screen_x = pix_x; + pNew->screen_y = pix_y; + return TRUE; +} |