825 lines
23 KiB
C
825 lines
23 KiB
C
/*
|
|
* Copyright © 2006 Sun Microsystems, 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 (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"
|
|
|
|
#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 == RedirectDrawNone);
|
|
assert (pWinPixmap == pScreenPixmap);
|
|
}
|
|
else if (pWin->redirectDraw != RedirectDrawNone)
|
|
{
|
|
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;
|
|
int rc = dixLookupWindow(&pWindow, (XID)(intptr_t)closure, pClient, DixWriteAccess);
|
|
|
|
if (rc == Success) {
|
|
RegionRec exposed;
|
|
|
|
REGION_NULL(pScreen, &exposed);
|
|
REGION_SUBTRACT(pScreen, &exposed, &pWindow->borderClip, &pWindow->winSize);
|
|
miPaintWindow(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 != RedirectDrawNone)
|
|
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)(intptr_t) 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);
|
|
CompScreenPtr cs = GetCompScreen(pWin->drawable.pScreen);
|
|
Bool should;
|
|
|
|
should = pWin->realized && (pWin->drawable.class != InputOnly) &&
|
|
(cw != NULL) && (pWin->parent != NULL);
|
|
|
|
/* Never redirect the overlay window */
|
|
if (cs->pOverlayWin != NULL) {
|
|
if (pWin == cs->pOverlayWin) {
|
|
should = FALSE;
|
|
}
|
|
}
|
|
|
|
if (should != (pWin->redirectDraw != RedirectDrawNone))
|
|
{
|
|
if (should)
|
|
return compAllocPixmap (pWin);
|
|
else
|
|
compFreePixmap (pWin);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
updateOverlayWindow(ScreenPtr pScreen)
|
|
{
|
|
CompScreenPtr cs;
|
|
WindowPtr pWin; /* overlay window */
|
|
XID vlist[2];
|
|
|
|
cs = GetCompScreen(pScreen);
|
|
if ((pWin = cs->pOverlayWin) != NULL) {
|
|
if ((pWin->drawable.width == pScreen->width) &&
|
|
(pWin->drawable.height == pScreen->height))
|
|
return Success;
|
|
|
|
/* Let's resize the overlay window. */
|
|
vlist[0] = pScreen->width;
|
|
vlist[1] = pScreen->height;
|
|
return ConfigureWindow(pWin, CWWidth | CWHeight, vlist, wClient(pWin));
|
|
}
|
|
|
|
/* Let's be on the safe side and not assume an overlay window is always allocated. */
|
|
return Success;
|
|
}
|
|
|
|
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 != RedirectDrawNone) !=
|
|
(pWin->viewable && (GetCompWindow(pWin) != NULL)))
|
|
OsAbort ();
|
|
#endif
|
|
if (pWin->redirectDraw != RedirectDrawNone)
|
|
{
|
|
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);
|
|
if (updateOverlayWindow(pScreen) != Success)
|
|
ret = FALSE;
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* 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 < cs->numAlternateVisuals; 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 != RedirectDrawNone)
|
|
{
|
|
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 != RedirectDrawNone)
|
|
{
|
|
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 != RedirectDrawNone)
|
|
{
|
|
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 != RedirectDrawNone)
|
|
{
|
|
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 != RedirectDrawNone)
|
|
{
|
|
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 != RedirectDrawNone)
|
|
{
|
|
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 == RedirectDrawNone)
|
|
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 != RedirectDrawNone)
|
|
{
|
|
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);
|
|
DamageRegionAppend(&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 != RedirectDrawNone)
|
|
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
|
|
*/
|
|
DamageRegionAppend(&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;
|
|
}
|
|
|
|
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 != RedirectDrawNone)
|
|
{
|
|
CompWindowPtr cw = GetCompWindow(pWin);
|
|
|
|
if (cw->damaged)
|
|
{
|
|
compWindowUpdateAutomatic (pWin);
|
|
cw->damaged = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
WindowPtr
|
|
CompositeRealChildHead (WindowPtr pWin)
|
|
{
|
|
WindowPtr pChild, pChildBefore;
|
|
CompScreenPtr cs;
|
|
|
|
if (!pWin->parent &&
|
|
(screenIsSaved == SCREEN_SAVER_ON) &&
|
|
(HasSaverWindow (pWin->drawable.pScreen->myNum))) {
|
|
|
|
/* First child is the screen saver; see if next child is the overlay */
|
|
pChildBefore = pWin->firstChild;
|
|
pChild = pChildBefore->nextSib;
|
|
|
|
} else {
|
|
pChildBefore = NullWindow;
|
|
pChild = pWin->firstChild;
|
|
}
|
|
|
|
if (!pChild) {
|
|
return NullWindow;
|
|
}
|
|
|
|
cs = GetCompScreen(pWin->drawable.pScreen);
|
|
if (pChild == cs->pOverlayWin) {
|
|
return pChild;
|
|
} else {
|
|
return pChildBefore;
|
|
}
|
|
}
|