2 * Rootless window management
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>
36 #include <stddef.h> /* For NULL */
37 #include <limits.h> /* For CHAR_BIT */
40 #include "rootlessCommon.h"
41 #include "rootlessWindow.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)
52 #define SCREEN_TO_GLOBAL_X 0
53 #define SCREEN_TO_GLOBAL_Y 0
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.
64 RootlessCreateWindow(WindowPtr pWin
)
71 SCREEN_UNWRAP(pWin
->drawable
.pScreen
, CreateWindow
);
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! */
82 result
= pWin
->drawable
.pScreen
->CreateWindow(pWin
);
88 SCREEN_WRAP(pWin
->drawable
.pScreen
, CreateWindow
);
95 * RootlessDestroyFrame
96 * Destroy the physical window associated with the given window.
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
);
115 * RootlessDestroyWindow
116 * Destroy the physical window associated with the given window.
119 RootlessDestroyWindow(WindowPtr pWin
)
121 RootlessWindowRec
*winRec
= WINREC(pWin
);
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
);
139 RootlessGetShape(WindowPtr pWin
, RegionPtr pShape
)
141 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
143 if (wBoundingShape(pWin
) == NULL
)
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
);
158 * RootlessReshapeFrame
159 * Set the frame shape.
161 static void RootlessReshapeFrame(WindowPtr pWin
)
163 RootlessWindowRec
*winRec
= WINREC(pWin
);
164 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
168 // If the window is not yet framed, do nothing
175 RootlessStopDrawing(pWin
, FALSE
);
177 pShape
= RootlessGetShape(pWin
, &newShape
) ? &newShape
: NULL
;
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
);
187 RL_DEBUG_MSG("no shape ");
191 SCREENREC(pScreen
)->imp
->ReshapeFrame(winRec
->wid
, pShape
);
194 REGION_UNINIT(pScreen
, &newShape
);
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.
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
);
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. */
225 RootlessChangeWindowAttributes(WindowPtr pWin
, unsigned long vmask
)
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
);
237 // disallow ParentRelative background state
238 if (pWin
->backgroundState
== ParentRelative
) {
240 ChangeWindowAttributes(pWin
, CWBackPixel
, &pixel
, serverClient
);
244 RL_DEBUG_MSG("change window attributes end\n");
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.
257 RootlessPositionWindow(WindowPtr pWin
, int x
, int y
)
259 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
260 RootlessWindowRec
*winRec
= WINREC(pWin
);
263 RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin
, x
, y
);
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
,
284 SCREEN_UNWRAP(pScreen
, PositionWindow
);
285 result
= pScreen
->PositionWindow(pWin
, x
, y
);
286 SCREEN_WRAP(pScreen
, PositionWindow
);
288 RL_DEBUG_MSG("positionwindow end\n");
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
300 RootlessInitializeFrame(WindowPtr pWin
, RootlessWindowRec
*winRec
)
302 DrawablePtr d
= &pWin
->drawable
;
303 int bw
= wBorderWidth(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
);
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
;
333 RegionPtr pShape
= NULL
;
335 if (WINREC(pWin
) != NULL
)
338 if (!IsTopLevel(pWin
))
341 if (pWin
->drawable
.class != InputOutput
)
344 winRec
= xalloc(sizeof(RootlessWindowRec
));
349 RootlessInitializeFrame(pWin
, winRec
);
351 winRec
->is_drawing
= FALSE
;
352 winRec
->is_reorder_pending
= FALSE
;
353 winRec
->pixmap
= NULL
;
356 WINREC(pWin
) = winRec
;
359 // Set the frame's shape if the window is shaped
360 if (RootlessGetShape(pWin
, &shape
))
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
,
371 RL_DEBUG_MSG("implementation failed to create frame!\n");
379 REGION_UNINIT(pScreen
, &shape
);
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.
392 RootlessRealizeWindow(WindowPtr pWin
)
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
);
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
) {
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");
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.
436 RootlessFrameForWindow(WindowPtr pWin
, Bool create
)
439 RootlessWindowRec
*winRec
;
441 pTopWin
= TopLevelParent(pWin
);
445 winRec
= WINREC(pTopWin
);
447 if (winRec
== NULL
&& create
&& pWin
->drawable
.class == InputOutput
) {
448 winRec
= RootlessEnsureFrame(pTopWin
);
459 * RootlessUnrealizeWindow
460 * Unmap the physical window.
463 RootlessUnrealizeWindow(WindowPtr pWin
)
465 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
466 RootlessWindowRec
*winRec
= WINREC(pWin
);
469 RL_DEBUG_MSG("unrealizewindow start ");
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");
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.
494 RootlessReorderWindow(WindowPtr pWin
)
496 RootlessWindowRec
*winRec
= WINREC(pWin
);
498 if (winRec
!= NULL
&& !winRec
->is_reorder_pending
) {
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
))
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
544 RootlessRestackWindow(WindowPtr pWin
, WindowPtr pOldNextSib
)
547 RootlessWindowRec
*winRec
= WINREC(pWin
);
548 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
550 RL_DEBUG_MSG("restackwindow start ");
552 RL_DEBUG_MSG("restack top level \n");
555 SCREEN_UNWRAP(pScreen
, RestackWindow
);
557 if (pScreen
->RestackWindow
)
558 pScreen
->RestackWindow(pWin
, pOldNextSib
);
560 SCREEN_WRAP(pScreen
, RestackWindow
);
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
588 RootlessNoCopyWindow(WindowPtr pWin
, DDXPointRec ptOldOrg
,
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.
609 RootlessResizeCopyWindow(WindowPtr pWin
, DDXPointRec ptOldOrg
,
612 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
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)
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);
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");
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.
678 RootlessCopyWindow(WindowPtr pWin
, DDXPointRec ptOldOrg
, RegionPtr prgnSrc
)
680 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
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
;
708 top
= TopLevelParent(pWin
);
710 RL_DEBUG_MSG("no parent\n");
714 winRec
= WINREC(top
);
715 if (winRec
== NULL
) {
716 RL_DEBUG_MSG("not framed\n");
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
),
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
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
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
;
781 return RL_GRAVITY_NONE
;
783 return RL_GRAVITY_NONE
;
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)
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
;
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
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
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.) */
859 code
|= WIDTH_SMALLER
;
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
875 gResizeDeathCount
= 1;
878 unsigned int copy_rowbytes
, Bpp
;
879 unsigned int copy_rect_width
, copy_rect_height
;
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
;
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
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
);
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
;
933 = GetScratchPixmapHeader(pScreen
, copy_rect_width
,
935 winRec
->win
->drawable
.depth
,
936 winRec
->win
->drawable
.bitsPerPixel
,
938 (void *) gResizeDeathBits
);
940 SetPixmapBaseToScreen(gResizeDeathPix
[1],
941 copy_rect
.x1
, copy_rect
.y1
);
943 gResizeDeathCount
= 2;
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
};
958 = GetScratchPixmapHeader(pScreen
, winRec
->width
,
960 winRec
->win
->drawable
.depth
,
961 winRec
->win
->drawable
.bitsPerPixel
,
963 (void *) gResizeDeathBits
);
965 SetPixmapBaseToScreen(gResizeDeathPix
[0], oldX
, oldY
);
966 gResizeDeathCount
= 1;
969 RootlessStopDrawing(pWin
, FALSE
);
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 */
981 SCREENREC(pScreen
)->imp
->ResizeFrame(winRec
->wid
, pScreen
,
982 newX
+ SCREEN_TO_GLOBAL_X
,
983 newY
+ SCREEN_TO_GLOBAL_Y
,
987 RootlessStartDrawing(pWin
);
989 /* If necessary, create a source pixmap pointing at the current
992 if (need_window_source
) {
993 gResizeDeathBounds
[0] = (BoxRec
) {oldX
, oldY
, oldX2
, oldY2
};
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. */
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
) {
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
;
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
);
1063 RootlessStopDrawing(pWin
, FALSE
);
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
;
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.
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
;
1120 RL_DEBUG_MSG("movewindow start \n");
1123 if (kind
== VTMove
) {
1126 RootlessRedisplay(pWin
);
1127 RootlessStartDrawing(pWin
);
1129 RL_DEBUG_MSG("movewindow border resizing ");
1131 oldBW
= winRec
->borderWidth
;
1134 oldW
= winRec
->width
;
1135 oldH
= winRec
->height
;
1137 newBW
= wBorderWidth(pWin
);
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
);
1150 SCREEN_UNWRAP(pScreen
, MoveWindow
);
1153 oldCopyWindowProc
= pScreen
->CopyWindow
;
1154 pScreen
->CopyWindow
= RootlessNoCopyWindow
;
1156 pScreen
->MoveWindow(pWin
, x
, y
, pSib
, kind
);
1158 pScreen
->CopyWindow
= oldCopyWindowProc
;
1162 SCREEN_WRAP(pScreen
, MoveWindow
);
1165 if (kind
== VTMove
) {
1168 RootlessStopDrawing(pWin
, FALSE
);
1169 SCREENREC(pScreen
)->imp
->MoveFrame(winRec
->wid
, pScreen
,
1170 x
+ SCREEN_TO_GLOBAL_X
,
1171 y
+ SCREEN_TO_GLOBAL_Y
);
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.
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
;
1201 RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin
);
1204 oldBW
= winRec
->borderWidth
;
1207 oldW
= winRec
->width
;
1208 oldH
= winRec
->height
;
1216 resize_after
= StartFrameResize(pWin
, TRUE
,
1217 oldX
, oldY
, oldW
, oldH
, oldBW
,
1218 newX
, newY
, newW
, newH
, newBW
);
1222 SCREEN_UNWRAP(pScreen
, ResizeWindow
);
1223 pScreen
->ResizeWindow(pWin
, x
, y
, w
, h
, pSib
);
1224 SCREEN_WRAP(pScreen
, ResizeWindow
);
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
1244 RootlessRepositionWindow(WindowPtr pWin
)
1246 RootlessWindowRec
*winRec
= WINREC(pWin
);
1247 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
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.
1271 RootlessReparentWindow(WindowPtr pWin
, WindowPtr pPriorParent
)
1273 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
1274 RootlessWindowRec
*winRec
= WINREC(pWin
);
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
)
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
);
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
,
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
;
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.
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
1345 ChangeWindowAttributes(pWin
, CWBackPixel
, &pixel
, serverClient
);
1346 RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin
);
1350 pWin
= pWin
->parent
;
1351 pScreen
->SetWindowPixmap(pWin
, topWinRec
->pixmap
);
1357 * RootlessPaintWindowBackground
1360 RootlessPaintWindowBackground(WindowPtr pWin
, RegionPtr pRegion
, int what
)
1362 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
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
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
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
1422 * pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1423 * Frame moves and resizes.
1426 RootlessChangeBorderWidth(WindowPtr pWin
, unsigned int width
)
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;
1440 oldBW
= winRec
->borderWidth
;
1443 oldW
= winRec
->width
;
1444 oldH
= winRec
->height
;
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
);
1458 SCREEN_UNWRAP(pWin
->drawable
.pScreen
, ChangeBorderWidth
);
1459 pWin
->drawable
.pScreen
->ChangeBorderWidth(pWin
, width
);
1460 SCREEN_WRAP(pWin
->drawable
.pScreen
, ChangeBorderWidth
);
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");