#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stddef.h>
#include <limits.h>
#include <assert.h>
#include "rootlessCommon.h"
#include "rootlessWindow.h"
#include "fb.h"
#ifdef ROOTLESS_GLOBAL_COORDS
#define SCREEN_TO_GLOBAL_X \
(dixScreenOrigins[pScreen->myNum].x + rootlessGlobalOffsetX)
#define SCREEN_TO_GLOBAL_Y \
(dixScreenOrigins[pScreen->myNum].y + rootlessGlobalOffsetY)
#else
#define SCREEN_TO_GLOBAL_X 0
#define SCREEN_TO_GLOBAL_Y 0
#endif
Bool
RootlessCreateWindow(WindowPtr pWin)
{
Bool result;
RegionRec saveRoot;
WINREC(pWin) = NULL;
SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow);
if (!IsRoot(pWin)) {
HUGE_ROOT(pWin);
SetWinSize(pWin);
SetBorderSize(pWin);
}
result = pWin->drawable.pScreen->CreateWindow(pWin);
if (pWin->parent) {
NORMAL_ROOT(pWin);
}
SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow);
return result;
}
static void
RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
SCREENREC(pScreen)->imp->DestroyFrame(winRec->wid);
#ifdef ROOTLESS_TRACK_DAMAGE
REGION_UNINIT(pScreen, &winRec->damage);
#endif
xfree(winRec);
WINREC(pWin) = NULL;
}
Bool
RootlessDestroyWindow(WindowPtr pWin)
{
RootlessWindowRec *winRec = WINREC(pWin);
Bool result;
if (winRec != NULL) {
RootlessDestroyFrame(pWin, winRec);
}
SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
result = pWin->drawable.pScreen->DestroyWindow(pWin);
SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
return result;
}
#ifdef SHAPE
static Bool
RootlessGetShape(WindowPtr pWin, RegionPtr pShape)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
if (wBoundingShape(pWin) == NULL)
return FALSE;
REGION_NULL(pScreen, pShape);
REGION_COPY(pScreen, pShape, wBoundingShape(pWin));
REGION_TRANSLATE(pScreen, pShape, pWin->borderWidth, pWin->borderWidth);
return TRUE;
}
static void RootlessReshapeFrame(WindowPtr pWin)
{
RootlessWindowRec *winRec = WINREC(pWin);
ScreenPtr pScreen = pWin->drawable.pScreen;
RegionRec newShape;
RegionPtr pShape;
if (winRec == NULL)
return;
if (IsRoot(pWin))
return;
RootlessStopDrawing(pWin, FALSE);
pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL;
#ifdef ROOTLESSDEBUG
RL_DEBUG_MSG("reshaping...");
if (pShape != NULL) {
RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ",
REGION_NUM_RECTS(&newShape),
newShape.extents.x1, newShape.extents.y1,
newShape.extents.x2, newShape.extents.y2);
} else {
RL_DEBUG_MSG("no shape ");
}
#endif
SCREENREC(pScreen)->imp->ReshapeFrame(winRec->wid, pShape);
if (pShape != NULL)
REGION_UNINIT(pScreen, &newShape);
}
void
RootlessSetShape(WindowPtr pWin)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
SCREEN_UNWRAP(pScreen, SetShape);
pScreen->SetShape(pWin);
SCREEN_WRAP(pScreen, SetShape);
RootlessReshapeFrame(pWin);
}
#endif // SHAPE
Bool
RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask)
{
Bool result;
ScreenPtr pScreen = pWin->drawable.pScreen;
RL_DEBUG_MSG("change window attributes start ");
SCREEN_UNWRAP(pScreen, ChangeWindowAttributes);
result = pScreen->ChangeWindowAttributes(pWin, vmask);
SCREEN_WRAP(pScreen, ChangeWindowAttributes);
if (WINREC(pWin)) {
if (pWin->backgroundState == ParentRelative) {
XID pixel = 0;
ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
}
}
RL_DEBUG_MSG("change window attributes end\n");
return result;
}
Bool
RootlessPositionWindow(WindowPtr pWin, int x, int y)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RootlessWindowRec *winRec = WINREC(pWin);
Bool result;
RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y);
if (winRec) {
if (winRec->is_drawing) {
int bw = wBorderWidth(pWin);
winRec->pixmap->devPrivate.ptr = winRec->pixelData;
SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw);
#ifdef ROOTLESS_TRACK_DAMAGE
if (REGION_NOTEMPTY(pScreen, &winRec->damage)) {
REGION_TRANSLATE(pScreen, &winRec->damage,
x - bw - winRec->x,
y - bw - winRec->y);
}
#endif
}
}
SCREEN_UNWRAP(pScreen, PositionWindow);
result = pScreen->PositionWindow(pWin, x, y);
SCREEN_WRAP(pScreen, PositionWindow);
RL_DEBUG_MSG("positionwindow end\n");
return result;
}
static void
RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec *winRec)
{
DrawablePtr d = &pWin->drawable;
int bw = wBorderWidth(pWin);
winRec->win = pWin;
winRec->x = d->x - bw;
winRec->y = d->y - bw;
winRec->width = d->width + 2*bw;
winRec->height = d->height + 2*bw;
winRec->borderWidth = bw;
#ifdef ROOTLESS_TRACK_DAMAGE
REGION_NULL(pScreen, &winRec->damage);
#endif
}
static RootlessWindowRec *
RootlessEnsureFrame(WindowPtr pWin)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RootlessWindowRec *winRec;
#ifdef SHAPE
RegionRec shape;
#endif
RegionPtr pShape = NULL;
if (WINREC(pWin) != NULL)
return WINREC(pWin);
if (!IsTopLevel(pWin))
return NULL;
if (pWin->drawable.class != InputOutput)
return NULL;
winRec = xalloc(sizeof(RootlessWindowRec));
if (!winRec)
return NULL;
RootlessInitializeFrame(pWin, winRec);
winRec->is_drawing = FALSE;
winRec->is_reorder_pending = FALSE;
winRec->pixmap = NULL;
winRec->wid = NULL;
WINREC(pWin) = winRec;
#ifdef SHAPE
if (RootlessGetShape(pWin, &shape))
pShape = &shape;
#endif
RL_DEBUG_MSG("creating frame ");
if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen,
winRec->x + SCREEN_TO_GLOBAL_X,
winRec->y + SCREEN_TO_GLOBAL_Y,
pShape))
{
RL_DEBUG_MSG("implementation failed to create frame!\n");
xfree(winRec);
WINREC(pWin) = NULL;
return NULL;
}
#ifdef SHAPE
if (pShape != NULL)
REGION_UNINIT(pScreen, &shape);
#endif
return winRec;
}
Bool
RootlessRealizeWindow(WindowPtr pWin)
{
Bool result;
RegionRec saveRoot;
ScreenPtr pScreen = pWin->drawable.pScreen;
RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin);
if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) {
RootlessWindowRec *winRec;
winRec = RootlessEnsureFrame(pWin);
if (winRec == NULL)
return FALSE;
winRec->is_reorder_pending = TRUE;
RL_DEBUG_MSG("Top level window ");
if (pWin->backgroundState == ParentRelative) {
XID pixel = 0;
ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
}
}
if (!IsRoot(pWin)) HUGE_ROOT(pWin);
SCREEN_UNWRAP(pScreen, RealizeWindow);
result = pScreen->RealizeWindow(pWin);
SCREEN_WRAP(pScreen, RealizeWindow);
if (!IsRoot(pWin)) NORMAL_ROOT(pWin);
RL_DEBUG_MSG("realizewindow end\n");
return result;
}
RootlessFrameID
RootlessFrameForWindow(WindowPtr pWin, Bool create)
{
WindowPtr pTopWin;
RootlessWindowRec *winRec;
pTopWin = TopLevelParent(pWin);
if (pTopWin == NULL)
return NULL;
winRec = WINREC(pTopWin);
if (winRec == NULL && create && pWin->drawable.class == InputOutput) {
winRec = RootlessEnsureFrame(pTopWin);
}
if (winRec == NULL)
return NULL;
return winRec->wid;
}
Bool
RootlessUnrealizeWindow(WindowPtr pWin)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RootlessWindowRec *winRec = WINREC(pWin);
Bool result;
RL_DEBUG_MSG("unrealizewindow start ");
if (winRec) {
RootlessStopDrawing(pWin, FALSE);
SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
winRec->is_reorder_pending = FALSE;
}
SCREEN_UNWRAP(pScreen, UnrealizeWindow);
result = pScreen->UnrealizeWindow(pWin);
SCREEN_WRAP(pScreen, UnrealizeWindow);
RL_DEBUG_MSG("unrealizewindow end\n");
return result;
}
void
RootlessReorderWindow(WindowPtr pWin)
{
RootlessWindowRec *winRec = WINREC(pWin);
if (winRec != NULL && !winRec->is_reorder_pending) {
WindowPtr newPrevW;
RootlessWindowRec *newPrev;
RootlessFrameID newPrevID;
ScreenPtr pScreen = pWin->drawable.pScreen;
if (SCREENREC(pScreen)->imp->DoReorderWindow) {
if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec))
return;
}
RootlessStopDrawing(pWin, FALSE);
newPrevW = pWin->prevSib;
while (newPrevW && (WINREC(newPrevW) == NULL || !newPrevW->realized))
newPrevW = newPrevW->prevSib;
newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
newPrevID = newPrev != NULL ? newPrev->wid : 0;
if (newPrev && newPrev->is_reorder_pending) {
newPrev->is_reorder_pending = FALSE;
RootlessReorderWindow(newPrevW);
}
SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
}
}
void
RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
{
RegionRec saveRoot;
RootlessWindowRec *winRec = WINREC(pWin);
ScreenPtr pScreen = pWin->drawable.pScreen;
RL_DEBUG_MSG("restackwindow start ");
if (winRec)
RL_DEBUG_MSG("restack top level \n");
HUGE_ROOT(pWin);
SCREEN_UNWRAP(pScreen, RestackWindow);
if (pScreen->RestackWindow)
pScreen->RestackWindow(pWin, pOldNextSib);
SCREEN_WRAP(pScreen, RestackWindow);
NORMAL_ROOT(pWin);
if (winRec && pWin->viewable) {
RootlessReorderWindow(pWin);
}
RL_DEBUG_MSG("restackwindow end\n");
}
static pointer gResizeDeathBits = NULL;
static int gResizeDeathCount = 0;
static PixmapPtr gResizeDeathPix[2] = {NULL, NULL};
static BoxRec gResizeDeathBounds[2];
static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
static void
RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
RegionPtr prgnSrc)
{
int dx = ptOldOrg.x - pWin->drawable.x;
int dy = ptOldOrg.y - pWin->drawable.y;
RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW ");
REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
}
static void
RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
RegionPtr prgnSrc)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RegionRec rgnDst;
int dx, dy;
RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
if (gResizeDeathCount == 0)
return;
RootlessStartDrawing(pWin);
dx = ptOldOrg.x - pWin->drawable.x;
dy = ptOldOrg.y - pWin->drawable.y;
REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
REGION_NULL(pScreen, &rgnDst);
REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
if (gResizeDeathCount == 1) {
fbCopyRegion(&gResizeDeathPix[0]->drawable,
&pScreen->GetWindowPixmap(pWin)->drawable, 0,
&rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
}
else {
int i;
RegionRec clip, clipped;
for (i = 0; i < gResizeDeathCount; i++) {
REGION_INIT(pScreen, &clip, gResizeDeathBounds + 0, 1);
REGION_NULL(pScreen, &clipped);
REGION_INTERSECT(pScreen, &rgnDst, &clip, &clipped);
fbCopyRegion(&gResizeDeathPix[i]->drawable,
&pScreen->GetWindowPixmap(pWin)->drawable, 0,
&clipped, dx, dy, fbCopyWindowProc, 0, 0);
REGION_UNINIT(pScreen, &clipped);
REGION_UNINIT(pScreen, &clip);
}
}
REGION_UNINIT(pScreen, &rgnDst);
fbValidateDrawable(&pWin->drawable);
RL_DEBUG_MSG("resizecopywindowFB end\n");
}
void
RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RegionRec rgnDst;
int dx, dy;
BoxPtr extents;
int area;
RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin);
SCREEN_UNWRAP(pScreen, CopyWindow);
dx = ptOldOrg.x - pWin->drawable.x;
dy = ptOldOrg.y - pWin->drawable.y;
REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
REGION_NULL(pScreen, &rgnDst);
REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
extents = REGION_EXTENTS(pScreen, &rgnDst);
area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
if (area > rootless_CopyWindow_threshold &&
SCREENREC(pScreen)->imp->CopyWindow)
{
RootlessWindowRec *winRec;
WindowPtr top;
top = TopLevelParent(pWin);
if (top == NULL) {
RL_DEBUG_MSG("no parent\n");
return;
}
winRec = WINREC(top);
if (winRec == NULL) {
RL_DEBUG_MSG("not framed\n");
return;
}
REGION_TRANSLATE(pScreen, &rgnDst, -winRec->x, -winRec->y);
RootlessStopDrawing(pWin, FALSE);
SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
REGION_NUM_RECTS(&rgnDst),
REGION_RECTS(&rgnDst),
dx, dy);
}
else {
RootlessStartDrawing(pWin);
fbCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
RootlessDamageRegion(pWin, prgnSrc);
}
REGION_UNINIT(pScreen, &rgnDst);
fbValidateDrawable(&pWin->drawable);
SCREEN_WRAP(pScreen, CopyWindow);
RL_DEBUG_MSG("copywindowFB end\n");
}
enum {
WIDTH_SMALLER = 1,
HEIGHT_SMALLER = 2,
};
static inline unsigned int
ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
int newX1, int newY1, int newX2, int newY2, int newBW)
{
#ifdef ROOTLESS_RESIZE_GRAVITY
if (newBW != oldBW)
return RL_GRAVITY_NONE;
if (newX1 == oldX1 && newY1 == oldY1)
return RL_GRAVITY_NORTH_WEST;
else if (newX1 == oldX1 && newY2 == oldY2)
return RL_GRAVITY_SOUTH_WEST;
else if (newX2 == oldX2 && newY2 == oldY2)
return RL_GRAVITY_SOUTH_EAST;
else if (newX2 == oldX2 && newY1 == oldY1)
return RL_GRAVITY_NORTH_EAST;
else
return RL_GRAVITY_NONE;
#else
return RL_GRAVITY_NONE;
#endif
}
static Bool
StartFrameResize(WindowPtr pWin, Bool gravity,
int oldX, int oldY, int oldW, int oldH, int oldBW,
int newX, int newY, int newW, int newH, int newBW)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RootlessWindowRec *winRec = WINREC(pWin);
Bool need_window_source = FALSE, resize_after = FALSE;
BoxRec rect;
int oldX2, newX2;
int oldY2, newY2;
unsigned int weight;
oldX2 = oldX + oldW, newX2 = newX + newW;
oldY2 = oldY + oldH, newY2 = newY + newH;
weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW);
rect.x1 = max(oldX, newX);
rect.y1 = max(oldY, newY);
rect.x2 = min(oldX2, newX2);
rect.y2 = min(oldY2, newY2);
RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n",
oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW);
RootlessRedisplay(pWin);
gResizeDeathCount = 0;
if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
unsigned int code = 0;
need_window_source = TRUE;
if (newW < oldW)
code |= WIDTH_SMALLER;
if (newH < oldH)
code |= HEIGHT_SMALLER;
if (((code ^ (code >> 1)) & 1) == 0) {
if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
resize_after = TRUE;
}
gResizeDeathCount = 1;
}
else {
unsigned int copy_rowbytes, Bpp;
unsigned int copy_rect_width, copy_rect_height;
BoxRec copy_rect;
RootlessStartDrawing(pWin);
if (code == WIDTH_SMALLER) {
copy_rect.x1 = rect.x2;
copy_rect.y1 = rect.y1;
copy_rect.x2 = oldX2;
copy_rect.y2 = oldY2;
}
else if (code == HEIGHT_SMALLER) {
copy_rect.x1 = rect.x1;
copy_rect.y1 = rect.y2;
copy_rect.x2 = oldX2;
copy_rect.y2 = oldY2;
}
else
abort();
Bpp = winRec->win->drawable.bitsPerPixel / 8;
copy_rect_width = copy_rect.x2 - copy_rect.x1;
copy_rect_height = copy_rect.y2 - copy_rect.y1;
copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
gResizeDeathBits = xalloc(copy_rowbytes
* copy_rect_height);
if (copy_rect_width * copy_rect_height >
rootless_CopyBytes_threshold &&
SCREENREC(pScreen)->imp->CopyBytes)
{
SCREENREC(pScreen)->imp->CopyBytes(
copy_rect_width * Bpp, copy_rect_height,
((char *) winRec->pixelData)
+ ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
+ (copy_rect.x1 - oldX) * Bpp, winRec->bytesPerRow,
gResizeDeathBits, copy_rowbytes);
} else {
fbBlt((FbBits *) (winRec->pixelData
+ ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
+ (copy_rect.x1 - oldX) * Bpp),
winRec->bytesPerRow / sizeof(FbBits), 0,
(FbBits *) gResizeDeathBits,
copy_rowbytes / sizeof(FbBits), 0,
copy_rect_width * Bpp, copy_rect_height,
GXcopy, FB_ALLONES, Bpp, 0, 0);
}
gResizeDeathBounds[1] = copy_rect;
gResizeDeathPix[1]
= GetScratchPixmapHeader(pScreen, copy_rect_width,
copy_rect_height,
winRec->win->drawable.depth,
winRec->win->drawable.bitsPerPixel,
winRec->bytesPerRow,
(void *) gResizeDeathBits);
SetPixmapBaseToScreen(gResizeDeathPix[1],
copy_rect.x1, copy_rect.y1);
gResizeDeathCount = 2;
}
}
else if (gravity) {
RootlessStartDrawing(pWin);
gResizeDeathBits = xalloc(winRec->bytesPerRow * winRec->height);
memcpy(gResizeDeathBits, winRec->pixelData,
winRec->bytesPerRow * winRec->height);
gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
gResizeDeathPix[0]
= GetScratchPixmapHeader(pScreen, winRec->width,
winRec->height,
winRec->win->drawable.depth,
winRec->win->drawable.bitsPerPixel,
winRec->bytesPerRow,
(void *) gResizeDeathBits);
SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
gResizeDeathCount = 1;
}
RootlessStopDrawing(pWin, FALSE);
winRec->x = newX;
winRec->y = newY;
winRec->width = newW;
winRec->height = newH;
winRec->borderWidth = newBW;
if (!resize_after) {
SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
newX + SCREEN_TO_GLOBAL_X,
newY + SCREEN_TO_GLOBAL_Y,
newW, newH, weight);
}
RootlessStartDrawing(pWin);
if (need_window_source) {
gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
gResizeDeathPix[0]
= GetScratchPixmapHeader(pScreen, oldW, oldH,
winRec->win->drawable.depth,
winRec->win->drawable.bitsPerPixel,
winRec->bytesPerRow, winRec->pixelData);
SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
}
if (gravity) {
gResizeOldCopyWindowProc = pScreen->CopyWindow;
pScreen->CopyWindow = RootlessResizeCopyWindow;
}
if (gravity && weight == RL_GRAVITY_NONE) {
PixmapPtr src, dst;
assert(gResizeDeathCount == 1);
src = gResizeDeathPix[0];
dst = pScreen->GetWindowPixmap(pWin);
RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
rect.x1, rect.y1, rect.x2, rect.y2);
if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
SetPixmapBaseToScreen(dst, newX, newY);
fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
&rect, 1, 0, 0, FALSE, FALSE, 0, 0);
((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
SetPixmapBaseToScreen(dst, oldX, oldY);
}
}
return resize_after;
}
static void
FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
unsigned int oldW, unsigned int oldH, unsigned int oldBW,
int newX, int newY, unsigned int newW, unsigned int newH,
unsigned int newBW, Bool resize_now)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RootlessWindowRec *winRec = WINREC(pWin);
int i;
RootlessStopDrawing(pWin, FALSE);
if (resize_now) {
unsigned int weight;
weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW);
SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
newX + SCREEN_TO_GLOBAL_X,
newY + SCREEN_TO_GLOBAL_Y,
newW, newH, weight);
}
RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
for (i = 0; i < 2; i++) {
if (gResizeDeathPix[i] != NULL) {
FreeScratchPixmapHeader(gResizeDeathPix[i]);
gResizeDeathPix[i] = NULL;
}
}
if (gResizeDeathBits != NULL) {
xfree(gResizeDeathBits);
gResizeDeathBits = NULL;
}
if (gravity) {
pScreen->CopyWindow = gResizeOldCopyWindowProc;
}
}
void
RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
{
RootlessWindowRec *winRec = WINREC(pWin);
ScreenPtr pScreen = pWin->drawable.pScreen;
CopyWindowProcPtr oldCopyWindowProc = NULL;
int oldX = 0, oldY = 0, newX = 0, newY = 0;
unsigned int oldW = 0, oldH = 0, oldBW = 0;
unsigned int newW = 0, newH = 0, newBW = 0;
Bool resize_after = FALSE;
RegionRec saveRoot;
RL_DEBUG_MSG("movewindow start \n");
if (winRec) {
if (kind == VTMove) {
oldX = winRec->x;
oldY = winRec->y;
RootlessRedisplay(pWin);
RootlessStartDrawing(pWin);
} else {
RL_DEBUG_MSG("movewindow border resizing ");
oldBW = winRec->borderWidth;
oldX = winRec->x;
oldY = winRec->y;
oldW = winRec->width;
oldH = winRec->height;
newBW = wBorderWidth(pWin);
newX = x;
newY = y;
newW = pWin->drawable.width + 2*newBW;
newH = pWin->drawable.height + 2*newBW;
resize_after = StartFrameResize(pWin, FALSE,
oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW);
}
}
HUGE_ROOT(pWin);
SCREEN_UNWRAP(pScreen, MoveWindow);
if (winRec) {
oldCopyWindowProc = pScreen->CopyWindow;
pScreen->CopyWindow = RootlessNoCopyWindow;
}
pScreen->MoveWindow(pWin, x, y, pSib, kind);
if (winRec) {
pScreen->CopyWindow = oldCopyWindowProc;
}
NORMAL_ROOT(pWin);
SCREEN_WRAP(pScreen, MoveWindow);
if (winRec) {
if (kind == VTMove) {
winRec->x = x;
winRec->y = y;
RootlessStopDrawing(pWin, FALSE);
SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
x + SCREEN_TO_GLOBAL_X,
y + SCREEN_TO_GLOBAL_Y);
} else {
FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW, resize_after);
}
}
RL_DEBUG_MSG("movewindow end\n");
}
void
RootlessResizeWindow(WindowPtr pWin, int x, int y,
unsigned int w, unsigned int h, WindowPtr pSib)
{
RootlessWindowRec *winRec = WINREC(pWin);
ScreenPtr pScreen = pWin->drawable.pScreen;
int oldX = 0, oldY = 0, newX = 0, newY = 0;
unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
Bool resize_after = FALSE;
RegionRec saveRoot;
RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
if (winRec) {
oldBW = winRec->borderWidth;
oldX = winRec->x;
oldY = winRec->y;
oldW = winRec->width;
oldH = winRec->height;
newBW = oldBW;
newX = x;
newY = y;
newW = w + 2*newBW;
newH = h + 2*newBW;
resize_after = StartFrameResize(pWin, TRUE,
oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW);
}
HUGE_ROOT(pWin);
SCREEN_UNWRAP(pScreen, ResizeWindow);
pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
SCREEN_WRAP(pScreen, ResizeWindow);
NORMAL_ROOT(pWin);
if (winRec) {
FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW, resize_after);
}
RL_DEBUG_MSG("resizewindow end\n");
}
void
RootlessRepositionWindow(WindowPtr pWin)
{
RootlessWindowRec *winRec = WINREC(pWin);
ScreenPtr pScreen = pWin->drawable.pScreen;
if (winRec == NULL)
return;
RootlessStopDrawing(pWin, FALSE);
SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
winRec->x + SCREEN_TO_GLOBAL_X,
winRec->y + SCREEN_TO_GLOBAL_Y);
RootlessReorderWindow(pWin);
}
void
RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
RootlessWindowRec *winRec = WINREC(pWin);
WindowPtr pTopWin;
if (IsRoot(pWin) || IsRoot(pWin->parent)
|| IsTopLevel(pWin) || winRec == NULL)
{
goto out;
}
pTopWin = TopLevelParent(pWin);
assert(pTopWin != pWin);
if (WINREC(pTopWin) != NULL) {
RootlessDestroyFrame(pWin, winRec);
} else {
if (!pTopWin->realized && pWin->realized) {
SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
}
WINREC(pWin) = NULL;
WINREC(pTopWin) = winRec;
RootlessInitializeFrame(pTopWin, winRec);
RootlessReshapeFrame(pTopWin);
SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
winRec->x + SCREEN_TO_GLOBAL_X,
winRec->y + SCREEN_TO_GLOBAL_Y,
winRec->width, winRec->height,
RL_GRAVITY_NONE);
if (SCREENREC(pScreen)->imp->SwitchWindow) {
SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
}
if (pTopWin->realized && !pWin->realized)
winRec->is_reorder_pending = TRUE;
}
out:
if (SCREENREC(pScreen)->ReparentWindow) {
SCREEN_UNWRAP(pScreen, ReparentWindow);
pScreen->ReparentWindow(pWin, pPriorParent);
SCREEN_WRAP(pScreen, ReparentWindow);
}
}
static void
SetPixmapOfAncestors(WindowPtr pWin)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
WindowPtr topWin = TopLevelParent(pWin);
RootlessWindowRec *topWinRec = WINREC(topWin);
while (pWin->backgroundState == ParentRelative) {
if (pWin == topWin) {
XID pixel = 0;
ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
break;
}
pWin = pWin->parent;
pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
}
}
void
RootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
if (IsRoot(pWin))
return;
RL_DEBUG_MSG("paintwindowbackground start (win 0x%x, framed %i) ",
pWin, IsFramedWindow(pWin));
if (IsFramedWindow(pWin)) {
RootlessStartDrawing(pWin);
RootlessDamageRegion(pWin, pRegion);
if (pWin->backgroundState == ParentRelative) {
SetPixmapOfAncestors(pWin);
}
}
SCREEN_UNWRAP(pScreen, PaintWindowBackground);
pScreen->PaintWindowBackground(pWin, pRegion, what);
SCREEN_WRAP(pScreen, PaintWindowBackground);
RL_DEBUG_MSG("paintwindowbackground end\n");
}
void
RootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what)
{
RL_DEBUG_MSG("paintwindowborder start (win 0x%x) ", pWin);
if (IsFramedWindow(pWin)) {
RootlessStartDrawing(pWin);
RootlessDamageRegion(pWin, pRegion);
if (!pWin->borderIsPixel &&
pWin->backgroundState == ParentRelative)
{
SetPixmapOfAncestors(pWin);
}
}
SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder);
pWin->drawable.pScreen->PaintWindowBorder(pWin, pRegion, what);
SCREEN_WRAP(pWin->drawable.pScreen, PaintWindowBorder);
RL_DEBUG_MSG("paintwindowborder end\n");
}
void
RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
{
RegionRec saveRoot;
Bool resize_after = FALSE;
RL_DEBUG_MSG("change border width ");
if (width != wBorderWidth(pWin)) {
RootlessWindowRec *winRec = WINREC(pWin);
int oldX = 0, oldY = 0, newX = 0, newY = 0;
unsigned int oldW = 0, oldH = 0, oldBW = 0;
unsigned int newW = 0, newH = 0, newBW = 0;
if (winRec) {
oldBW = winRec->borderWidth;
oldX = winRec->x;
oldY = winRec->y;
oldW = winRec->width;
oldH = winRec->height;
newBW = width;
newX = pWin->drawable.x - newBW;
newY = pWin->drawable.y - newBW;
newW = pWin->drawable.width + 2*newBW;
newH = pWin->drawable.height + 2*newBW;
resize_after = StartFrameResize(pWin, FALSE,
oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW);
}
HUGE_ROOT(pWin);
SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
NORMAL_ROOT(pWin);
if (winRec) {
FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
newX, newY, newW, newH, newBW, resize_after);
}
}
RL_DEBUG_MSG("change border width end\n");
}