#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "compint.h"
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);
cs->damaged = TRUE;
cw->damaged = TRUE;
}
static void
compDestroyDamage (DamagePtr pDamage, void *closure)
{
WindowPtr pWin = (WindowPtr) closure;
CompWindowPtr cw = GetCompWindow (pWin);
cw->damage = 0;
}
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 (cw && update == CompositeRedirectManual)
for (ccw = cw->clients; ccw; ccw = ccw->next)
if (ccw->update == CompositeRedirectManual)
return BadAccess;
ccw = xalloc (sizeof (CompClientWindowRec));
if (!ccw)
return BadAlloc;
ccw->id = FakeClientID (pClient->index);
ccw->update = update;
if (!cw)
{
cw = xalloc (sizeof (CompWindowRec));
if (!cw)
{
xfree (ccw);
return BadAlloc;
}
cw->damage = DamageCreate (compReportDamage,
compDestroyDamage,
DamageReportNonEmpty,
FALSE,
pWin->drawable.pScreen,
pWin);
if (!cw->damage)
{
xfree (ccw);
xfree (cw);
return BadAlloc;
}
if (wasMapped)
{
DisableMapUnmapEvents (pWin);
UnmapWindow (pWin, FALSE);
EnableMapUnmapEvents (pWin);
}
REGION_NULL (pScreen, &cw->borderClip);
cw->update = CompositeRedirectAutomatic;
cw->clients = 0;
cw->oldx = COMP_ORIGIN_INVALID;
cw->oldy = COMP_ORIGIN_INVALID;
cw->damageRegistered = FALSE;
cw->damaged = FALSE;
pWin->devPrivates[CompWindowPrivateIndex].ptr = cw;
}
ccw->next = cw->clients;
cw->clients = ccw;
if (!AddResource (ccw->id, CompositeClientWindowType, pWin))
return BadAlloc;
if (ccw->update == CompositeRedirectManual)
{
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;
}
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;
xfree (ccw);
break;
}
}
if (!cw->clients)
{
if (wasMapped)
{
DisableMapUnmapEvents (pWin);
UnmapWindow (pWin, FALSE);
EnableMapUnmapEvents (pWin);
}
if (pWin->redirectDraw)
compFreePixmap (pWin);
if (cw->damage)
DamageDestroy (cw->damage);
REGION_UNINIT (pScreen, &cw->borderClip);
pWin->devPrivates[CompWindowPrivateIndex].ptr = 0;
xfree (cw);
}
else if (cw->update == CompositeRedirectAutomatic &&
!cw->damageRegistered && pWin->redirectDraw)
{
DamageRegister (&pWin->drawable, cw->damage);
cw->damageRegistered = TRUE;
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;
}
}
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;
}
int
compRedirectSubwindows (ClientPtr pClient, WindowPtr pWin, int update)
{
CompSubwindowsPtr csw = GetCompSubwindows (pWin);
CompClientWindowPtr ccw;
WindowPtr pChild;
if (csw && update == CompositeRedirectManual)
for (ccw = csw->clients; ccw; ccw = ccw->next)
if (ccw->update == CompositeRedirectManual)
return BadAccess;
ccw = xalloc (sizeof (CompClientWindowRec));
if (!ccw)
return BadAlloc;
ccw->id = FakeClientID (pClient->index);
ccw->update = update;
if (!csw)
{
csw = xalloc (sizeof (CompSubwindowsRec));
if (!csw)
{
xfree (ccw);
return BadAlloc;
}
csw->update = CompositeRedirectAutomatic;
csw->clients = 0;
pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = csw;
}
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)
{
xfree (csw);
pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = 0;
}
xfree (ccw);
return ret;
}
}
ccw->next = csw->clients;
csw->clients = ccw;
if (!AddResource (ccw->id, CompositeClientSubwindowsType, pWin))
return BadAlloc;
if (ccw->update == CompositeRedirectManual)
{
csw->update = CompositeRedirectManual;
DamageExtSetCritical (pClient, TRUE);
}
return Success;
}
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)
{
DamageExtSetCritical (pClient, FALSE);
csw->update = CompositeRedirectAutomatic;
if (pWin->mapped)
(*pWin->drawable.pScreen->ClearToBackground)(pWin, 0, 0, 0, 0, TRUE);
}
for (pChild = pWin->lastChild; pChild; pChild = pChild->prevSib)
(void) compUnredirectWindow (pClient, pChild, ccw->update);
xfree (ccw);
break;
}
}
if (!csw->clients)
{
pWin->devPrivates[CompSubwindowsPrivateIndex].ptr = 0;
xfree (csw);
}
}
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;
}
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;
}
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)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
WindowPtr pParent = pWin->parent;
PixmapPtr pPixmap;
GCPtr pGC;
pPixmap = (*pScreen->CreatePixmap) (pScreen, w, h, pWin->drawable.depth);
if (!pPixmap)
return 0;
pPixmap->screen_x = x;
pPixmap->screen_y = y;
pGC = GetScratchGC (pWin->drawable.depth, pScreen);
if (pGC)
{
XID val = IncludeInferiors;
ValidateGC(&pPixmap->drawable, pGC);
dixChangeGC (serverClient, pGC, GCSubwindowMode, &val, NULL);
(*pGC->ops->CopyArea) (&pParent->drawable,
&pPixmap->drawable,
pGC,
x - pParent->drawable.x,
y - pParent->drawable.y,
w, h, 0, 0);
FreeScratchGC (pGC);
}
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);
CompWindowPtr cw = GetCompWindow (pWin);
if (!pPixmap)
return FALSE;
pWin->redirectDraw = TRUE;
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);
}
REGION_COPY (pScreen, &pWin->borderClip, &cw->borderClip);
pRedirectPixmap = (*pScreen->GetWindowPixmap) (pWin);
pParentPixmap = (*pScreen->GetWindowPixmap) (pWin->parent);
pWin->redirectDraw = FALSE;
compSetPixmap (pWin, pParentPixmap);
(*pScreen->DestroyPixmap) (pRedirectPixmap);
}
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);
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);
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;
}