Initial commit
[xorg_rtime.git] / xorg-server-1.4 / miext / rootless / rootlessWindow.c
blob30b7daaab0b5ad65c05a03922f3273b19ac26e69
1 /*
2 * Rootless window management
3 */
4 /*
5 * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6 * Copyright (c) 2002-2004 Torrey T. Lyons. All Rights Reserved.
7 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the sale,
29 * use or other dealings in this Software without prior written authorization.
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
34 #endif
36 #include <stddef.h> /* For NULL */
37 #include <limits.h> /* For CHAR_BIT */
38 #include <assert.h>
40 #include "rootlessCommon.h"
41 #include "rootlessWindow.h"
43 #include "fb.h"
46 #ifdef ROOTLESS_GLOBAL_COORDS
47 #define SCREEN_TO_GLOBAL_X \
48 (dixScreenOrigins[pScreen->myNum].x + rootlessGlobalOffsetX)
49 #define SCREEN_TO_GLOBAL_Y \
50 (dixScreenOrigins[pScreen->myNum].y + rootlessGlobalOffsetY)
51 #else
52 #define SCREEN_TO_GLOBAL_X 0
53 #define SCREEN_TO_GLOBAL_Y 0
54 #endif
58 * RootlessCreateWindow
59 * For now, don't create a physical window until either the window is
60 * realized, or we really need it (e.g. to attach VRAM surfaces to).
61 * Do reset the window size so it's not clipped by the root window.
63 Bool
64 RootlessCreateWindow(WindowPtr pWin)
66 Bool result;
67 RegionRec saveRoot;
69 WINREC(pWin) = NULL;
71 SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow);
73 if (!IsRoot(pWin)) {
74 /* win/border size set by DIX, not by wrapped CreateWindow, so
75 correct it here. Don't HUGE_ROOT when pWin is the root! */
77 HUGE_ROOT(pWin);
78 SetWinSize(pWin);
79 SetBorderSize(pWin);
82 result = pWin->drawable.pScreen->CreateWindow(pWin);
84 if (pWin->parent) {
85 NORMAL_ROOT(pWin);
88 SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow);
90 return result;
95 * RootlessDestroyFrame
96 * Destroy the physical window associated with the given window.
98 static void
99 RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec)
101 ScreenPtr pScreen = pWin->drawable.pScreen;
103 SCREENREC(pScreen)->imp->DestroyFrame(winRec->wid);
105 #ifdef ROOTLESS_TRACK_DAMAGE
106 REGION_UNINIT(pScreen, &winRec->damage);
107 #endif
109 xfree(winRec);
110 WINREC(pWin) = NULL;
115 * RootlessDestroyWindow
116 * Destroy the physical window associated with the given window.
118 Bool
119 RootlessDestroyWindow(WindowPtr pWin)
121 RootlessWindowRec *winRec = WINREC(pWin);
122 Bool result;
124 if (winRec != NULL) {
125 RootlessDestroyFrame(pWin, winRec);
128 SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
129 result = pWin->drawable.pScreen->DestroyWindow(pWin);
130 SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
132 return result;
136 #ifdef SHAPE
138 static Bool
139 RootlessGetShape(WindowPtr pWin, RegionPtr pShape)
141 ScreenPtr pScreen = pWin->drawable.pScreen;
143 if (wBoundingShape(pWin) == NULL)
144 return FALSE;
146 /* wBoundingShape is relative to *inner* origin of window.
147 Translate by borderWidth to get the outside-relative position. */
149 REGION_NULL(pScreen, pShape);
150 REGION_COPY(pScreen, pShape, wBoundingShape(pWin));
151 REGION_TRANSLATE(pScreen, pShape, pWin->borderWidth, pWin->borderWidth);
153 return TRUE;
158 * RootlessReshapeFrame
159 * Set the frame shape.
161 static void RootlessReshapeFrame(WindowPtr pWin)
163 RootlessWindowRec *winRec = WINREC(pWin);
164 ScreenPtr pScreen = pWin->drawable.pScreen;
165 RegionRec newShape;
166 RegionPtr pShape;
168 // If the window is not yet framed, do nothing
169 if (winRec == NULL)
170 return;
172 if (IsRoot(pWin))
173 return;
175 RootlessStopDrawing(pWin, FALSE);
177 pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL;
179 #ifdef ROOTLESSDEBUG
180 RL_DEBUG_MSG("reshaping...");
181 if (pShape != NULL) {
182 RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ",
183 REGION_NUM_RECTS(&newShape),
184 newShape.extents.x1, newShape.extents.y1,
185 newShape.extents.x2, newShape.extents.y2);
186 } else {
187 RL_DEBUG_MSG("no shape ");
189 #endif
191 SCREENREC(pScreen)->imp->ReshapeFrame(winRec->wid, pShape);
193 if (pShape != NULL)
194 REGION_UNINIT(pScreen, &newShape);
199 * RootlessSetShape
200 * Shape is usually set before a window is mapped and the window will
201 * not have a frame associated with it. In this case, the frame will be
202 * shaped when the window is framed.
204 void
205 RootlessSetShape(WindowPtr pWin)
207 ScreenPtr pScreen = pWin->drawable.pScreen;
209 SCREEN_UNWRAP(pScreen, SetShape);
210 pScreen->SetShape(pWin);
211 SCREEN_WRAP(pScreen, SetShape);
213 RootlessReshapeFrame(pWin);
216 #endif // SHAPE
219 /* Disallow ParentRelative background on top-level windows
220 because the root window doesn't really have the right background
221 and fb will try to draw on the root instead of on the window.
222 ParentRelative prevention is also in PaintWindowBackground/Border()
223 so it is no longer really needed here. */
224 Bool
225 RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask)
227 Bool result;
228 ScreenPtr pScreen = pWin->drawable.pScreen;
230 RL_DEBUG_MSG("change window attributes start ");
232 SCREEN_UNWRAP(pScreen, ChangeWindowAttributes);
233 result = pScreen->ChangeWindowAttributes(pWin, vmask);
234 SCREEN_WRAP(pScreen, ChangeWindowAttributes);
236 if (WINREC(pWin)) {
237 // disallow ParentRelative background state
238 if (pWin->backgroundState == ParentRelative) {
239 XID pixel = 0;
240 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
244 RL_DEBUG_MSG("change window attributes end\n");
245 return result;
250 * RootlessPositionWindow
251 * This is a hook for when DIX moves or resizes a window.
252 * Update the frame position now although the physical window is moved
253 * in RootlessMoveWindow. (x, y) are *inside* position. After this,
254 * mi and fb are expecting the pixmap to be at the new location.
256 Bool
257 RootlessPositionWindow(WindowPtr pWin, int x, int y)
259 ScreenPtr pScreen = pWin->drawable.pScreen;
260 RootlessWindowRec *winRec = WINREC(pWin);
261 Bool result;
263 RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y);
265 if (winRec) {
266 if (winRec->is_drawing) {
267 // Reset frame's pixmap and move it to the new position.
268 int bw = wBorderWidth(pWin);
270 winRec->pixmap->devPrivate.ptr = winRec->pixelData;
271 SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw);
273 #ifdef ROOTLESS_TRACK_DAMAGE
274 // Move damaged region to correspond to new window position
275 if (REGION_NOTEMPTY(pScreen, &winRec->damage)) {
276 REGION_TRANSLATE(pScreen, &winRec->damage,
277 x - bw - winRec->x,
278 y - bw - winRec->y);
280 #endif
284 SCREEN_UNWRAP(pScreen, PositionWindow);
285 result = pScreen->PositionWindow(pWin, x, y);
286 SCREEN_WRAP(pScreen, PositionWindow);
288 RL_DEBUG_MSG("positionwindow end\n");
289 return result;
294 * RootlessInitializeFrame
295 * Initialize some basic attributes of the frame. Note that winRec
296 * may already have valid data in it, so don't overwrite anything
297 * valuable.
299 static void
300 RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec *winRec)
302 DrawablePtr d = &pWin->drawable;
303 int bw = wBorderWidth(pWin);
305 winRec->win = pWin;
307 winRec->x = d->x - bw;
308 winRec->y = d->y - bw;
309 winRec->width = d->width + 2*bw;
310 winRec->height = d->height + 2*bw;
311 winRec->borderWidth = bw;
313 #ifdef ROOTLESS_TRACK_DAMAGE
314 REGION_NULL(pScreen, &winRec->damage);
315 #endif
320 * RootlessEnsureFrame
321 * Make sure the given window is framed. If the window doesn't have a
322 * physical window associated with it, attempt to create one. If that
323 * is unsuccessful, return NULL.
325 static RootlessWindowRec *
326 RootlessEnsureFrame(WindowPtr pWin)
328 ScreenPtr pScreen = pWin->drawable.pScreen;
329 RootlessWindowRec *winRec;
330 #ifdef SHAPE
331 RegionRec shape;
332 #endif
333 RegionPtr pShape = NULL;
335 if (WINREC(pWin) != NULL)
336 return WINREC(pWin);
338 if (!IsTopLevel(pWin))
339 return NULL;
341 if (pWin->drawable.class != InputOutput)
342 return NULL;
344 winRec = xalloc(sizeof(RootlessWindowRec));
346 if (!winRec)
347 return NULL;
349 RootlessInitializeFrame(pWin, winRec);
351 winRec->is_drawing = FALSE;
352 winRec->is_reorder_pending = FALSE;
353 winRec->pixmap = NULL;
354 winRec->wid = NULL;
356 WINREC(pWin) = winRec;
358 #ifdef SHAPE
359 // Set the frame's shape if the window is shaped
360 if (RootlessGetShape(pWin, &shape))
361 pShape = &shape;
362 #endif
364 RL_DEBUG_MSG("creating frame ");
366 if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen,
367 winRec->x + SCREEN_TO_GLOBAL_X,
368 winRec->y + SCREEN_TO_GLOBAL_Y,
369 pShape))
371 RL_DEBUG_MSG("implementation failed to create frame!\n");
372 xfree(winRec);
373 WINREC(pWin) = NULL;
374 return NULL;
377 #ifdef SHAPE
378 if (pShape != NULL)
379 REGION_UNINIT(pScreen, &shape);
380 #endif
382 return winRec;
387 * RootlessRealizeWindow
388 * The frame is usually created here and not in CreateWindow so that
389 * windows do not eat memory until they are realized.
391 Bool
392 RootlessRealizeWindow(WindowPtr pWin)
394 Bool result;
395 RegionRec saveRoot;
396 ScreenPtr pScreen = pWin->drawable.pScreen;
398 RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin);
400 if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) {
401 RootlessWindowRec *winRec;
403 winRec = RootlessEnsureFrame(pWin);
404 if (winRec == NULL)
405 return FALSE;
407 winRec->is_reorder_pending = TRUE;
409 RL_DEBUG_MSG("Top level window ");
411 // Disallow ParentRelative background state on top-level windows.
412 // This might have been set before the window was mapped.
413 if (pWin->backgroundState == ParentRelative) {
414 XID pixel = 0;
415 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
419 if (!IsRoot(pWin)) HUGE_ROOT(pWin);
420 SCREEN_UNWRAP(pScreen, RealizeWindow);
421 result = pScreen->RealizeWindow(pWin);
422 SCREEN_WRAP(pScreen, RealizeWindow);
423 if (!IsRoot(pWin)) NORMAL_ROOT(pWin);
425 RL_DEBUG_MSG("realizewindow end\n");
426 return result;
431 * RootlessFrameForWindow
432 * Returns the frame ID for the physical window displaying the given window.
433 * If CREATE is true and the window has no frame, attempt to create one.
435 RootlessFrameID
436 RootlessFrameForWindow(WindowPtr pWin, Bool create)
438 WindowPtr pTopWin;
439 RootlessWindowRec *winRec;
441 pTopWin = TopLevelParent(pWin);
442 if (pTopWin == NULL)
443 return NULL;
445 winRec = WINREC(pTopWin);
447 if (winRec == NULL && create && pWin->drawable.class == InputOutput) {
448 winRec = RootlessEnsureFrame(pTopWin);
451 if (winRec == NULL)
452 return NULL;
454 return winRec->wid;
459 * RootlessUnrealizeWindow
460 * Unmap the physical window.
462 Bool
463 RootlessUnrealizeWindow(WindowPtr pWin)
465 ScreenPtr pScreen = pWin->drawable.pScreen;
466 RootlessWindowRec *winRec = WINREC(pWin);
467 Bool result;
469 RL_DEBUG_MSG("unrealizewindow start ");
471 if (winRec) {
472 RootlessStopDrawing(pWin, FALSE);
474 SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
476 winRec->is_reorder_pending = FALSE;
479 SCREEN_UNWRAP(pScreen, UnrealizeWindow);
480 result = pScreen->UnrealizeWindow(pWin);
481 SCREEN_WRAP(pScreen, UnrealizeWindow);
483 RL_DEBUG_MSG("unrealizewindow end\n");
484 return result;
489 * RootlessReorderWindow
490 * Reorder the frame associated with the given window so that it's
491 * physically above the window below it in the X stacking order.
493 void
494 RootlessReorderWindow(WindowPtr pWin)
496 RootlessWindowRec *winRec = WINREC(pWin);
498 if (winRec != NULL && !winRec->is_reorder_pending) {
499 WindowPtr newPrevW;
500 RootlessWindowRec *newPrev;
501 RootlessFrameID newPrevID;
502 ScreenPtr pScreen = pWin->drawable.pScreen;
504 /* Check if the implementation wants the frame to not be reordered
505 even though the X11 window is restacked. This can be useful if
506 frames are ordered-in with animation so that the reordering is not
507 done until the animation is complete. */
508 if (SCREENREC(pScreen)->imp->DoReorderWindow) {
509 if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec))
510 return;
513 RootlessStopDrawing(pWin, FALSE);
515 /* Find the next window above this one that has a mapped frame. */
517 newPrevW = pWin->prevSib;
518 while (newPrevW && (WINREC(newPrevW) == NULL || !newPrevW->realized))
519 newPrevW = newPrevW->prevSib;
521 newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
522 newPrevID = newPrev != NULL ? newPrev->wid : 0;
524 /* If it exists, reorder the frame above us first. */
526 if (newPrev && newPrev->is_reorder_pending) {
527 newPrev->is_reorder_pending = FALSE;
528 RootlessReorderWindow(newPrevW);
531 SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
537 * RootlessRestackWindow
538 * This is a hook for when DIX changes the window stacking order.
539 * The window has already been inserted into its new position in the
540 * DIX window stack. We need to change the order of the physical
541 * window to match.
543 void
544 RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
546 RegionRec saveRoot;
547 RootlessWindowRec *winRec = WINREC(pWin);
548 ScreenPtr pScreen = pWin->drawable.pScreen;
550 RL_DEBUG_MSG("restackwindow start ");
551 if (winRec)
552 RL_DEBUG_MSG("restack top level \n");
554 HUGE_ROOT(pWin);
555 SCREEN_UNWRAP(pScreen, RestackWindow);
557 if (pScreen->RestackWindow)
558 pScreen->RestackWindow(pWin, pOldNextSib);
560 SCREEN_WRAP(pScreen, RestackWindow);
561 NORMAL_ROOT(pWin);
563 if (winRec && pWin->viewable) {
564 RootlessReorderWindow(pWin);
567 RL_DEBUG_MSG("restackwindow end\n");
572 * Specialized window copy procedures
575 // Globals needed during window resize and move.
576 static pointer gResizeDeathBits = NULL;
577 static int gResizeDeathCount = 0;
578 static PixmapPtr gResizeDeathPix[2] = {NULL, NULL};
579 static BoxRec gResizeDeathBounds[2];
580 static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
583 * RootlessNoCopyWindow
584 * CopyWindow() that doesn't do anything. For MoveWindow() of
585 * top-level windows.
587 static void
588 RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
589 RegionPtr prgnSrc)
591 // some code expects the region to be translated
592 int dx = ptOldOrg.x - pWin->drawable.x;
593 int dy = ptOldOrg.y - pWin->drawable.y;
595 RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW ");
597 REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
602 * RootlessResizeCopyWindow
603 * CopyWindow used during ResizeWindow for gravity moves. Based on
604 * fbCopyWindow. The original always draws on the root pixmap, which
605 * we don't have. Instead, draw on the parent window's pixmap.
606 * Resize version: the old location's pixels are in gResizeCopyWindowSource.
608 static void
609 RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
610 RegionPtr prgnSrc)
612 ScreenPtr pScreen = pWin->drawable.pScreen;
613 RegionRec rgnDst;
614 int dx, dy;
616 RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
618 /* Don't unwrap pScreen->CopyWindow.
619 The bogus rewrap with RootlessCopyWindow causes a crash if
620 CopyWindow is called again during the same resize. */
622 if (gResizeDeathCount == 0)
623 return;
625 RootlessStartDrawing(pWin);
627 dx = ptOldOrg.x - pWin->drawable.x;
628 dy = ptOldOrg.y - pWin->drawable.y;
629 REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
630 REGION_NULL(pScreen, &rgnDst);
631 REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
633 if (gResizeDeathCount == 1) {
634 /* Simple case, we only have a single source pixmap. */
636 fbCopyRegion(&gResizeDeathPix[0]->drawable,
637 &pScreen->GetWindowPixmap(pWin)->drawable, 0,
638 &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
640 else {
641 int i;
642 RegionRec clip, clipped;
644 /* More complex case, N source pixmaps (usually two). So we
645 intersect the destination with each source and copy those bits. */
647 for (i = 0; i < gResizeDeathCount; i++) {
648 REGION_INIT(pScreen, &clip, gResizeDeathBounds + 0, 1);
649 REGION_NULL(pScreen, &clipped);
650 REGION_INTERSECT(pScreen, &rgnDst, &clip, &clipped);
652 fbCopyRegion(&gResizeDeathPix[i]->drawable,
653 &pScreen->GetWindowPixmap(pWin)->drawable, 0,
654 &clipped, dx, dy, fbCopyWindowProc, 0, 0);
656 REGION_UNINIT(pScreen, &clipped);
657 REGION_UNINIT(pScreen, &clip);
661 /* Don't update - resize will update everything */
662 REGION_UNINIT(pScreen, &rgnDst);
664 fbValidateDrawable(&pWin->drawable);
666 RL_DEBUG_MSG("resizecopywindowFB end\n");
671 * RootlessCopyWindow
672 * Update *new* location of window. Old location is redrawn with
673 * PaintWindowBackground/Border. Cloned from fbCopyWindow.
674 * The original always draws on the root pixmap, which we don't have.
675 * Instead, draw on the parent window's pixmap.
677 void
678 RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
680 ScreenPtr pScreen = pWin->drawable.pScreen;
681 RegionRec rgnDst;
682 int dx, dy;
683 BoxPtr extents;
684 int area;
686 RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin);
688 SCREEN_UNWRAP(pScreen, CopyWindow);
690 dx = ptOldOrg.x - pWin->drawable.x;
691 dy = ptOldOrg.y - pWin->drawable.y;
692 REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
694 REGION_NULL(pScreen, &rgnDst);
695 REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
697 extents = REGION_EXTENTS(pScreen, &rgnDst);
698 area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
700 /* If the area exceeds threshold, use the implementation's
701 accelerated version. */
702 if (area > rootless_CopyWindow_threshold &&
703 SCREENREC(pScreen)->imp->CopyWindow)
705 RootlessWindowRec *winRec;
706 WindowPtr top;
708 top = TopLevelParent(pWin);
709 if (top == NULL) {
710 RL_DEBUG_MSG("no parent\n");
711 return;
714 winRec = WINREC(top);
715 if (winRec == NULL) {
716 RL_DEBUG_MSG("not framed\n");
717 return;
720 /* Move region to window local coords */
721 REGION_TRANSLATE(pScreen, &rgnDst, -winRec->x, -winRec->y);
723 RootlessStopDrawing(pWin, FALSE);
725 SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
726 REGION_NUM_RECTS(&rgnDst),
727 REGION_RECTS(&rgnDst),
728 dx, dy);
730 else {
731 RootlessStartDrawing(pWin);
733 fbCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
734 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
736 /* prgnSrc has been translated to dst position */
737 RootlessDamageRegion(pWin, prgnSrc);
740 REGION_UNINIT(pScreen, &rgnDst);
741 fbValidateDrawable(&pWin->drawable);
743 SCREEN_WRAP(pScreen, CopyWindow);
745 RL_DEBUG_MSG("copywindowFB end\n");
750 * Window resize procedures
753 enum {
754 WIDTH_SMALLER = 1,
755 HEIGHT_SMALLER = 2,
760 * ResizeWeighting
761 * Choose gravity to avoid local copies. Do that by looking for
762 * a corner that doesn't move _relative to the screen_.
764 static inline unsigned int
765 ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
766 int newX1, int newY1, int newX2, int newY2, int newBW)
768 #ifdef ROOTLESS_RESIZE_GRAVITY
769 if (newBW != oldBW)
770 return RL_GRAVITY_NONE;
772 if (newX1 == oldX1 && newY1 == oldY1)
773 return RL_GRAVITY_NORTH_WEST;
774 else if (newX1 == oldX1 && newY2 == oldY2)
775 return RL_GRAVITY_SOUTH_WEST;
776 else if (newX2 == oldX2 && newY2 == oldY2)
777 return RL_GRAVITY_SOUTH_EAST;
778 else if (newX2 == oldX2 && newY1 == oldY1)
779 return RL_GRAVITY_NORTH_EAST;
780 else
781 return RL_GRAVITY_NONE;
782 #else
783 return RL_GRAVITY_NONE;
784 #endif
789 * StartFrameResize
790 * Prepare to resize a top-level window. The old window's pixels are
791 * saved and the implementation is told to change the window size.
792 * (x,y,w,h) is outer frame of window (outside border)
794 static Bool
795 StartFrameResize(WindowPtr pWin, Bool gravity,
796 int oldX, int oldY, int oldW, int oldH, int oldBW,
797 int newX, int newY, int newW, int newH, int newBW)
799 ScreenPtr pScreen = pWin->drawable.pScreen;
800 RootlessWindowRec *winRec = WINREC(pWin);
801 Bool need_window_source = FALSE, resize_after = FALSE;
803 BoxRec rect;
804 int oldX2, newX2;
805 int oldY2, newY2;
806 unsigned int weight;
808 oldX2 = oldX + oldW, newX2 = newX + newW;
809 oldY2 = oldY + oldH, newY2 = newY + newH;
811 /* Decide which resize weighting to use */
812 weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
813 newX, newY, newW, newH, newBW);
815 /* Compute intersection between old and new rects */
816 rect.x1 = max(oldX, newX);
817 rect.y1 = max(oldY, newY);
818 rect.x2 = min(oldX2, newX2);
819 rect.y2 = min(oldY2, newY2);
821 RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
822 RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n",
823 oldX, oldY, oldW, oldH, oldBW,
824 newX, newY, newW, newH, newBW);
826 RootlessRedisplay(pWin);
828 /* If gravity is true, then we need to have a way of recovering all
829 the original bits in the window for when X rearranges the contents
830 based on the various gravity settings. The obvious way is to just
831 snapshot the entire backing store before resizing it, but that
832 it slow on large windows.
834 So the optimization here is to use the implementation's resize
835 weighting options (if available) to allow us to reason about what
836 is left in the backing store after the resize. We can then only
837 copy what won't be there after the resize, and do a two-stage copy
838 operation.
840 Most of these optimizations are only applied when the top-left
841 corner of the window is fixed, since that's the common case. They
842 could probably be extended with some thought. */
844 gResizeDeathCount = 0;
846 if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
847 unsigned int code = 0;
849 /* Top left corner is anchored. We never need to copy the
850 entire window. */
852 need_window_source = TRUE;
854 /* These comparisons were chosen to avoid setting bits when the sizes
855 are the same. (So the fastest case automatically gets taken when
856 dimensions are unchanging.) */
858 if (newW < oldW)
859 code |= WIDTH_SMALLER;
860 if (newH < oldH)
861 code |= HEIGHT_SMALLER;
863 if (((code ^ (code >> 1)) & 1) == 0) {
864 /* Both dimensions are either getting larger, or both
865 are getting smaller. No need to copy anything. */
867 if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
868 /* Since the window is getting smaller, we can do gravity
869 repair on it with it's current size, then resize it
870 afterwards. */
872 resize_after = TRUE;
875 gResizeDeathCount = 1;
877 else {
878 unsigned int copy_rowbytes, Bpp;
879 unsigned int copy_rect_width, copy_rect_height;
880 BoxRec copy_rect;
882 /* We can get away with a partial copy. 'rect' is the
883 intersection between old and new bounds, so copy
884 everything to the right of or below the intersection. */
886 RootlessStartDrawing(pWin);
888 if (code == WIDTH_SMALLER) {
889 copy_rect.x1 = rect.x2;
890 copy_rect.y1 = rect.y1;
891 copy_rect.x2 = oldX2;
892 copy_rect.y2 = oldY2;
894 else if (code == HEIGHT_SMALLER) {
895 copy_rect.x1 = rect.x1;
896 copy_rect.y1 = rect.y2;
897 copy_rect.x2 = oldX2;
898 copy_rect.y2 = oldY2;
900 else
901 abort();
903 Bpp = winRec->win->drawable.bitsPerPixel / 8;
904 copy_rect_width = copy_rect.x2 - copy_rect.x1;
905 copy_rect_height = copy_rect.y2 - copy_rect.y1;
906 copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
907 gResizeDeathBits = xalloc(copy_rowbytes
908 * copy_rect_height);
910 if (copy_rect_width * copy_rect_height >
911 rootless_CopyBytes_threshold &&
912 SCREENREC(pScreen)->imp->CopyBytes)
914 SCREENREC(pScreen)->imp->CopyBytes(
915 copy_rect_width * Bpp, copy_rect_height,
916 ((char *) winRec->pixelData)
917 + ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
918 + (copy_rect.x1 - oldX) * Bpp, winRec->bytesPerRow,
919 gResizeDeathBits, copy_rowbytes);
920 } else {
921 fbBlt((FbBits *) (winRec->pixelData
922 + ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
923 + (copy_rect.x1 - oldX) * Bpp),
924 winRec->bytesPerRow / sizeof(FbBits), 0,
925 (FbBits *) gResizeDeathBits,
926 copy_rowbytes / sizeof(FbBits), 0,
927 copy_rect_width * Bpp, copy_rect_height,
928 GXcopy, FB_ALLONES, Bpp, 0, 0);
931 gResizeDeathBounds[1] = copy_rect;
932 gResizeDeathPix[1]
933 = GetScratchPixmapHeader(pScreen, copy_rect_width,
934 copy_rect_height,
935 winRec->win->drawable.depth,
936 winRec->win->drawable.bitsPerPixel,
937 winRec->bytesPerRow,
938 (void *) gResizeDeathBits);
940 SetPixmapBaseToScreen(gResizeDeathPix[1],
941 copy_rect.x1, copy_rect.y1);
943 gResizeDeathCount = 2;
946 else if (gravity) {
947 /* The general case. Just copy everything. */
949 RootlessStartDrawing(pWin);
951 gResizeDeathBits = xalloc(winRec->bytesPerRow * winRec->height);
953 memcpy(gResizeDeathBits, winRec->pixelData,
954 winRec->bytesPerRow * winRec->height);
956 gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
957 gResizeDeathPix[0]
958 = GetScratchPixmapHeader(pScreen, winRec->width,
959 winRec->height,
960 winRec->win->drawable.depth,
961 winRec->win->drawable.bitsPerPixel,
962 winRec->bytesPerRow,
963 (void *) gResizeDeathBits);
965 SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
966 gResizeDeathCount = 1;
969 RootlessStopDrawing(pWin, FALSE);
971 winRec->x = newX;
972 winRec->y = newY;
973 winRec->width = newW;
974 winRec->height = newH;
975 winRec->borderWidth = newBW;
977 /* Unless both dimensions are getting smaller, Resize the frame
978 before doing gravity repair */
980 if (!resize_after) {
981 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
982 newX + SCREEN_TO_GLOBAL_X,
983 newY + SCREEN_TO_GLOBAL_Y,
984 newW, newH, weight);
987 RootlessStartDrawing(pWin);
989 /* If necessary, create a source pixmap pointing at the current
990 window bits. */
992 if (need_window_source) {
993 gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
994 gResizeDeathPix[0]
995 = GetScratchPixmapHeader(pScreen, oldW, oldH,
996 winRec->win->drawable.depth,
997 winRec->win->drawable.bitsPerPixel,
998 winRec->bytesPerRow, winRec->pixelData);
1000 SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1003 /* Use custom CopyWindow when moving gravity bits around
1004 ResizeWindow assumes the old window contents are in the same
1005 pixmap, but here they're in deathPix instead. */
1007 if (gravity) {
1008 gResizeOldCopyWindowProc = pScreen->CopyWindow;
1009 pScreen->CopyWindow = RootlessResizeCopyWindow;
1012 /* If we can't rely on the window server preserving the bits we
1013 need in the position we need, copy the pixels in the
1014 intersection from src to dst. ResizeWindow assumes these pixels
1015 are already present when making gravity adjustments. pWin
1016 currently has new-sized pixmap but is in old position.
1018 FIXME: border width change! (?) */
1020 if (gravity && weight == RL_GRAVITY_NONE) {
1021 PixmapPtr src, dst;
1023 assert(gResizeDeathCount == 1);
1025 src = gResizeDeathPix[0];
1026 dst = pScreen->GetWindowPixmap(pWin);
1028 RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1029 rect.x1, rect.y1, rect.x2, rect.y2);
1031 /* rect is the intersection of the old location and new location */
1032 if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
1033 /* The window drawable still has the old frame position, which
1034 means that DST doesn't actually point at the origin of our
1035 physical backing store when adjusted by the drawable.x,y
1036 position. So sneakily adjust it temporarily while copying.. */
1038 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1039 SetPixmapBaseToScreen(dst, newX, newY);
1041 fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1042 &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1044 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1045 SetPixmapBaseToScreen(dst, oldX, oldY);
1049 return resize_after;
1053 static void
1054 FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
1055 unsigned int oldW, unsigned int oldH, unsigned int oldBW,
1056 int newX, int newY, unsigned int newW, unsigned int newH,
1057 unsigned int newBW, Bool resize_now)
1059 ScreenPtr pScreen = pWin->drawable.pScreen;
1060 RootlessWindowRec *winRec = WINREC(pWin);
1061 int i;
1063 RootlessStopDrawing(pWin, FALSE);
1065 if (resize_now) {
1066 unsigned int weight;
1068 /* We didn't resize anything earlier, so do it now, now that
1069 we've finished gravitating the bits. */
1071 weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
1072 newX, newY, newW, newH, newBW);
1074 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1075 newX + SCREEN_TO_GLOBAL_X,
1076 newY + SCREEN_TO_GLOBAL_Y,
1077 newW, newH, weight);
1080 /* Redraw everything. FIXME: there must be times when we don't need
1081 to do this. Perhaps when top-left weighting and no gravity? */
1083 RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
1085 for (i = 0; i < 2; i++) {
1086 if (gResizeDeathPix[i] != NULL) {
1087 FreeScratchPixmapHeader(gResizeDeathPix[i]);
1088 gResizeDeathPix[i] = NULL;
1092 if (gResizeDeathBits != NULL) {
1093 xfree(gResizeDeathBits);
1094 gResizeDeathBits = NULL;
1097 if (gravity) {
1098 pScreen->CopyWindow = gResizeOldCopyWindowProc;
1104 * RootlessMoveWindow
1105 * If kind==VTOther, window border is resizing (and borderWidth is
1106 * already changed!!@#$) This case works like window resize, not move.
1108 void
1109 RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1111 RootlessWindowRec *winRec = WINREC(pWin);
1112 ScreenPtr pScreen = pWin->drawable.pScreen;
1113 CopyWindowProcPtr oldCopyWindowProc = NULL;
1114 int oldX = 0, oldY = 0, newX = 0, newY = 0;
1115 unsigned int oldW = 0, oldH = 0, oldBW = 0;
1116 unsigned int newW = 0, newH = 0, newBW = 0;
1117 Bool resize_after = FALSE;
1118 RegionRec saveRoot;
1120 RL_DEBUG_MSG("movewindow start \n");
1122 if (winRec) {
1123 if (kind == VTMove) {
1124 oldX = winRec->x;
1125 oldY = winRec->y;
1126 RootlessRedisplay(pWin);
1127 RootlessStartDrawing(pWin);
1128 } else {
1129 RL_DEBUG_MSG("movewindow border resizing ");
1131 oldBW = winRec->borderWidth;
1132 oldX = winRec->x;
1133 oldY = winRec->y;
1134 oldW = winRec->width;
1135 oldH = winRec->height;
1137 newBW = wBorderWidth(pWin);
1138 newX = x;
1139 newY = y;
1140 newW = pWin->drawable.width + 2*newBW;
1141 newH = pWin->drawable.height + 2*newBW;
1143 resize_after = StartFrameResize(pWin, FALSE,
1144 oldX, oldY, oldW, oldH, oldBW,
1145 newX, newY, newW, newH, newBW);
1149 HUGE_ROOT(pWin);
1150 SCREEN_UNWRAP(pScreen, MoveWindow);
1152 if (winRec) {
1153 oldCopyWindowProc = pScreen->CopyWindow;
1154 pScreen->CopyWindow = RootlessNoCopyWindow;
1156 pScreen->MoveWindow(pWin, x, y, pSib, kind);
1157 if (winRec) {
1158 pScreen->CopyWindow = oldCopyWindowProc;
1161 NORMAL_ROOT(pWin);
1162 SCREEN_WRAP(pScreen, MoveWindow);
1164 if (winRec) {
1165 if (kind == VTMove) {
1166 winRec->x = x;
1167 winRec->y = y;
1168 RootlessStopDrawing(pWin, FALSE);
1169 SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1170 x + SCREEN_TO_GLOBAL_X,
1171 y + SCREEN_TO_GLOBAL_Y);
1172 } else {
1173 FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1174 newX, newY, newW, newH, newBW, resize_after);
1178 RL_DEBUG_MSG("movewindow end\n");
1183 * RootlessResizeWindow
1184 * Note: (x, y, w, h) as passed to this procedure don't match the frame
1185 * definition. (x,y) is corner of very outer edge, *outside* border.
1186 * w,h is width and height *inside* border, *ignoring* border width.
1187 * The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
1188 * is total rect and (x+bw, y+bw, w, h) is inner rect.
1190 void
1191 RootlessResizeWindow(WindowPtr pWin, int x, int y,
1192 unsigned int w, unsigned int h, WindowPtr pSib)
1194 RootlessWindowRec *winRec = WINREC(pWin);
1195 ScreenPtr pScreen = pWin->drawable.pScreen;
1196 int oldX = 0, oldY = 0, newX = 0, newY = 0;
1197 unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
1198 Bool resize_after = FALSE;
1199 RegionRec saveRoot;
1201 RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
1203 if (winRec) {
1204 oldBW = winRec->borderWidth;
1205 oldX = winRec->x;
1206 oldY = winRec->y;
1207 oldW = winRec->width;
1208 oldH = winRec->height;
1210 newBW = oldBW;
1211 newX = x;
1212 newY = y;
1213 newW = w + 2*newBW;
1214 newH = h + 2*newBW;
1216 resize_after = StartFrameResize(pWin, TRUE,
1217 oldX, oldY, oldW, oldH, oldBW,
1218 newX, newY, newW, newH, newBW);
1221 HUGE_ROOT(pWin);
1222 SCREEN_UNWRAP(pScreen, ResizeWindow);
1223 pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
1224 SCREEN_WRAP(pScreen, ResizeWindow);
1225 NORMAL_ROOT(pWin);
1227 if (winRec) {
1228 FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
1229 newX, newY, newW, newH, newBW, resize_after);
1232 RL_DEBUG_MSG("resizewindow end\n");
1237 * RootlessRepositionWindow
1238 * Called by the implementation when a window needs to be repositioned to
1239 * its correct location on the screen. This routine is typically needed
1240 * due to changes in the underlying window system, such as a screen layout
1241 * change.
1243 void
1244 RootlessRepositionWindow(WindowPtr pWin)
1246 RootlessWindowRec *winRec = WINREC(pWin);
1247 ScreenPtr pScreen = pWin->drawable.pScreen;
1249 if (winRec == NULL)
1250 return;
1252 RootlessStopDrawing(pWin, FALSE);
1253 SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1254 winRec->x + SCREEN_TO_GLOBAL_X,
1255 winRec->y + SCREEN_TO_GLOBAL_Y);
1257 RootlessReorderWindow(pWin);
1262 * RootlessReparentWindow
1263 * Called after a window has been reparented. Generally windows are not
1264 * framed until they are mapped. However, a window may be framed early by the
1265 * implementation calling RootlessFrameForWindow. (e.g. this could be needed
1266 * to attach a VRAM surface to it.) If the window is subsequently reparented
1267 * by the window manager before being mapped, we need to give the frame to
1268 * the new top-level window.
1270 void
1271 RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
1273 ScreenPtr pScreen = pWin->drawable.pScreen;
1274 RootlessWindowRec *winRec = WINREC(pWin);
1275 WindowPtr pTopWin;
1277 /* Check that window is not top-level now, but used to be. */
1278 if (IsRoot(pWin) || IsRoot(pWin->parent)
1279 || IsTopLevel(pWin) || winRec == NULL)
1281 goto out;
1284 /* If the formerly top-level window has a frame, we want to give the
1285 frame to its new top-level parent. If we can't do that, we'll just
1286 have to jettison it... */
1288 pTopWin = TopLevelParent(pWin);
1289 assert(pTopWin != pWin);
1291 if (WINREC(pTopWin) != NULL) {
1292 /* We're screwed. */
1293 RootlessDestroyFrame(pWin, winRec);
1294 } else {
1295 if (!pTopWin->realized && pWin->realized) {
1296 SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
1299 /* Switch the frame record from one to the other. */
1301 WINREC(pWin) = NULL;
1302 WINREC(pTopWin) = winRec;
1304 RootlessInitializeFrame(pTopWin, winRec);
1305 RootlessReshapeFrame(pTopWin);
1307 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1308 winRec->x + SCREEN_TO_GLOBAL_X,
1309 winRec->y + SCREEN_TO_GLOBAL_Y,
1310 winRec->width, winRec->height,
1311 RL_GRAVITY_NONE);
1313 if (SCREENREC(pScreen)->imp->SwitchWindow) {
1314 SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
1317 if (pTopWin->realized && !pWin->realized)
1318 winRec->is_reorder_pending = TRUE;
1321 out:
1322 if (SCREENREC(pScreen)->ReparentWindow) {
1323 SCREEN_UNWRAP(pScreen, ReparentWindow);
1324 pScreen->ReparentWindow(pWin, pPriorParent);
1325 SCREEN_WRAP(pScreen, ReparentWindow);
1331 * SetPixmapOfAncestors
1332 * Set the Pixmaps on all ParentRelative windows up the ancestor chain.
1334 static void
1335 SetPixmapOfAncestors(WindowPtr pWin)
1337 ScreenPtr pScreen = pWin->drawable.pScreen;
1338 WindowPtr topWin = TopLevelParent(pWin);
1339 RootlessWindowRec *topWinRec = WINREC(topWin);
1341 while (pWin->backgroundState == ParentRelative) {
1342 if (pWin == topWin) {
1343 // disallow ParentRelative background state on top level
1344 XID pixel = 0;
1345 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
1346 RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
1347 break;
1350 pWin = pWin->parent;
1351 pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
1357 * RootlessPaintWindowBackground
1359 void
1360 RootlessPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what)
1362 ScreenPtr pScreen = pWin->drawable.pScreen;
1364 if (IsRoot(pWin))
1365 return;
1367 RL_DEBUG_MSG("paintwindowbackground start (win 0x%x, framed %i) ",
1368 pWin, IsFramedWindow(pWin));
1370 if (IsFramedWindow(pWin)) {
1371 RootlessStartDrawing(pWin);
1372 RootlessDamageRegion(pWin, pRegion);
1374 // For ParentRelative windows, we have to make sure the window
1375 // pixmap is set correctly all the way up the ancestor chain.
1376 if (pWin->backgroundState == ParentRelative) {
1377 SetPixmapOfAncestors(pWin);
1381 SCREEN_UNWRAP(pScreen, PaintWindowBackground);
1382 pScreen->PaintWindowBackground(pWin, pRegion, what);
1383 SCREEN_WRAP(pScreen, PaintWindowBackground);
1385 RL_DEBUG_MSG("paintwindowbackground end\n");
1390 * RootlessPaintWindowBorder
1392 void
1393 RootlessPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what)
1395 RL_DEBUG_MSG("paintwindowborder start (win 0x%x) ", pWin);
1397 if (IsFramedWindow(pWin)) {
1398 RootlessStartDrawing(pWin);
1399 RootlessDamageRegion(pWin, pRegion);
1401 // For ParentRelative windows with tiled borders, we have to make
1402 // sure the window pixmap is set correctly all the way up the
1403 // ancestor chain.
1404 if (!pWin->borderIsPixel &&
1405 pWin->backgroundState == ParentRelative)
1407 SetPixmapOfAncestors(pWin);
1411 SCREEN_UNWRAP(pWin->drawable.pScreen, PaintWindowBorder);
1412 pWin->drawable.pScreen->PaintWindowBorder(pWin, pRegion, what);
1413 SCREEN_WRAP(pWin->drawable.pScreen, PaintWindowBorder);
1415 RL_DEBUG_MSG("paintwindowborder end\n");
1420 * RootlessChangeBorderWidth
1421 * FIXME: untested!
1422 * pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1423 * Frame moves and resizes.
1425 void
1426 RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
1428 RegionRec saveRoot;
1429 Bool resize_after = FALSE;
1431 RL_DEBUG_MSG("change border width ");
1433 if (width != wBorderWidth(pWin)) {
1434 RootlessWindowRec *winRec = WINREC(pWin);
1435 int oldX = 0, oldY = 0, newX = 0, newY = 0;
1436 unsigned int oldW = 0, oldH = 0, oldBW = 0;
1437 unsigned int newW = 0, newH = 0, newBW = 0;
1439 if (winRec) {
1440 oldBW = winRec->borderWidth;
1441 oldX = winRec->x;
1442 oldY = winRec->y;
1443 oldW = winRec->width;
1444 oldH = winRec->height;
1446 newBW = width;
1447 newX = pWin->drawable.x - newBW;
1448 newY = pWin->drawable.y - newBW;
1449 newW = pWin->drawable.width + 2*newBW;
1450 newH = pWin->drawable.height + 2*newBW;
1452 resize_after = StartFrameResize(pWin, FALSE,
1453 oldX, oldY, oldW, oldH, oldBW,
1454 newX, newY, newW, newH, newBW);
1457 HUGE_ROOT(pWin);
1458 SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1459 pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
1460 SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1461 NORMAL_ROOT(pWin);
1463 if (winRec) {
1464 FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1465 newX, newY, newW, newH, newBW, resize_after);
1469 RL_DEBUG_MSG("change border width end\n");