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 */
39
#include <X11/Xatom.h>
43
#include "pixmapstr.h"
44
#include "windowstr.h"
45
//#include <X11/extensions/applewm.h>
46
extern int darwinMainScreenX, darwinMainScreenY;
47
extern Bool no_configure_window;
51
#include "rootlessCommon.h"
52
#include "rootlessWindow.h"
54
#define SCREEN_TO_GLOBAL_X \
55
(pScreen->x + rootlessGlobalOffsetX)
56
#define SCREEN_TO_GLOBAL_Y \
57
(pScreen->y + rootlessGlobalOffsetY)
59
#define DEFINE_ATOM_HELPER(func,atom_name) \
60
static Atom func (void) { \
61
static unsigned int generation = 0; \
63
if (generation != serverGeneration) { \
64
generation = serverGeneration; \
65
atom = MakeAtom (atom_name, strlen (atom_name), TRUE); \
70
DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID")
72
static Bool windows_hidden;
74
// TODO - abstract xp functions
78
// XXX: identical to x_cvt_vptr_to_uint ?
79
#define MAKE_WINDOW_ID(x) ((xp_window_id)((size_t)(x)))
82
RootlessNativeWindowStateChanged(WindowPtr pWin, unsigned int state)
84
RootlessWindowRec *winRec;
89
winRec = WINREC(pWin);
93
winRec->is_offscreen = ((state & XP_WINDOW_STATE_OFFSCREEN) != 0);
94
winRec->is_obscured = ((state & XP_WINDOW_STATE_OBSCURED) != 0);
95
pWin->rootlessUnhittable = winRec->is_offscreen;
99
RootlessNativeWindowMoved(WindowPtr pWin)
106
RootlessWindowRec *winRec;
108
winRec = WINREC(pWin);
110
if (xp_get_window_bounds(MAKE_WINDOW_ID(winRec->wid), &bounds) != Success)
113
sx = pWin->drawable.pScreen->x + darwinMainScreenX;
114
sy = pWin->drawable.pScreen->y + darwinMainScreenY;
116
/* Fake up a ConfigureWindow packet to resize the window to the current bounds. */
117
vlist[0] = (INT16) bounds.x1 - sx;
118
vlist[1] = (INT16) bounds.y1 - sy;
121
/* pretend we're the owner of the window! */
123
dixLookupClient(&pClient, pWin->drawable.id, serverClient,
125
if (err != Success) {
126
ErrorF("RootlessNativeWindowMoved(): Failed to lookup window: 0x%x\n",
127
(unsigned int) pWin->drawable.id);
131
/* Don't want to do anything to the physical window (avoids
132
notification-response feedback loops) */
134
no_configure_window = TRUE;
135
ConfigureWindow(pWin, mask, vlist, pClient);
136
no_configure_window = FALSE;
139
#endif /* __APPLE__ */
142
* RootlessCreateWindow
143
* For now, don't create a physical window until either the window is
144
* realized, or we really need it (e.g. to attach VRAM surfaces to).
145
* Do reset the window size so it's not clipped by the root window.
148
RootlessCreateWindow(WindowPtr pWin)
153
SETWINREC(pWin, NULL);
154
dixSetPrivate(&pWin->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL);
156
SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow);
159
/* win/border size set by DIX, not by wrapped CreateWindow, so
160
correct it here. Don't HUGE_ROOT when pWin is the root! */
167
result = pWin->drawable.pScreen->CreateWindow(pWin);
173
SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow);
179
* RootlessDestroyFrame
180
* Destroy the physical window associated with the given window.
183
RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec)
185
SCREENREC(pWin->drawable.pScreen)->imp->DestroyFrame(winRec->wid);
187
SETWINREC(pWin, NULL);
191
* RootlessDestroyWindow
192
* Destroy the physical window associated with the given window.
195
RootlessDestroyWindow(WindowPtr pWin)
197
RootlessWindowRec *winRec = WINREC(pWin);
200
if (winRec != NULL) {
201
RootlessDestroyFrame(pWin, winRec);
204
SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
205
result = pWin->drawable.pScreen->DestroyWindow(pWin);
206
SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
212
RootlessGetShape(WindowPtr pWin, RegionPtr pShape)
214
if (wBoundingShape(pWin) == NULL)
217
/* wBoundingShape is relative to *inner* origin of window.
218
Translate by borderWidth to get the outside-relative position. */
221
RegionCopy(pShape, wBoundingShape(pWin));
222
RegionTranslate(pShape, pWin->borderWidth, pWin->borderWidth);
228
* RootlessReshapeFrame
229
* Set the frame shape.
232
RootlessReshapeFrame(WindowPtr pWin)
234
RootlessWindowRec *winRec = WINREC(pWin);
238
// If the window is not yet framed, do nothing
245
RootlessStopDrawing(pWin, FALSE);
247
pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL;
250
RL_DEBUG_MSG("reshaping...");
251
if (pShape != NULL) {
252
RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ",
253
RegionNumRects(&newShape),
254
newShape.extents.x1, newShape.extents.y1,
255
newShape.extents.x2, newShape.extents.y2);
258
RL_DEBUG_MSG("no shape ");
262
SCREENREC(pWin->drawable.pScreen)->imp->ReshapeFrame(winRec->wid, pShape);
265
RegionUninit(&newShape);
270
* Shape is usually set before a window is mapped and the window will
271
* not have a frame associated with it. In this case, the frame will be
272
* shaped when the window is framed.
275
RootlessSetShape(WindowPtr pWin, int kind)
277
ScreenPtr pScreen = pWin->drawable.pScreen;
279
SCREEN_UNWRAP(pScreen, SetShape);
280
pScreen->SetShape(pWin, kind);
281
SCREEN_WRAP(pScreen, SetShape);
283
RootlessReshapeFrame(pWin);
286
/* Disallow ParentRelative background on top-level windows
287
because the root window doesn't really have the right background.
290
RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask)
293
ScreenPtr pScreen = pWin->drawable.pScreen;
295
RL_DEBUG_MSG("change window attributes start ");
297
SCREEN_UNWRAP(pScreen, ChangeWindowAttributes);
298
result = pScreen->ChangeWindowAttributes(pWin, vmask);
299
SCREEN_WRAP(pScreen, ChangeWindowAttributes);
302
// disallow ParentRelative background state
303
if (pWin->backgroundState == ParentRelative) {
306
ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
310
RL_DEBUG_MSG("change window attributes end\n");
315
* RootlessPositionWindow
316
* This is a hook for when DIX moves or resizes a window.
317
* Update the frame position now although the physical window is moved
318
* in RootlessMoveWindow. (x, y) are *inside* position. After this,
319
* mi and fb are expecting the pixmap to be at the new location.
322
RootlessPositionWindow(WindowPtr pWin, int x, int y)
324
ScreenPtr pScreen = pWin->drawable.pScreen;
325
RootlessWindowRec *winRec = WINREC(pWin);
328
RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y);
331
if (winRec->is_drawing) {
332
// Reset frame's pixmap and move it to the new position.
333
int bw = wBorderWidth(pWin);
335
winRec->pixmap->devPrivate.ptr = winRec->pixelData;
336
SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw);
340
SCREEN_UNWRAP(pScreen, PositionWindow);
341
result = pScreen->PositionWindow(pWin, x, y);
342
SCREEN_WRAP(pScreen, PositionWindow);
344
RL_DEBUG_MSG("positionwindow end\n");
349
* RootlessInitializeFrame
350
* Initialize some basic attributes of the frame. Note that winRec
351
* may already have valid data in it, so don't overwrite anything
355
RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec * winRec)
357
DrawablePtr d = &pWin->drawable;
358
int bw = wBorderWidth(pWin);
362
winRec->x = d->x - bw;
363
winRec->y = d->y - bw;
364
winRec->width = d->width + 2 * bw;
365
winRec->height = d->height + 2 * bw;
366
winRec->borderWidth = bw;
370
* RootlessEnsureFrame
371
* Make sure the given window is framed. If the window doesn't have a
372
* physical window associated with it, attempt to create one. If that
373
* is unsuccessful, return NULL.
375
static RootlessWindowRec *
376
RootlessEnsureFrame(WindowPtr pWin)
378
ScreenPtr pScreen = pWin->drawable.pScreen;
379
RootlessWindowRec *winRec;
381
RegionPtr pShape = NULL;
383
if (WINREC(pWin) != NULL)
386
if (!IsTopLevel(pWin) && !IsRoot(pWin))
389
if (pWin->drawable.class != InputOutput)
392
winRec = malloc(sizeof(RootlessWindowRec));
397
RootlessInitializeFrame(pWin, winRec);
399
winRec->is_drawing = FALSE;
400
winRec->is_reorder_pending = FALSE;
401
winRec->pixmap = NULL;
405
SETWINREC(pWin, winRec);
407
// Set the frame's shape if the window is shaped
408
if (RootlessGetShape(pWin, &shape))
411
RL_DEBUG_MSG("creating frame ");
413
if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen,
414
winRec->x + SCREEN_TO_GLOBAL_X,
415
winRec->y + SCREEN_TO_GLOBAL_Y,
417
RL_DEBUG_MSG("implementation failed to create frame!\n");
419
SETWINREC(pWin, NULL);
423
if (pWin->drawable.depth == 8)
424
RootlessFlushWindowColormap(pWin);
427
RegionUninit(&shape);
433
* RootlessRealizeWindow
434
* The frame is usually created here and not in CreateWindow so that
435
* windows do not eat memory until they are realized.
438
RootlessRealizeWindow(WindowPtr pWin)
442
ScreenPtr pScreen = pWin->drawable.pScreen;
444
RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin);
446
if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) {
447
RootlessWindowRec *winRec;
449
winRec = RootlessEnsureFrame(pWin);
453
winRec->is_reorder_pending = TRUE;
455
RL_DEBUG_MSG("Top level window ");
457
// Disallow ParentRelative background state on top-level windows.
458
// This might have been set before the window was mapped.
459
if (pWin->backgroundState == ParentRelative) {
462
ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
468
SCREEN_UNWRAP(pScreen, RealizeWindow);
469
result = pScreen->RealizeWindow(pWin);
470
SCREEN_WRAP(pScreen, RealizeWindow);
474
RL_DEBUG_MSG("realizewindow end\n");
479
* RootlessFrameForWindow
480
* Returns the frame ID for the physical window displaying the given window.
481
* If CREATE is true and the window has no frame, attempt to create one.
484
RootlessFrameForWindow(WindowPtr pWin, Bool create)
487
RootlessWindowRec *winRec;
489
pTopWin = TopLevelParent(pWin);
493
winRec = WINREC(pTopWin);
495
if (winRec == NULL && create && pWin->drawable.class == InputOutput) {
496
winRec = RootlessEnsureFrame(pTopWin);
506
* RootlessUnrealizeWindow
507
* Unmap the physical window.
510
RootlessUnrealizeWindow(WindowPtr pWin)
512
ScreenPtr pScreen = pWin->drawable.pScreen;
513
RootlessWindowRec *winRec = WINREC(pWin);
516
RL_DEBUG_MSG("unrealizewindow start ");
519
RootlessStopDrawing(pWin, FALSE);
521
SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
523
winRec->is_reorder_pending = FALSE;
526
SCREEN_UNWRAP(pScreen, UnrealizeWindow);
527
result = pScreen->UnrealizeWindow(pWin);
528
SCREEN_WRAP(pScreen, UnrealizeWindow);
530
RL_DEBUG_MSG("unrealizewindow end\n");
535
* RootlessReorderWindow
536
* Reorder the frame associated with the given window so that it's
537
* physically above the window below it in the X stacking order.
540
RootlessReorderWindow(WindowPtr pWin)
542
RootlessWindowRec *winRec = WINREC(pWin);
544
if (pWin->realized && winRec != NULL && !winRec->is_reorder_pending &&
547
RootlessWindowRec *newPrev;
548
RootlessFrameID newPrevID;
549
ScreenPtr pScreen = pWin->drawable.pScreen;
551
/* Check if the implementation wants the frame to not be reordered
552
even though the X11 window is restacked. This can be useful if
553
frames are ordered-in with animation so that the reordering is not
554
done until the animation is complete. */
555
if (SCREENREC(pScreen)->imp->DoReorderWindow) {
556
if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec))
560
RootlessStopDrawing(pWin, FALSE);
562
/* Find the next window above this one that has a mapped frame.
563
* Only include cases where the windows are in the same category of
564
* hittability to ensure offscreen windows dont get restacked
565
* relative to onscreen ones (but that the offscreen ones maintain
566
* their stacking order if they are explicitly asked to Reorder
569
newPrevW = pWin->prevSib;
571
(WINREC(newPrevW) == NULL || !newPrevW->realized ||
572
newPrevW->rootlessUnhittable != pWin->rootlessUnhittable))
573
newPrevW = newPrevW->prevSib;
575
newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
576
newPrevID = newPrev != NULL ? newPrev->wid : 0;
578
/* If it exists, reorder the frame above us first. */
580
if (newPrev && newPrev->is_reorder_pending) {
581
newPrev->is_reorder_pending = FALSE;
582
RootlessReorderWindow(newPrevW);
585
SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
590
* RootlessRestackWindow
591
* This is a hook for when DIX changes the window stacking order.
592
* The window has already been inserted into its new position in the
593
* DIX window stack. We need to change the order of the physical
597
RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
600
RootlessWindowRec *winRec = WINREC(pWin);
601
ScreenPtr pScreen = pWin->drawable.pScreen;
603
RL_DEBUG_MSG("restackwindow start ");
605
RL_DEBUG_MSG("restack top level \n");
608
SCREEN_UNWRAP(pScreen, RestackWindow);
610
if (pScreen->RestackWindow)
611
pScreen->RestackWindow(pWin, pOldNextSib);
613
SCREEN_WRAP(pScreen, RestackWindow);
616
if (winRec && pWin->viewable) {
617
RootlessReorderWindow(pWin);
620
RL_DEBUG_MSG("restackwindow end\n");
624
* Specialized window copy procedures
627
// Globals needed during window resize and move.
628
static void *gResizeDeathBits = NULL;
629
static int gResizeDeathCount = 0;
630
static PixmapPtr gResizeDeathPix[2] = { NULL, NULL };
632
static BoxRec gResizeDeathBounds[2];
633
static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
636
* RootlessNoCopyWindow
637
* CopyWindow() that doesn't do anything. For MoveWindow() of
641
RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
643
// some code expects the region to be translated
644
int dx = ptOldOrg.x - pWin->drawable.x;
645
int dy = ptOldOrg.y - pWin->drawable.y;
647
RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW ");
649
RegionTranslate(prgnSrc, -dx, -dy);
653
* RootlessResizeCopyWindow
654
* CopyWindow used during ResizeWindow for gravity moves. Based on
655
* fbCopyWindow. The original always draws on the root pixmap, which
656
* we don't have. Instead, draw on the parent window's pixmap.
657
* Resize version: the old location's pixels are in gResizeCopyWindowSource.
660
RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
663
ScreenPtr pScreen = pWin->drawable.pScreen;
667
RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
669
/* Don't unwrap pScreen->CopyWindow.
670
The bogus rewrap with RootlessCopyWindow causes a crash if
671
CopyWindow is called again during the same resize. */
673
if (gResizeDeathCount == 0)
676
RootlessStartDrawing(pWin);
678
dx = ptOldOrg.x - pWin->drawable.x;
679
dy = ptOldOrg.y - pWin->drawable.y;
680
RegionTranslate(prgnSrc, -dx, -dy);
682
RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
684
if (gResizeDeathCount == 1) {
685
/* Simple case, we only have a single source pixmap. */
687
miCopyRegion(&gResizeDeathPix[0]->drawable,
688
&pScreen->GetWindowPixmap(pWin)->drawable, 0,
689
&rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
693
RegionRec clip, clipped;
695
/* More complex case, N source pixmaps (usually two). So we
696
intersect the destination with each source and copy those bits. */
698
for (i = 0; i < gResizeDeathCount; i++) {
699
RegionInit(&clip, gResizeDeathBounds + 0, 1);
700
RegionNull(&clipped);
701
RegionIntersect(&rgnDst, &clip, &clipped);
703
miCopyRegion(&gResizeDeathPix[i]->drawable,
704
&pScreen->GetWindowPixmap(pWin)->drawable, 0,
705
&clipped, dx, dy, fbCopyWindowProc, 0, 0);
707
RegionUninit(&clipped);
712
/* Don't update - resize will update everything */
713
RegionUninit(&rgnDst);
715
fbValidateDrawable(&pWin->drawable);
717
RL_DEBUG_MSG("resizecopywindowFB end\n");
722
* Update *new* location of window. Old location is redrawn with
723
* miPaintWindow. Cloned from fbCopyWindow.
724
* The original always draws on the root pixmap, which we don't have.
725
* Instead, draw on the parent window's pixmap.
728
RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
730
ScreenPtr pScreen = pWin->drawable.pScreen;
736
RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin);
738
SCREEN_UNWRAP(pScreen, CopyWindow);
740
dx = ptOldOrg.x - pWin->drawable.x;
741
dy = ptOldOrg.y - pWin->drawable.y;
742
RegionTranslate(prgnSrc, -dx, -dy);
745
RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
747
extents = RegionExtents(&rgnDst);
748
area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
750
/* If the area exceeds threshold, use the implementation's
751
accelerated version. */
752
if (area > rootless_CopyWindow_threshold &&
753
SCREENREC(pScreen)->imp->CopyWindow) {
754
RootlessWindowRec *winRec;
757
top = TopLevelParent(pWin);
759
RL_DEBUG_MSG("no parent\n");
763
winRec = WINREC(top);
764
if (winRec == NULL) {
765
RL_DEBUG_MSG("not framed\n");
769
/* Move region to window local coords */
770
RegionTranslate(&rgnDst, -winRec->x, -winRec->y);
772
RootlessStopDrawing(pWin, FALSE);
774
SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
775
RegionNumRects(&rgnDst),
776
RegionRects(&rgnDst), dx, dy);
779
RootlessStartDrawing(pWin);
781
miCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
782
0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
784
/* prgnSrc has been translated to dst position */
785
RootlessDamageRegion(pWin, prgnSrc);
789
RegionUninit(&rgnDst);
790
fbValidateDrawable(&pWin->drawable);
792
SCREEN_WRAP(pScreen, CopyWindow);
794
RL_DEBUG_MSG("copywindowFB end\n");
798
* Window resize procedures
808
* Choose gravity to avoid local copies. Do that by looking for
809
* a corner that doesn't move _relative to the screen_.
811
static inline unsigned int
812
ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
813
int newX1, int newY1, int newX2, int newY2, int newBW)
815
#ifdef ROOTLESS_RESIZE_GRAVITY
817
return RL_GRAVITY_NONE;
819
if (newX1 == oldX1 && newY1 == oldY1)
820
return RL_GRAVITY_NORTH_WEST;
821
else if (newX1 == oldX1 && newY2 == oldY2)
822
return RL_GRAVITY_SOUTH_WEST;
823
else if (newX2 == oldX2 && newY2 == oldY2)
824
return RL_GRAVITY_SOUTH_EAST;
825
else if (newX2 == oldX2 && newY1 == oldY1)
826
return RL_GRAVITY_NORTH_EAST;
828
return RL_GRAVITY_NONE;
830
return RL_GRAVITY_NONE;
836
* Prepare to resize a top-level window. The old window's pixels are
837
* saved and the implementation is told to change the window size.
838
* (x,y,w,h) is outer frame of window (outside border)
841
StartFrameResize(WindowPtr pWin, Bool gravity,
842
int oldX, int oldY, int oldW, int oldH, int oldBW,
843
int newX, int newY, int newW, int newH, int newBW)
845
ScreenPtr pScreen = pWin->drawable.pScreen;
846
RootlessWindowRec *winRec = WINREC(pWin);
847
Bool need_window_source = FALSE, resize_after = FALSE;
854
oldX2 = oldX + oldW, newX2 = newX + newW;
855
oldY2 = oldY + oldH, newY2 = newY + newH;
857
/* Decide which resize weighting to use */
858
weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
859
newX, newY, newW, newH, newBW);
861
/* Compute intersection between old and new rects */
862
rect.x1 = max(oldX, newX);
863
rect.y1 = max(oldY, newY);
864
rect.x2 = min(oldX2, newX2);
865
rect.y2 = min(oldY2, newY2);
867
RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
868
RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n",
869
oldX, oldY, oldW, oldH, oldBW, newX, newY, newW, newH, newBW);
871
RootlessRedisplay(pWin);
873
/* If gravity is true, then we need to have a way of recovering all
874
the original bits in the window for when X rearranges the contents
875
based on the various gravity settings. The obvious way is to just
876
snapshot the entire backing store before resizing it, but that
877
it slow on large windows.
879
So the optimization here is to use the implementation's resize
880
weighting options (if available) to allow us to reason about what
881
is left in the backing store after the resize. We can then only
882
copy what won't be there after the resize, and do a two-stage copy
885
Most of these optimizations are only applied when the top-left
886
corner of the window is fixed, since that's the common case. They
887
could probably be extended with some thought. */
889
gResizeDeathCount = 0;
891
if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
892
unsigned int code = 0;
894
/* Top left corner is anchored. We never need to copy the
897
need_window_source = TRUE;
899
/* These comparisons were chosen to avoid setting bits when the sizes
900
are the same. (So the fastest case automatically gets taken when
901
dimensions are unchanging.) */
904
code |= WIDTH_SMALLER;
906
code |= HEIGHT_SMALLER;
908
if (((code ^ (code >> 1)) & 1) == 0) {
909
/* Both dimensions are either getting larger, or both
910
are getting smaller. No need to copy anything. */
912
if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
913
/* Since the window is getting smaller, we can do gravity
914
repair on it with it's current size, then resize it
920
gResizeDeathCount = 1;
923
unsigned int copy_rowbytes, Bpp;
924
unsigned int copy_rect_width, copy_rect_height;
927
/* We can get away with a partial copy. 'rect' is the
928
intersection between old and new bounds, so copy
929
everything to the right of or below the intersection. */
931
RootlessStartDrawing(pWin);
933
if (code == WIDTH_SMALLER) {
934
copy_rect.x1 = rect.x2;
935
copy_rect.y1 = rect.y1;
936
copy_rect.x2 = oldX2;
937
copy_rect.y2 = oldY2;
939
else if (code == HEIGHT_SMALLER) {
940
copy_rect.x1 = rect.x1;
941
copy_rect.y1 = rect.y2;
942
copy_rect.x2 = oldX2;
943
copy_rect.y2 = oldY2;
948
Bpp = winRec->win->drawable.bitsPerPixel / 8;
949
copy_rect_width = copy_rect.x2 - copy_rect.x1;
950
copy_rect_height = copy_rect.y2 - copy_rect.y1;
951
copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
952
gResizeDeathBits = malloc(copy_rowbytes * copy_rect_height);
954
if (copy_rect_width * copy_rect_height >
955
rootless_CopyBytes_threshold &&
956
SCREENREC(pScreen)->imp->CopyBytes) {
957
SCREENREC(pScreen)->imp->CopyBytes(copy_rect_width * Bpp,
959
((char *) winRec->pixelData)
971
fbBlt((FbBits *) (winRec->pixelData
973
((copy_rect.y1 - oldY) * winRec->bytesPerRow)
974
+ (copy_rect.x1 - oldX) * Bpp),
975
winRec->bytesPerRow / sizeof(FbBits), 0,
976
(FbBits *) gResizeDeathBits,
977
copy_rowbytes / sizeof(FbBits), 0, copy_rect_width * Bpp,
978
copy_rect_height, GXcopy, FB_ALLONES, Bpp, 0, 0);
981
gResizeDeathBounds[1] = copy_rect;
983
= GetScratchPixmapHeader(pScreen, copy_rect_width,
985
winRec->win->drawable.depth,
986
winRec->win->drawable.bitsPerPixel,
988
(void *) gResizeDeathBits);
990
SetPixmapBaseToScreen(gResizeDeathPix[1],
991
copy_rect.x1, copy_rect.y1);
993
gResizeDeathCount = 2;
997
/* The general case. Just copy everything. */
999
RootlessStartDrawing(pWin);
1001
gResizeDeathBits = malloc(winRec->bytesPerRow * winRec->height);
1003
memcpy(gResizeDeathBits, winRec->pixelData,
1004
winRec->bytesPerRow * winRec->height);
1006
gResizeDeathBounds[0] = (BoxRec) {
1007
oldX, oldY, oldX2, oldY2};
1009
= GetScratchPixmapHeader(pScreen, winRec->width,
1011
winRec->win->drawable.depth,
1012
winRec->win->drawable.bitsPerPixel,
1013
winRec->bytesPerRow,
1014
(void *) gResizeDeathBits);
1016
SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1017
gResizeDeathCount = 1;
1020
RootlessStopDrawing(pWin, FALSE);
1024
winRec->width = newW;
1025
winRec->height = newH;
1026
winRec->borderWidth = newBW;
1028
/* Unless both dimensions are getting smaller, Resize the frame
1029
before doing gravity repair */
1031
if (!resize_after) {
1032
SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1033
newX + SCREEN_TO_GLOBAL_X,
1034
newY + SCREEN_TO_GLOBAL_Y,
1035
newW, newH, weight);
1038
RootlessStartDrawing(pWin);
1040
/* If necessary, create a source pixmap pointing at the current
1043
if (need_window_source) {
1044
gResizeDeathBounds[0] = (BoxRec) {
1045
oldX, oldY, oldX2, oldY2};
1047
= GetScratchPixmapHeader(pScreen, oldW, oldH,
1048
winRec->win->drawable.depth,
1049
winRec->win->drawable.bitsPerPixel,
1050
winRec->bytesPerRow, winRec->pixelData);
1052
SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1055
/* Use custom CopyWindow when moving gravity bits around
1056
ResizeWindow assumes the old window contents are in the same
1057
pixmap, but here they're in deathPix instead. */
1060
gResizeOldCopyWindowProc = pScreen->CopyWindow;
1061
pScreen->CopyWindow = RootlessResizeCopyWindow;
1064
/* If we can't rely on the window server preserving the bits we
1065
need in the position we need, copy the pixels in the
1066
intersection from src to dst. ResizeWindow assumes these pixels
1067
are already present when making gravity adjustments. pWin
1068
currently has new-sized pixmap but is in old position.
1070
FIXME: border width change! (?) */
1072
if (gravity && weight == RL_GRAVITY_NONE) {
1075
assert(gResizeDeathCount == 1);
1077
src = gResizeDeathPix[0];
1078
dst = pScreen->GetWindowPixmap(pWin);
1080
RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1081
rect.x1, rect.y1, rect.x2, rect.y2);
1083
/* rect is the intersection of the old location and new location */
1084
if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
1085
/* The window drawable still has the old frame position, which
1086
means that DST doesn't actually point at the origin of our
1087
physical backing store when adjusted by the drawable.x,y
1088
position. So sneakily adjust it temporarily while copying.. */
1090
((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1091
SetPixmapBaseToScreen(dst, newX, newY);
1093
fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1094
&rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1096
((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1097
SetPixmapBaseToScreen(dst, oldX, oldY);
1101
return resize_after;
1105
FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
1106
unsigned int oldW, unsigned int oldH, unsigned int oldBW,
1107
int newX, int newY, unsigned int newW, unsigned int newH,
1108
unsigned int newBW, Bool resize_now)
1110
ScreenPtr pScreen = pWin->drawable.pScreen;
1111
RootlessWindowRec *winRec = WINREC(pWin);
1114
RootlessStopDrawing(pWin, FALSE);
1117
unsigned int weight;
1119
/* We didn't resize anything earlier, so do it now, now that
1120
we've finished gravitating the bits. */
1122
weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
1123
newX, newY, newW, newH, newBW);
1125
SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1126
newX + SCREEN_TO_GLOBAL_X,
1127
newY + SCREEN_TO_GLOBAL_Y,
1128
newW, newH, weight);
1131
/* Redraw everything. FIXME: there must be times when we don't need
1132
to do this. Perhaps when top-left weighting and no gravity? */
1134
RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
1136
for (i = 0; i < 2; i++) {
1137
if (gResizeDeathPix[i] != NULL) {
1138
FreeScratchPixmapHeader(gResizeDeathPix[i]);
1139
gResizeDeathPix[i] = NULL;
1143
free(gResizeDeathBits);
1144
gResizeDeathBits = NULL;
1147
pScreen->CopyWindow = gResizeOldCopyWindowProc;
1152
* RootlessMoveWindow
1153
* If kind==VTOther, window border is resizing (and borderWidth is
1154
* already changed!!@#$) This case works like window resize, not move.
1157
RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1159
RootlessWindowRec *winRec = WINREC(pWin);
1160
ScreenPtr pScreen = pWin->drawable.pScreen;
1161
CopyWindowProcPtr oldCopyWindowProc = NULL;
1162
int oldX = 0, oldY = 0, newX = 0, newY = 0;
1163
unsigned int oldW = 0, oldH = 0, oldBW = 0;
1164
unsigned int newW = 0, newH = 0, newBW = 0;
1165
Bool resize_after = FALSE;
1168
RL_DEBUG_MSG("movewindow start \n");
1171
if (kind == VTMove) {
1174
RootlessRedisplay(pWin);
1175
RootlessStartDrawing(pWin);
1178
RL_DEBUG_MSG("movewindow border resizing ");
1180
oldBW = winRec->borderWidth;
1183
oldW = winRec->width;
1184
oldH = winRec->height;
1186
newBW = wBorderWidth(pWin);
1189
newW = pWin->drawable.width + 2 * newBW;
1190
newH = pWin->drawable.height + 2 * newBW;
1192
resize_after = StartFrameResize(pWin, FALSE,
1193
oldX, oldY, oldW, oldH, oldBW,
1194
newX, newY, newW, newH, newBW);
1199
SCREEN_UNWRAP(pScreen, MoveWindow);
1202
oldCopyWindowProc = pScreen->CopyWindow;
1203
pScreen->CopyWindow = RootlessNoCopyWindow;
1205
pScreen->MoveWindow(pWin, x, y, pSib, kind);
1207
pScreen->CopyWindow = oldCopyWindowProc;
1211
SCREEN_WRAP(pScreen, MoveWindow);
1214
if (kind == VTMove) {
1217
RootlessStopDrawing(pWin, FALSE);
1218
SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1219
x + SCREEN_TO_GLOBAL_X,
1220
y + SCREEN_TO_GLOBAL_Y);
1223
FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1224
newX, newY, newW, newH, newBW, resize_after);
1228
RL_DEBUG_MSG("movewindow end\n");
1232
* RootlessResizeWindow
1233
* Note: (x, y, w, h) as passed to this procedure don't match the frame
1234
* definition. (x,y) is corner of very outer edge, *outside* border.
1235
* w,h is width and height *inside* border, *ignoring* border width.
1236
* The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
1237
* is total rect and (x+bw, y+bw, w, h) is inner rect.
1240
RootlessResizeWindow(WindowPtr pWin, int x, int y,
1241
unsigned int w, unsigned int h, WindowPtr pSib)
1243
RootlessWindowRec *winRec = WINREC(pWin);
1244
ScreenPtr pScreen = pWin->drawable.pScreen;
1245
int oldX = 0, oldY = 0, newX = 0, newY = 0;
1246
unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
1247
Bool resize_after = FALSE;
1250
RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
1254
oldBW = winRec->borderWidth;
1257
oldW = winRec->width;
1258
oldH = winRec->height;
1263
newW = w + 2 * newBW;
1264
newH = h + 2 * newBW;
1266
resize_after = StartFrameResize(pWin, TRUE,
1267
oldX, oldY, oldW, oldH, oldBW,
1268
newX, newY, newW, newH, newBW);
1272
SCREEN_UNWRAP(pScreen, ResizeWindow);
1273
pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
1274
SCREEN_WRAP(pScreen, ResizeWindow);
1278
FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
1279
newX, newY, newW, newH, newBW, resize_after);
1283
/* Special case for resizing the root window */
1286
pWin->drawable.x = x;
1287
pWin->drawable.y = y;
1288
pWin->drawable.width = w;
1289
pWin->drawable.height = h;
1295
RegionUninit(&pWin->winSize);
1296
RegionInit(&pWin->winSize, &box, 1);
1297
RegionCopy(&pWin->borderSize, &pWin->winSize);
1298
RegionCopy(&pWin->clipList, &pWin->winSize);
1299
RegionCopy(&pWin->borderClip, &pWin->winSize);
1302
SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1303
x + SCREEN_TO_GLOBAL_X,
1304
y + SCREEN_TO_GLOBAL_Y,
1305
w, h, RL_GRAVITY_NONE);
1308
miSendExposures(pWin, &pWin->borderClip,
1309
pWin->drawable.x, pWin->drawable.y);
1312
RL_DEBUG_MSG("resizewindow end\n");
1316
* RootlessRepositionWindow
1317
* Called by the implementation when a window needs to be repositioned to
1318
* its correct location on the screen. This routine is typically needed
1319
* due to changes in the underlying window system, such as a screen layout
1323
RootlessRepositionWindow(WindowPtr pWin)
1325
RootlessWindowRec *winRec = WINREC(pWin);
1326
ScreenPtr pScreen = pWin->drawable.pScreen;
1331
RootlessStopDrawing(pWin, FALSE);
1332
SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1333
winRec->x + SCREEN_TO_GLOBAL_X,
1334
winRec->y + SCREEN_TO_GLOBAL_Y);
1336
RootlessReorderWindow(pWin);
1340
* RootlessReparentWindow
1341
* Called after a window has been reparented. Generally windows are not
1342
* framed until they are mapped. However, a window may be framed early by the
1343
* implementation calling RootlessFrameForWindow. (e.g. this could be needed
1344
* to attach a VRAM surface to it.) If the window is subsequently reparented
1345
* by the window manager before being mapped, we need to give the frame to
1346
* the new top-level window.
1349
RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
1351
ScreenPtr pScreen = pWin->drawable.pScreen;
1352
RootlessWindowRec *winRec = WINREC(pWin);
1355
/* Check that window is not top-level now, but used to be. */
1356
if (IsRoot(pWin) || IsRoot(pWin->parent)
1357
|| IsTopLevel(pWin) || winRec == NULL) {
1361
/* If the formerly top-level window has a frame, we want to give the
1362
frame to its new top-level parent. If we can't do that, we'll just
1363
have to jettison it... */
1365
pTopWin = TopLevelParent(pWin);
1366
assert(pTopWin != pWin);
1368
pWin->rootlessUnhittable = FALSE;
1370
DeleteProperty(serverClient, pWin, xa_native_window_id());
1372
if (WINREC(pTopWin) != NULL) {
1373
/* We're screwed. */
1374
RootlessDestroyFrame(pWin, winRec);
1377
if (!pTopWin->realized && pWin->realized) {
1378
SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
1381
/* Switch the frame record from one to the other. */
1383
SETWINREC(pWin, NULL);
1384
SETWINREC(pTopWin, winRec);
1386
RootlessInitializeFrame(pTopWin, winRec);
1387
RootlessReshapeFrame(pTopWin);
1389
SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1390
winRec->x + SCREEN_TO_GLOBAL_X,
1391
winRec->y + SCREEN_TO_GLOBAL_Y,
1392
winRec->width, winRec->height,
1395
if (SCREENREC(pScreen)->imp->SwitchWindow) {
1396
SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
1399
if (pTopWin->realized && !pWin->realized)
1400
winRec->is_reorder_pending = TRUE;
1404
if (SCREENREC(pScreen)->ReparentWindow) {
1405
SCREEN_UNWRAP(pScreen, ReparentWindow);
1406
pScreen->ReparentWindow(pWin, pPriorParent);
1407
SCREEN_WRAP(pScreen, ReparentWindow);
1412
RootlessFlushWindowColormap(WindowPtr pWin)
1414
RootlessWindowRec *winRec = WINREC(pWin);
1415
ScreenPtr pScreen = pWin->drawable.pScreen;
1420
RootlessStopDrawing(pWin, FALSE);
1422
if (SCREENREC(pScreen)->imp->UpdateColormap)
1423
SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen);
1427
* RootlessChangeBorderWidth
1429
* pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1430
* Frame moves and resizes.
1433
RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
1436
Bool resize_after = FALSE;
1438
RL_DEBUG_MSG("change border width ");
1440
if (width != wBorderWidth(pWin)) {
1441
RootlessWindowRec *winRec = WINREC(pWin);
1442
int oldX = 0, oldY = 0, newX = 0, newY = 0;
1443
unsigned int oldW = 0, oldH = 0, oldBW = 0;
1444
unsigned int newW = 0, newH = 0, newBW = 0;
1447
oldBW = winRec->borderWidth;
1450
oldW = winRec->width;
1451
oldH = winRec->height;
1454
newX = pWin->drawable.x - newBW;
1455
newY = pWin->drawable.y - newBW;
1456
newW = pWin->drawable.width + 2 * newBW;
1457
newH = pWin->drawable.height + 2 * newBW;
1459
resize_after = StartFrameResize(pWin, FALSE,
1460
oldX, oldY, oldW, oldH, oldBW,
1461
newX, newY, newW, newH, newBW);
1465
SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1466
pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
1467
SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1471
FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1472
newX, newY, newW, newH, newBW, resize_after);
1476
RL_DEBUG_MSG("change border width end\n");
1480
* RootlessOrderAllWindows
1481
* Brings all X11 windows to the top of the window stack
1482
* (i.e in front of Aqua windows) -- called when X11.app is given focus
1485
RootlessOrderAllWindows(Bool include_unhitable)
1493
RL_DEBUG_MSG("RootlessOrderAllWindows() ");
1494
for (i = 0; i < screenInfo.numScreens; i++) {
1495
if (screenInfo.screens[i] == NULL)
1497
pWin = screenInfo.screens[i]->root;
1501
for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1502
if (!pWin->realized)
1504
if (RootlessEnsureFrame(pWin) == NULL)
1506
if (!include_unhitable && pWin->rootlessUnhittable)
1508
RootlessReorderWindow(pWin);
1511
RL_DEBUG_MSG("RootlessOrderAllWindows() done");
1515
RootlessEnableRoot(ScreenPtr pScreen)
1519
pRoot = pScreen->root;
1521
RootlessEnsureFrame(pRoot);
1522
(*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
1523
RootlessReorderWindow(pRoot);
1527
RootlessDisableRoot(ScreenPtr pScreen)
1530
RootlessWindowRec *winRec;
1532
pRoot = pScreen->root;
1533
winRec = WINREC(pRoot);
1538
RootlessDestroyFrame(pRoot, winRec);
1539
DeleteProperty(serverClient, pRoot, xa_native_window_id());
1543
RootlessHideAllWindows(void)
1548
RootlessWindowRec *winRec;
1553
windows_hidden = TRUE;
1555
for (i = 0; i < screenInfo.numScreens; i++) {
1556
pScreen = screenInfo.screens[i];
1557
if (pScreen == NULL)
1559
pWin = pScreen->root;
1563
for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1564
if (!pWin->realized)
1567
RootlessStopDrawing(pWin, FALSE);
1569
winRec = WINREC(pWin);
1570
if (winRec != NULL) {
1571
if (SCREENREC(pScreen)->imp->HideWindow)
1572
SCREENREC(pScreen)->imp->HideWindow(winRec->wid);
1579
RootlessShowAllWindows(void)
1584
RootlessWindowRec *winRec;
1586
if (!windows_hidden)
1589
windows_hidden = FALSE;
1591
for (i = 0; i < screenInfo.numScreens; i++) {
1592
pScreen = screenInfo.screens[i];
1593
if (pScreen == NULL)
1595
pWin = pScreen->root;
1599
for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1600
if (!pWin->realized)
1603
winRec = RootlessEnsureFrame(pWin);
1607
RootlessReorderWindow(pWin);
1610
RootlessScreenExpose(pScreen);
1615
* SetPixmapOfAncestors
1616
* Set the Pixmaps on all ParentRelative windows up the ancestor chain.
1619
RootlessSetPixmapOfAncestors(WindowPtr pWin)
1621
ScreenPtr pScreen = pWin->drawable.pScreen;
1622
WindowPtr topWin = TopLevelParent(pWin);
1623
RootlessWindowRec *topWinRec = WINREC(topWin);
1625
while (pWin->backgroundState == ParentRelative) {
1626
if (pWin == topWin) {
1627
// disallow ParentRelative background state on top level
1630
ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
1631
RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
1635
pWin = pWin->parent;
1636
pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);