summaryrefslogtreecommitdiff
path: root/composite/compwindow.c
diff options
context:
space:
mode:
Diffstat (limited to 'composite/compwindow.c')
-rw-r--r--composite/compwindow.c754
1 files changed, 754 insertions, 0 deletions
diff --git a/composite/compwindow.c b/composite/compwindow.c
new file mode 100644
index 000000000..c7ea98c13
--- /dev/null
+++ b/composite/compwindow.c
@@ -0,0 +1,754 @@
+/*
+ * $Id$
+ *
+ * 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_CONFIG_H
+#include <config.h>
+#endif
+#include "compint.h"
+
+#ifdef COMPOSITE_DEBUG
+static int
+compCheckWindow (WindowPtr pWin, pointer data)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ PixmapPtr pWinPixmap = (*pScreen->GetWindowPixmap) (pWin);
+ PixmapPtr pParentPixmap = pWin->parent ? (*pScreen->GetWindowPixmap) (pWin->parent) : 0;
+ PixmapPtr pScreenPixmap = (*pScreen->GetScreenPixmap) (pScreen);
+
+ if (!pWin->parent)
+ {
+ assert (!pWin->redirectDraw);
+ assert (pWinPixmap == pScreenPixmap);
+ }
+ else if (pWin->redirectDraw)
+ {
+ assert (pWinPixmap != pParentPixmap);
+ assert (pWinPixmap != pScreenPixmap);
+ }
+ else
+ {
+ assert (pWinPixmap == pParentPixmap);
+ }
+ assert (0 < pWinPixmap->refcnt && pWinPixmap->refcnt < 3);
+ assert (0 < pScreenPixmap->refcnt && pScreenPixmap->refcnt < 3);
+ if (pParentPixmap)
+ assert (0 <= pParentPixmap->refcnt && pParentPixmap->refcnt < 3);
+ return WT_WALKCHILDREN;
+}
+
+void
+compCheckTree (ScreenPtr pScreen)
+{
+ WalkTree (pScreen, compCheckWindow, 0);
+}
+#endif
+
+typedef struct _compPixmapVisit {
+ WindowPtr pWindow;
+ PixmapPtr pPixmap;
+} CompPixmapVisitRec, *CompPixmapVisitPtr;
+
+static Bool
+compRepaintBorder (ClientPtr pClient, pointer closure)
+{
+ WindowPtr pWindow = LookupWindow ((XID) closure, pClient);
+
+ if (pWindow)
+ {
+ RegionRec exposed;
+
+ REGION_NULL(pScreen, &exposed);
+ REGION_SUBTRACT(pScreen, &exposed, &pWindow->borderClip, &pWindow->winSize);
+ (*pWindow->drawable.pScreen->PaintWindowBorder)(pWindow, &exposed, PW_BORDER);
+ REGION_UNINIT(pScreen, &exposed);
+ }
+ return TRUE;
+}
+
+static int
+compSetPixmapVisitWindow (WindowPtr pWindow, pointer data)
+{
+ CompPixmapVisitPtr pVisit = (CompPixmapVisitPtr) data;
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+
+ if (pWindow != pVisit->pWindow && pWindow->redirectDraw)
+ return WT_DONTWALKCHILDREN;
+ (*pScreen->SetWindowPixmap) (pWindow, pVisit->pPixmap);
+ /*
+ * Recompute winSize and borderSize. This is duplicate effort
+ * when resizing pixmaps, but necessary when changing redirection.
+ * Might be nice to fix this.
+ */
+ SetWinSize (pWindow);
+ SetBorderSize (pWindow);
+ if (HasBorder (pWindow))
+ QueueWorkProc (compRepaintBorder, serverClient,
+ (pointer) pWindow->drawable.id);
+ return WT_WALKCHILDREN;
+}
+
+void
+compSetPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
+{
+ CompPixmapVisitRec visitRec;
+
+ visitRec.pWindow = pWindow;
+ visitRec.pPixmap = pPixmap;
+ TraverseTree (pWindow, compSetPixmapVisitWindow, (pointer) &visitRec);
+ compCheckTree (pWindow->drawable.pScreen);
+}
+
+Bool
+compCheckRedirect (WindowPtr pWin)
+{
+ CompWindowPtr cw = GetCompWindow (pWin);
+ Bool should;
+
+ should = pWin->realized && (pWin->drawable.class != InputOnly) &&
+ (cw != NULL);
+
+ if (should != pWin->redirectDraw)
+ {
+ if (should)
+ return compAllocPixmap (pWin);
+ else
+ compFreePixmap (pWin);
+ }
+ return TRUE;
+}
+
+Bool
+compPositionWindow (WindowPtr pWin, int x, int y)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ Bool ret = TRUE;
+
+ pScreen->PositionWindow = cs->PositionWindow;
+ /*
+ * "Shouldn't need this as all possible places should be wrapped
+ *
+ compCheckRedirect (pWin);
+ */
+#ifdef COMPOSITE_DEBUG
+ if (pWin->redirectDraw != (pWin->viewable && (GetCompWindow(pWin) != NULL)))
+ abort ();
+#endif
+ if (pWin->redirectDraw)
+ {
+ PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
+ int bw = wBorderWidth (pWin);
+ int nx = pWin->drawable.x - bw;
+ int ny = pWin->drawable.y - bw;
+
+ if (pPixmap->screen_x != nx || pPixmap->screen_y != ny)
+ {
+ pPixmap->screen_x = nx;
+ pPixmap->screen_y = ny;
+ pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ }
+ }
+
+ if (!(*pScreen->PositionWindow) (pWin, x, y))
+ ret = FALSE;
+ cs->PositionWindow = pScreen->PositionWindow;
+ pScreen->PositionWindow = compPositionWindow;
+ compCheckTree (pWin->drawable.pScreen);
+ return ret;
+}
+
+Bool
+compRealizeWindow (WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ Bool ret = TRUE;
+
+ pScreen->RealizeWindow = cs->RealizeWindow;
+ compCheckRedirect (pWin);
+ if (!(*pScreen->RealizeWindow) (pWin))
+ ret = FALSE;
+ cs->RealizeWindow = pScreen->RealizeWindow;
+ pScreen->RealizeWindow = compRealizeWindow;
+ compCheckTree (pWin->drawable.pScreen);
+ return ret;
+}
+
+Bool
+compUnrealizeWindow (WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ Bool ret = TRUE;
+
+ pScreen->UnrealizeWindow = cs->UnrealizeWindow;
+ compCheckRedirect (pWin);
+ if (!(*pScreen->UnrealizeWindow) (pWin))
+ ret = FALSE;
+ cs->UnrealizeWindow = pScreen->UnrealizeWindow;
+ pScreen->UnrealizeWindow = compUnrealizeWindow;
+ compCheckTree (pWin->drawable.pScreen);
+ return ret;
+}
+
+void
+compPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompSubwindowsPtr csw = GetCompSubwindows (pWin);
+ CompScreenPtr cs = GetCompScreen (pScreen);
+
+ if (csw && csw->update == CompositeRedirectManual)
+ return;
+ pScreen->PaintWindowBackground = cs->PaintWindowBackground;
+ (*pScreen->PaintWindowBackground) (pWin, pRegion, what);
+ cs->PaintWindowBackground = pScreen->PaintWindowBackground;
+ pScreen->PaintWindowBackground = compPaintWindowBackground;
+}
+
+/*
+ * Called after the borderClip for the window has settled down
+ * We use this to make sure our extra borderClip has the right origin
+ */
+
+void
+compClipNotify (WindowPtr pWin, int dx, int dy)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ CompWindowPtr cw = GetCompWindow (pWin);
+
+ if (cw)
+ {
+ if (cw->borderClipX != pWin->drawable.x ||
+ cw->borderClipY != pWin->drawable.y)
+ {
+ REGION_TRANSLATE (pScreen, &cw->borderClip,
+ pWin->drawable.x - cw->borderClipX,
+ pWin->drawable.y - cw->borderClipY);
+ cw->borderClipX = pWin->drawable.x;
+ cw->borderClipY = pWin->drawable.y;
+ }
+ }
+ if (cs->ClipNotify)
+ {
+ pScreen->ClipNotify = cs->ClipNotify;
+ (*pScreen->ClipNotify) (pWin, dx, dy);
+ cs->ClipNotify = pScreen->ClipNotify;
+ pScreen->ClipNotify = compClipNotify;
+ }
+}
+
+/*
+ * Returns TRUE if the window needs server-provided automatic redirect,
+ * which is true if the child and parent aren't both regular or ARGB visuals
+ */
+
+static Bool
+compIsAlternateVisual (ScreenPtr pScreen,
+ XID visual)
+{
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ int i;
+
+ for (i = 0; i < NUM_COMP_ALTERNATE_VISUALS; i++)
+ if (cs->alternateVisuals[i] == visual)
+ return TRUE;
+ return FALSE;
+}
+
+static Bool
+compImplicitRedirect (WindowPtr pWin, WindowPtr pParent)
+{
+ if (pParent)
+ {
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ XID winVisual = wVisual (pWin);
+ XID parentVisual = wVisual (pParent);
+
+ if (winVisual != parentVisual &&
+ (compIsAlternateVisual (pScreen, winVisual) ||
+ compIsAlternateVisual (pScreen, parentVisual)))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+compMoveWindow (WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+
+ compCheckTree (pScreen);
+ if (pWin->redirectDraw)
+ {
+ WindowPtr pParent;
+ int draw_x, draw_y;
+ unsigned int w, h, bw;
+
+ /* if this is a root window, can't be moved */
+ if (!(pParent = pWin->parent))
+ return;
+
+ bw = wBorderWidth (pWin);
+ draw_x = pParent->drawable.x + x + (int)bw;
+ draw_y = pParent->drawable.y + y + (int)bw;
+ w = pWin->drawable.width;
+ h = pWin->drawable.height;
+ compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
+ }
+ compCheckTree (pScreen);
+
+ pScreen->MoveWindow = cs->MoveWindow;
+ (*pScreen->MoveWindow) (pWin, x, y, pSib, kind);
+ cs->MoveWindow = pScreen->MoveWindow;
+ pScreen->MoveWindow = compMoveWindow;
+
+ if (pWin->redirectDraw)
+ {
+ CompWindowPtr cw = GetCompWindow (pWin);
+ if (cw->pOldPixmap)
+ {
+ (*pScreen->DestroyPixmap) (cw->pOldPixmap);
+ cw->pOldPixmap = NullPixmap;
+ }
+ }
+
+ compCheckTree (pScreen);
+}
+
+void
+compResizeWindow (WindowPtr pWin, int x, int y,
+ unsigned int w, unsigned int h, WindowPtr pSib)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+
+ compCheckTree (pScreen);
+ if (pWin->redirectDraw)
+ {
+ WindowPtr pParent;
+ int draw_x, draw_y;
+ unsigned int bw;
+
+ /* if this is a root window, can't be moved */
+ if (!(pParent = pWin->parent))
+ return;
+
+ bw = wBorderWidth (pWin);
+ draw_x = pParent->drawable.x + x + (int)bw;
+ draw_y = pParent->drawable.y + y + (int)bw;
+ compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
+ }
+ compCheckTree (pScreen);
+
+ pScreen->ResizeWindow = cs->ResizeWindow;
+ (*pScreen->ResizeWindow) (pWin, x, y, w, h, pSib);
+ cs->ResizeWindow = pScreen->ResizeWindow;
+ pScreen->ResizeWindow = compResizeWindow;
+ if (pWin->redirectDraw)
+ {
+ CompWindowPtr cw = GetCompWindow (pWin);
+ if (cw->pOldPixmap)
+ {
+ (*pScreen->DestroyPixmap) (cw->pOldPixmap);
+ cw->pOldPixmap = NullPixmap;
+ }
+ }
+ compCheckTree (pWin->drawable.pScreen);
+}
+
+void
+compChangeBorderWidth (WindowPtr pWin, unsigned int bw)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+
+ compCheckTree (pScreen);
+ if (pWin->redirectDraw)
+ {
+ WindowPtr pParent;
+ int draw_x, draw_y;
+ unsigned int w, h;
+
+ /* if this is a root window, can't be moved */
+ if (!(pParent = pWin->parent))
+ return;
+
+ draw_x = pWin->drawable.x;
+ draw_y = pWin->drawable.y;
+ w = pWin->drawable.width;
+ h = pWin->drawable.height;
+ compReallocPixmap (pWin, draw_x, draw_y, w, h, bw);
+ }
+ compCheckTree (pScreen);
+
+ pScreen->ChangeBorderWidth = cs->ChangeBorderWidth;
+ (*pScreen->ChangeBorderWidth) (pWin, bw);
+ cs->ChangeBorderWidth = pScreen->ChangeBorderWidth;
+ pScreen->ChangeBorderWidth = compChangeBorderWidth;
+ if (pWin->redirectDraw)
+ {
+ CompWindowPtr cw = GetCompWindow (pWin);
+ if (cw->pOldPixmap)
+ {
+ (*pScreen->DestroyPixmap) (cw->pOldPixmap);
+ cw->pOldPixmap = NullPixmap;
+ }
+ }
+ compCheckTree (pWin->drawable.pScreen);
+}
+
+void
+compReparentWindow (WindowPtr pWin, WindowPtr pPriorParent)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+
+ pScreen->ReparentWindow = cs->ReparentWindow;
+ /*
+ * Remove any implicit redirect due to synthesized visual
+ */
+ if (compImplicitRedirect (pWin, pPriorParent))
+ compUnredirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
+ /*
+ * Handle subwindows redirection
+ */
+ compUnredirectOneSubwindow (pPriorParent, pWin);
+ compRedirectOneSubwindow (pWin->parent, pWin);
+ /*
+ * Add any implict redirect due to synthesized visual
+ */
+ if (compImplicitRedirect (pWin, pWin->parent))
+ compRedirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
+
+ /*
+ * Allocate any necessary redirect pixmap
+ * (this actually should never be true; pWin is always unmapped)
+ */
+ compCheckRedirect (pWin);
+
+ /*
+ * Reset pixmap pointers as appropriate
+ */
+ if (pWin->parent && !pWin->redirectDraw)
+ compSetPixmap (pWin, (*pScreen->GetWindowPixmap) (pWin->parent));
+ /*
+ * Call down to next function
+ */
+ if (pScreen->ReparentWindow)
+ (*pScreen->ReparentWindow) (pWin, pPriorParent);
+ cs->ReparentWindow = pScreen->ReparentWindow;
+ pScreen->ReparentWindow = compReparentWindow;
+ compCheckTree (pWin->drawable.pScreen);
+}
+
+void
+compCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ int dx = 0, dy = 0;
+
+ if (pWin->redirectDraw)
+ {
+ PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
+ CompWindowPtr cw = GetCompWindow (pWin);
+
+ assert (cw->oldx != COMP_ORIGIN_INVALID);
+ assert (cw->oldy != COMP_ORIGIN_INVALID);
+ if (cw->pOldPixmap)
+ {
+ /*
+ * Ok, the old bits are available in pOldPixmap and
+ * need to be copied to pNewPixmap.
+ */
+ RegionRec rgnDst;
+ PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
+ GCPtr pGC;
+
+ dx = ptOldOrg.x - pWin->drawable.x;
+ dy = ptOldOrg.y - pWin->drawable.y;
+ REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
+
+ REGION_NULL (pWin->drawable.pScreen, &rgnDst);
+
+ REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst,
+ &pWin->borderClip, prgnSrc);
+
+ REGION_TRANSLATE (pWin->drawable.pScreen, &rgnDst,
+ -pPixmap->screen_x, -pPixmap->screen_y);
+
+ dx = dx + pPixmap->screen_x - cw->oldx;
+ dy = dy + pPixmap->screen_y - cw->oldy;
+ pGC = GetScratchGC (pPixmap->drawable.depth, pScreen);
+ if (pGC)
+ {
+ BoxPtr pBox = REGION_RECTS (&rgnDst);
+ int nBox = REGION_NUM_RECTS (&rgnDst);
+
+ ValidateGC(&pPixmap->drawable, pGC);
+ while (nBox--)
+ {
+ (void) (*pGC->ops->CopyArea) (&cw->pOldPixmap->drawable,
+ &pPixmap->drawable,
+ pGC,
+ pBox->x1 + dx, pBox->y1 + dy,
+ pBox->x2 - pBox->x1,
+ pBox->y2 - pBox->y1,
+ pBox->x1, pBox->y1);
+ pBox++;
+ }
+ FreeScratchGC (pGC);
+ }
+ return;
+ }
+ dx = pPixmap->screen_x - cw->oldx;
+ dy = pPixmap->screen_y - cw->oldy;
+ ptOldOrg.x += dx;
+ ptOldOrg.y += dy;
+ }
+
+ pScreen->CopyWindow = cs->CopyWindow;
+ if (ptOldOrg.x != pWin->drawable.x || ptOldOrg.y != pWin->drawable.y)
+ {
+ if (dx || dy)
+ REGION_TRANSLATE (pScreen, prgnSrc, dx, dy);
+ (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc);
+ if (dx || dy)
+ REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
+ }
+ else
+ {
+ ptOldOrg.x -= dx;
+ ptOldOrg.y -= dy;
+ REGION_TRANSLATE (prgnSrc, prgnSrc,
+ pWin->drawable.x - ptOldOrg.x,
+ pWin->drawable.y - ptOldOrg.y);
+ DamageDamageRegion (&pWin->drawable, prgnSrc);
+ }
+ cs->CopyWindow = pScreen->CopyWindow;
+ pScreen->CopyWindow = compCopyWindow;
+ compCheckTree (pWin->drawable.pScreen);
+}
+
+Bool
+compCreateWindow (WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ Bool ret;
+
+ pScreen->CreateWindow = cs->CreateWindow;
+ ret = (*pScreen->CreateWindow) (pWin);
+ if (pWin->parent && ret)
+ {
+ CompSubwindowsPtr csw = GetCompSubwindows (pWin->parent);
+ CompClientWindowPtr ccw;
+
+ (*pScreen->SetWindowPixmap) (pWin, (*pScreen->GetWindowPixmap) (pWin->parent));
+ if (csw)
+ for (ccw = csw->clients; ccw; ccw = ccw->next)
+ compRedirectWindow (clients[CLIENT_ID(ccw->id)],
+ pWin, ccw->update);
+ if (compImplicitRedirect (pWin, pWin->parent))
+ compRedirectWindow (serverClient, pWin, CompositeRedirectAutomatic);
+ }
+ cs->CreateWindow = pScreen->CreateWindow;
+ pScreen->CreateWindow = compCreateWindow;
+ compCheckTree (pWin->drawable.pScreen);
+ return ret;
+}
+
+Bool
+compDestroyWindow (WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ CompScreenPtr cs = GetCompScreen (pScreen);
+ CompWindowPtr cw;
+ CompSubwindowsPtr csw;
+ Bool ret;
+
+ pScreen->DestroyWindow = cs->DestroyWindow;
+ while ((cw = GetCompWindow (pWin)))
+ FreeResource (cw->clients->id, RT_NONE);
+ while ((csw = GetCompSubwindows (pWin)))
+ FreeResource (csw->clients->id, RT_NONE);
+
+ if (pWin->redirectDraw)
+ compFreePixmap (pWin);
+ ret = (*pScreen->DestroyWindow) (pWin);
+ cs->DestroyWindow = pScreen->DestroyWindow;
+ pScreen->DestroyWindow = compDestroyWindow;
+/* compCheckTree (pWin->drawable.pScreen); can't check -- tree isn't good*/
+ return ret;
+}
+
+void
+compSetRedirectBorderClip (WindowPtr pWin, RegionPtr pRegion)
+{
+ CompWindowPtr cw = GetCompWindow (pWin);
+ RegionRec damage;
+
+ REGION_NULL (pScreen, &damage);
+ /*
+ * Align old border clip with new border clip
+ */
+ REGION_TRANSLATE (pScreen, &cw->borderClip,
+ pWin->drawable.x - cw->borderClipX,
+ pWin->drawable.y - cw->borderClipY);
+ /*
+ * Compute newly visible portion of window for repaint
+ */
+ REGION_SUBTRACT (pScreen, &damage, pRegion, &cw->borderClip);
+ /*
+ * Report that as damaged so it will be redrawn
+ */
+ DamageDamageRegion (&pWin->drawable, &damage);
+ REGION_UNINIT (pScreen, &damage);
+ /*
+ * Save the new border clip region
+ */
+ REGION_COPY (pScreen, &cw->borderClip, pRegion);
+ cw->borderClipX = pWin->drawable.x;
+ cw->borderClipY = pWin->drawable.y;
+}
+
+RegionPtr
+compGetRedirectBorderClip (WindowPtr pWin)
+{
+ CompWindowPtr cw = GetCompWindow (pWin);
+
+ return &cw->borderClip;
+}
+
+static VisualPtr
+compGetWindowVisual (WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ VisualID vid = wVisual (pWin);
+ int i;
+
+ for (i = 0; i < pScreen->numVisuals; i++)
+ if (pScreen->visuals[i].vid == vid)
+ return &pScreen->visuals[i];
+ return 0;
+}
+
+static PictFormatPtr
+compWindowFormat (WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+
+ return PictureMatchVisual (pScreen, pWin->drawable.depth,
+ compGetWindowVisual (pWin));
+}
+
+static void
+compWindowUpdateAutomatic (WindowPtr pWin)
+{
+ CompWindowPtr cw = GetCompWindow (pWin);
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ WindowPtr pParent = pWin->parent;
+ PixmapPtr pSrcPixmap = (*pScreen->GetWindowPixmap) (pWin);
+ PictFormatPtr pSrcFormat = compWindowFormat (pWin);
+ PictFormatPtr pDstFormat = compWindowFormat (pWin->parent);
+ int error;
+ RegionPtr pRegion = DamageRegion (cw->damage);
+ PicturePtr pSrcPicture = CreatePicture (0, &pSrcPixmap->drawable,
+ pSrcFormat,
+ 0, 0,
+ serverClient,
+ &error);
+ XID subwindowMode = IncludeInferiors;
+ PicturePtr pDstPicture = CreatePicture (0, &pParent->drawable,
+ pDstFormat,
+ CPSubwindowMode,
+ &subwindowMode,
+ serverClient,
+ &error);
+
+ /*
+ * First move the region from window to screen coordinates
+ */
+ REGION_TRANSLATE (pScreen, pRegion,
+ pWin->drawable.x, pWin->drawable.y);
+
+ /*
+ * Clip against the "real" border clip
+ */
+ REGION_INTERSECT (pScreen, pRegion, pRegion, &cw->borderClip);
+
+ /*
+ * Now translate from screen to dest coordinates
+ */
+ REGION_TRANSLATE (pScreen, pRegion,
+ -pParent->drawable.x, -pParent->drawable.y);
+
+ /*
+ * Clip the picture
+ */
+ SetPictureClipRegion (pDstPicture, 0, 0, pRegion);
+
+ /*
+ * And paint
+ */
+ CompositePicture (PictOpSrc,
+ pSrcPicture,
+ 0,
+ pDstPicture,
+ 0, 0, /* src_x, src_y */
+ 0, 0, /* msk_x, msk_y */
+ pSrcPixmap->screen_x - pParent->drawable.x,
+ pSrcPixmap->screen_y - pParent->drawable.y,
+ pSrcPixmap->drawable.width,
+ pSrcPixmap->drawable.height);
+ FreePicture (pSrcPicture, 0);
+ FreePicture (pDstPicture, 0);
+ /*
+ * Empty the damage region. This has the nice effect of
+ * rendering the translations above harmless
+ */
+ DamageEmpty (cw->damage);
+}
+
+void
+compWindowUpdate (WindowPtr pWin)
+{
+ WindowPtr pChild;
+
+ for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
+ compWindowUpdate (pChild);
+ if (pWin->redirectDraw)
+ {
+ CompWindowPtr cw = GetCompWindow(pWin);
+
+ if (cw->damaged)
+ {
+ compWindowUpdateAutomatic (pWin);
+ cw->damaged = FALSE;
+ }
+ }
+}