tizen 2.4 release
[framework/uifw/xorg/server/xorg-server.git] / miext / rootless / rootlessWindow.c
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.
8  *
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:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
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.
26  *
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.
30  */
31
32 #ifdef HAVE_DIX_CONFIG_H
33 #include <dix-config.h>
34 #endif
35
36 #include <stddef.h>             /* For NULL */
37 #include <limits.h>             /* For CHAR_BIT */
38 #include <assert.h>
39 #include <X11/Xatom.h>
40 #ifdef __APPLE__
41 #include <Xplugin.h>
42 #include "mi.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;
48 #endif
49 #include "fb.h"
50
51 #include "rootlessCommon.h"
52 #include "rootlessWindow.h"
53
54 #define SCREEN_TO_GLOBAL_X \
55     (pScreen->x + rootlessGlobalOffsetX)
56 #define SCREEN_TO_GLOBAL_Y \
57     (pScreen->y + rootlessGlobalOffsetY)
58
59 #define DEFINE_ATOM_HELPER(func,atom_name)                      \
60   static Atom func (void) {                                       \
61     static unsigned int generation = 0;                             \
62     static Atom atom;                                           \
63     if (generation != serverGeneration) {                       \
64       generation = serverGeneration;                          \
65       atom = MakeAtom (atom_name, strlen (atom_name), TRUE);  \
66     }                                                           \
67     return atom;                                                \
68   }
69
70 DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID")
71
72 static Bool windows_hidden;
73
74 // TODO - abstract xp functions
75
76 #ifdef __APPLE__
77
78 // XXX: identical to x_cvt_vptr_to_uint ?
79 #define MAKE_WINDOW_ID(x)               ((xp_window_id)((size_t)(x)))
80
81 void
82 RootlessNativeWindowStateChanged(WindowPtr pWin, unsigned int state)
83 {
84     RootlessWindowRec *winRec;
85
86     if (pWin == NULL)
87         return;
88
89     winRec = WINREC(pWin);
90     if (winRec == NULL)
91         return;
92
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;
96 }
97
98 void
99 RootlessNativeWindowMoved(WindowPtr pWin)
100 {
101     xp_box bounds;
102     int sx, sy, err;
103     XID vlist[2];
104     Mask mask;
105     ClientPtr pClient;
106     RootlessWindowRec *winRec;
107
108     winRec = WINREC(pWin);
109
110     if (xp_get_window_bounds(MAKE_WINDOW_ID(winRec->wid), &bounds) != Success)
111         return;
112
113     sx = pWin->drawable.pScreen->x + darwinMainScreenX;
114     sy = pWin->drawable.pScreen->y + darwinMainScreenY;
115
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;
119     mask = CWX | CWY;
120
121     /* pretend we're the owner of the window! */
122     err =
123         dixLookupClient(&pClient, pWin->drawable.id, serverClient,
124                         DixUnknownAccess);
125     if (err != Success) {
126         ErrorF("RootlessNativeWindowMoved(): Failed to lookup window: 0x%x\n",
127                (unsigned int) pWin->drawable.id);
128         return;
129     }
130
131     /* Don't want to do anything to the physical window (avoids 
132        notification-response feedback loops) */
133
134     no_configure_window = TRUE;
135     ConfigureWindow(pWin, mask, vlist, pClient);
136     no_configure_window = FALSE;
137 }
138
139 #endif                          /* __APPLE__ */
140
141 /*
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.
146  */
147 Bool
148 RootlessCreateWindow(WindowPtr pWin)
149 {
150     Bool result;
151     RegionRec saveRoot;
152
153     SETWINREC(pWin, NULL);
154     dixSetPrivate(&pWin->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL);
155
156     SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow);
157
158     if (!IsRoot(pWin)) {
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! */
161
162         HUGE_ROOT(pWin);
163         SetWinSize(pWin);
164         SetBorderSize(pWin);
165     }
166
167     result = pWin->drawable.pScreen->CreateWindow(pWin);
168
169     if (pWin->parent) {
170         NORMAL_ROOT(pWin);
171     }
172
173     SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow);
174
175     return result;
176 }
177
178 /*
179  * RootlessDestroyFrame
180  *  Destroy the physical window associated with the given window.
181  */
182 static void
183 RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec)
184 {
185     SCREENREC(pWin->drawable.pScreen)->imp->DestroyFrame(winRec->wid);
186     free(winRec);
187     SETWINREC(pWin, NULL);
188 }
189
190 /*
191  * RootlessDestroyWindow
192  *  Destroy the physical window associated with the given window.
193  */
194 Bool
195 RootlessDestroyWindow(WindowPtr pWin)
196 {
197     RootlessWindowRec *winRec = WINREC(pWin);
198     Bool result;
199
200     if (winRec != NULL) {
201         RootlessDestroyFrame(pWin, winRec);
202     }
203
204     SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
205     result = pWin->drawable.pScreen->DestroyWindow(pWin);
206     SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
207
208     return result;
209 }
210
211 static Bool
212 RootlessGetShape(WindowPtr pWin, RegionPtr pShape)
213 {
214     if (wBoundingShape(pWin) == NULL)
215         return FALSE;
216
217     /* wBoundingShape is relative to *inner* origin of window.
218        Translate by borderWidth to get the outside-relative position. */
219
220     RegionNull(pShape);
221     RegionCopy(pShape, wBoundingShape(pWin));
222     RegionTranslate(pShape, pWin->borderWidth, pWin->borderWidth);
223
224     return TRUE;
225 }
226
227 /*
228  * RootlessReshapeFrame
229  *  Set the frame shape.
230  */
231 static void
232 RootlessReshapeFrame(WindowPtr pWin)
233 {
234     RootlessWindowRec *winRec = WINREC(pWin);
235     RegionRec newShape;
236     RegionPtr pShape;
237
238     // If the window is not yet framed, do nothing
239     if (winRec == NULL)
240         return;
241
242     if (IsRoot(pWin))
243         return;
244
245     RootlessStopDrawing(pWin, FALSE);
246
247     pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL;
248
249 #ifdef ROOTLESSDEBUG
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);
256     }
257     else {
258         RL_DEBUG_MSG("no shape ");
259     }
260 #endif
261
262     SCREENREC(pWin->drawable.pScreen)->imp->ReshapeFrame(winRec->wid, pShape);
263
264     if (pShape != NULL)
265         RegionUninit(&newShape);
266 }
267
268 /*
269  * RootlessSetShape
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.
273  */
274 void
275 RootlessSetShape(WindowPtr pWin, int kind)
276 {
277     ScreenPtr pScreen = pWin->drawable.pScreen;
278
279     SCREEN_UNWRAP(pScreen, SetShape);
280     pScreen->SetShape(pWin, kind);
281     SCREEN_WRAP(pScreen, SetShape);
282
283     RootlessReshapeFrame(pWin);
284 }
285
286 /* Disallow ParentRelative background on top-level windows
287    because the root window doesn't really have the right background.
288  */
289 Bool
290 RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask)
291 {
292     Bool result;
293     ScreenPtr pScreen = pWin->drawable.pScreen;
294
295     RL_DEBUG_MSG("change window attributes start ");
296
297     SCREEN_UNWRAP(pScreen, ChangeWindowAttributes);
298     result = pScreen->ChangeWindowAttributes(pWin, vmask);
299     SCREEN_WRAP(pScreen, ChangeWindowAttributes);
300
301     if (WINREC(pWin)) {
302         // disallow ParentRelative background state
303         if (pWin->backgroundState == ParentRelative) {
304             XID pixel = 0;
305
306             ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
307         }
308     }
309
310     RL_DEBUG_MSG("change window attributes end\n");
311     return result;
312 }
313
314 /*
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.
320  */
321 Bool
322 RootlessPositionWindow(WindowPtr pWin, int x, int y)
323 {
324     ScreenPtr pScreen = pWin->drawable.pScreen;
325     RootlessWindowRec *winRec = WINREC(pWin);
326     Bool result;
327
328     RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y);
329
330     if (winRec) {
331         if (winRec->is_drawing) {
332             // Reset frame's pixmap and move it to the new position.
333             int bw = wBorderWidth(pWin);
334
335             winRec->pixmap->devPrivate.ptr = winRec->pixelData;
336             SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw);
337         }
338     }
339
340     SCREEN_UNWRAP(pScreen, PositionWindow);
341     result = pScreen->PositionWindow(pWin, x, y);
342     SCREEN_WRAP(pScreen, PositionWindow);
343
344     RL_DEBUG_MSG("positionwindow end\n");
345     return result;
346 }
347
348 /*
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
352  *  valuable.
353  */
354 static void
355 RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec * winRec)
356 {
357     DrawablePtr d = &pWin->drawable;
358     int bw = wBorderWidth(pWin);
359
360     winRec->win = pWin;
361
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;
367 }
368
369 /*
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.
374  */
375 static RootlessWindowRec *
376 RootlessEnsureFrame(WindowPtr pWin)
377 {
378     ScreenPtr pScreen = pWin->drawable.pScreen;
379     RootlessWindowRec *winRec;
380     RegionRec shape;
381     RegionPtr pShape = NULL;
382
383     if (WINREC(pWin) != NULL)
384         return WINREC(pWin);
385
386     if (!IsTopLevel(pWin) && !IsRoot(pWin))
387         return NULL;
388
389     if (pWin->drawable.class != InputOutput)
390         return NULL;
391
392     winRec = malloc(sizeof(RootlessWindowRec));
393
394     if (!winRec)
395         return NULL;
396
397     RootlessInitializeFrame(pWin, winRec);
398
399     winRec->is_drawing = FALSE;
400     winRec->is_reorder_pending = FALSE;
401     winRec->pixmap = NULL;
402     winRec->wid = NULL;
403     winRec->level = 0;
404
405     SETWINREC(pWin, winRec);
406
407     // Set the frame's shape if the window is shaped
408     if (RootlessGetShape(pWin, &shape))
409         pShape = &shape;
410
411     RL_DEBUG_MSG("creating frame ");
412
413     if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen,
414                                               winRec->x + SCREEN_TO_GLOBAL_X,
415                                               winRec->y + SCREEN_TO_GLOBAL_Y,
416                                               pShape)) {
417         RL_DEBUG_MSG("implementation failed to create frame!\n");
418         free(winRec);
419         SETWINREC(pWin, NULL);
420         return NULL;
421     }
422
423     if (pWin->drawable.depth == 8)
424         RootlessFlushWindowColormap(pWin);
425
426     if (pShape != NULL)
427         RegionUninit(&shape);
428
429     return winRec;
430 }
431
432 /*
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.
436  */
437 Bool
438 RootlessRealizeWindow(WindowPtr pWin)
439 {
440     Bool result;
441     RegionRec saveRoot;
442     ScreenPtr pScreen = pWin->drawable.pScreen;
443
444     RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin);
445
446     if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) {
447         RootlessWindowRec *winRec;
448
449         winRec = RootlessEnsureFrame(pWin);
450         if (winRec == NULL)
451             return FALSE;
452
453         winRec->is_reorder_pending = TRUE;
454
455         RL_DEBUG_MSG("Top level window ");
456
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) {
460             XID pixel = 0;
461
462             ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
463         }
464     }
465
466     if (!IsRoot(pWin))
467         HUGE_ROOT(pWin);
468     SCREEN_UNWRAP(pScreen, RealizeWindow);
469     result = pScreen->RealizeWindow(pWin);
470     SCREEN_WRAP(pScreen, RealizeWindow);
471     if (!IsRoot(pWin))
472         NORMAL_ROOT(pWin);
473
474     RL_DEBUG_MSG("realizewindow end\n");
475     return result;
476 }
477
478 /*
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.
482  */
483 RootlessFrameID
484 RootlessFrameForWindow(WindowPtr pWin, Bool create)
485 {
486     WindowPtr pTopWin;
487     RootlessWindowRec *winRec;
488
489     pTopWin = TopLevelParent(pWin);
490     if (pTopWin == NULL)
491         return NULL;
492
493     winRec = WINREC(pTopWin);
494
495     if (winRec == NULL && create && pWin->drawable.class == InputOutput) {
496         winRec = RootlessEnsureFrame(pTopWin);
497     }
498
499     if (winRec == NULL)
500         return NULL;
501
502     return winRec->wid;
503 }
504
505 /*
506  * RootlessUnrealizeWindow
507  *  Unmap the physical window.
508  */
509 Bool
510 RootlessUnrealizeWindow(WindowPtr pWin)
511 {
512     ScreenPtr pScreen = pWin->drawable.pScreen;
513     RootlessWindowRec *winRec = WINREC(pWin);
514     Bool result;
515
516     RL_DEBUG_MSG("unrealizewindow start ");
517
518     if (winRec) {
519         RootlessStopDrawing(pWin, FALSE);
520
521         SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
522
523         winRec->is_reorder_pending = FALSE;
524     }
525
526     SCREEN_UNWRAP(pScreen, UnrealizeWindow);
527     result = pScreen->UnrealizeWindow(pWin);
528     SCREEN_WRAP(pScreen, UnrealizeWindow);
529
530     RL_DEBUG_MSG("unrealizewindow end\n");
531     return result;
532 }
533
534 /*
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.
538  */
539 void
540 RootlessReorderWindow(WindowPtr pWin)
541 {
542     RootlessWindowRec *winRec = WINREC(pWin);
543
544     if (pWin->realized && winRec != NULL && !winRec->is_reorder_pending &&
545         !windows_hidden) {
546         WindowPtr newPrevW;
547         RootlessWindowRec *newPrev;
548         RootlessFrameID newPrevID;
549         ScreenPtr pScreen = pWin->drawable.pScreen;
550
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))
557                 return;
558         }
559
560         RootlessStopDrawing(pWin, FALSE);
561
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
567          */
568
569         newPrevW = pWin->prevSib;
570         while (newPrevW &&
571                (WINREC(newPrevW) == NULL || !newPrevW->realized ||
572                 newPrevW->rootlessUnhittable != pWin->rootlessUnhittable))
573             newPrevW = newPrevW->prevSib;
574
575         newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
576         newPrevID = newPrev != NULL ? newPrev->wid : 0;
577
578         /* If it exists, reorder the frame above us first. */
579
580         if (newPrev && newPrev->is_reorder_pending) {
581             newPrev->is_reorder_pending = FALSE;
582             RootlessReorderWindow(newPrevW);
583         }
584
585         SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
586     }
587 }
588
589 /*
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
594  *  window to match.
595  */
596 void
597 RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
598 {
599     RegionRec saveRoot;
600     RootlessWindowRec *winRec = WINREC(pWin);
601     ScreenPtr pScreen = pWin->drawable.pScreen;
602
603     RL_DEBUG_MSG("restackwindow start ");
604     if (winRec)
605         RL_DEBUG_MSG("restack top level \n");
606
607     HUGE_ROOT(pWin);
608     SCREEN_UNWRAP(pScreen, RestackWindow);
609
610     if (pScreen->RestackWindow)
611         pScreen->RestackWindow(pWin, pOldNextSib);
612
613     SCREEN_WRAP(pScreen, RestackWindow);
614     NORMAL_ROOT(pWin);
615
616     if (winRec && pWin->viewable) {
617         RootlessReorderWindow(pWin);
618     }
619
620     RL_DEBUG_MSG("restackwindow end\n");
621 }
622
623 /*
624  * Specialized window copy procedures
625  */
626
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 };
631
632 static BoxRec gResizeDeathBounds[2];
633 static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
634
635 /*
636  * RootlessNoCopyWindow
637  *  CopyWindow() that doesn't do anything. For MoveWindow() of
638  *  top-level windows.
639  */
640 static void
641 RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
642 {
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;
646
647     RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW ");
648
649     RegionTranslate(prgnSrc, -dx, -dy);
650 }
651
652 /*
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.
658  */
659 static void
660 RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
661                          RegionPtr prgnSrc)
662 {
663     ScreenPtr pScreen = pWin->drawable.pScreen;
664     RegionRec rgnDst;
665     int dx, dy;
666
667     RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
668
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. */
672
673     if (gResizeDeathCount == 0)
674         return;
675
676     RootlessStartDrawing(pWin);
677
678     dx = ptOldOrg.x - pWin->drawable.x;
679     dy = ptOldOrg.y - pWin->drawable.y;
680     RegionTranslate(prgnSrc, -dx, -dy);
681     RegionNull(&rgnDst);
682     RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
683
684     if (gResizeDeathCount == 1) {
685         /* Simple case, we only have a single source pixmap. */
686
687         miCopyRegion(&gResizeDeathPix[0]->drawable,
688                      &pScreen->GetWindowPixmap(pWin)->drawable, 0,
689                      &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
690     }
691     else {
692         int i;
693         RegionRec clip, clipped;
694
695         /* More complex case, N source pixmaps (usually two). So we
696            intersect the destination with each source and copy those bits. */
697
698         for (i = 0; i < gResizeDeathCount; i++) {
699             RegionInit(&clip, gResizeDeathBounds + 0, 1);
700             RegionNull(&clipped);
701             RegionIntersect(&rgnDst, &clip, &clipped);
702
703             miCopyRegion(&gResizeDeathPix[i]->drawable,
704                          &pScreen->GetWindowPixmap(pWin)->drawable, 0,
705                          &clipped, dx, dy, fbCopyWindowProc, 0, 0);
706
707             RegionUninit(&clipped);
708             RegionUninit(&clip);
709         }
710     }
711
712     /* Don't update - resize will update everything */
713     RegionUninit(&rgnDst);
714
715     fbValidateDrawable(&pWin->drawable);
716
717     RL_DEBUG_MSG("resizecopywindowFB end\n");
718 }
719
720 /*
721  * RootlessCopyWindow
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.
726  */
727 void
728 RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
729 {
730     ScreenPtr pScreen = pWin->drawable.pScreen;
731     RegionRec rgnDst;
732     int dx, dy;
733     BoxPtr extents;
734     int area;
735
736     RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin);
737
738     SCREEN_UNWRAP(pScreen, CopyWindow);
739
740     dx = ptOldOrg.x - pWin->drawable.x;
741     dy = ptOldOrg.y - pWin->drawable.y;
742     RegionTranslate(prgnSrc, -dx, -dy);
743
744     RegionNull(&rgnDst);
745     RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
746
747     extents = RegionExtents(&rgnDst);
748     area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
749
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;
755         WindowPtr top;
756
757         top = TopLevelParent(pWin);
758         if (top == NULL) {
759             RL_DEBUG_MSG("no parent\n");
760             goto out;
761         }
762
763         winRec = WINREC(top);
764         if (winRec == NULL) {
765             RL_DEBUG_MSG("not framed\n");
766             goto out;
767         }
768
769         /* Move region to window local coords */
770         RegionTranslate(&rgnDst, -winRec->x, -winRec->y);
771
772         RootlessStopDrawing(pWin, FALSE);
773
774         SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
775                                             RegionNumRects(&rgnDst),
776                                             RegionRects(&rgnDst), dx, dy);
777     }
778     else {
779         RootlessStartDrawing(pWin);
780
781         miCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
782                      0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
783
784         /* prgnSrc has been translated to dst position */
785         RootlessDamageRegion(pWin, prgnSrc);
786     }
787
788  out:
789     RegionUninit(&rgnDst);
790     fbValidateDrawable(&pWin->drawable);
791
792     SCREEN_WRAP(pScreen, CopyWindow);
793
794     RL_DEBUG_MSG("copywindowFB end\n");
795 }
796
797 /*
798  * Window resize procedures
799  */
800
801 enum {
802     WIDTH_SMALLER = 1,
803     HEIGHT_SMALLER = 2,
804 };
805
806 /*
807  * ResizeWeighting
808  *  Choose gravity to avoid local copies. Do that by looking for
809  *  a corner that doesn't move _relative to the screen_.
810  */
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)
814 {
815 #ifdef ROOTLESS_RESIZE_GRAVITY
816     if (newBW != oldBW)
817         return RL_GRAVITY_NONE;
818
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;
827     else
828         return RL_GRAVITY_NONE;
829 #else
830     return RL_GRAVITY_NONE;
831 #endif
832 }
833
834 /*
835  * StartFrameResize
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)
839  */
840 static Bool
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)
844 {
845     ScreenPtr pScreen = pWin->drawable.pScreen;
846     RootlessWindowRec *winRec = WINREC(pWin);
847     Bool need_window_source = FALSE, resize_after = FALSE;
848
849     BoxRec rect;
850     int oldX2, newX2;
851     int oldY2, newY2;
852     unsigned int weight;
853
854     oldX2 = oldX + oldW, newX2 = newX + newW;
855     oldY2 = oldY + oldH, newY2 = newY + newH;
856
857     /* Decide which resize weighting to use */
858     weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
859                              newX, newY, newW, newH, newBW);
860
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);
866
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);
870
871     RootlessRedisplay(pWin);
872
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.
878
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
883        operation.
884
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. */
888
889     gResizeDeathCount = 0;
890
891     if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
892         unsigned int code = 0;
893
894         /* Top left corner is anchored. We never need to copy the
895            entire window. */
896
897         need_window_source = TRUE;
898
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.) */
902
903         if (newW < oldW)
904             code |= WIDTH_SMALLER;
905         if (newH < oldH)
906             code |= HEIGHT_SMALLER;
907
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. */
911
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
915                    afterwards. */
916
917                 resize_after = TRUE;
918             }
919
920             gResizeDeathCount = 1;
921         }
922         else {
923             unsigned int copy_rowbytes, Bpp;
924             unsigned int copy_rect_width, copy_rect_height;
925             BoxRec copy_rect;
926
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. */
930
931             RootlessStartDrawing(pWin);
932
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;
938             }
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;
944             }
945             else
946                 OsAbort();
947
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);
953
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,
958                                                    copy_rect_height,
959                                                    ((char *) winRec->pixelData)
960                                                    +
961                                                    ((copy_rect.y1 -
962                                                      oldY) *
963                                                     winRec->bytesPerRow)
964                                                    + (copy_rect.x1 -
965                                                       oldX) * Bpp,
966                                                    winRec->bytesPerRow,
967                                                    gResizeDeathBits,
968                                                    copy_rowbytes);
969             }
970             else {
971                 fbBlt((FbBits *) (winRec->pixelData
972                                   +
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);
979             }
980
981             gResizeDeathBounds[1] = copy_rect;
982             gResizeDeathPix[1]
983                 = GetScratchPixmapHeader(pScreen, copy_rect_width,
984                                          copy_rect_height,
985                                          winRec->win->drawable.depth,
986                                          winRec->win->drawable.bitsPerPixel,
987                                          winRec->bytesPerRow,
988                                          (void *) gResizeDeathBits);
989
990             SetPixmapBaseToScreen(gResizeDeathPix[1],
991                                   copy_rect.x1, copy_rect.y1);
992
993             gResizeDeathCount = 2;
994         }
995     }
996     else if (gravity) {
997         /* The general case. Just copy everything. */
998
999         RootlessStartDrawing(pWin);
1000
1001         gResizeDeathBits = malloc(winRec->bytesPerRow * winRec->height);
1002
1003         memcpy(gResizeDeathBits, winRec->pixelData,
1004                winRec->bytesPerRow * winRec->height);
1005
1006         gResizeDeathBounds[0] = (BoxRec) {
1007         oldX, oldY, oldX2, oldY2};
1008         gResizeDeathPix[0]
1009             = GetScratchPixmapHeader(pScreen, winRec->width,
1010                                      winRec->height,
1011                                      winRec->win->drawable.depth,
1012                                      winRec->win->drawable.bitsPerPixel,
1013                                      winRec->bytesPerRow,
1014                                      (void *) gResizeDeathBits);
1015
1016         SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1017         gResizeDeathCount = 1;
1018     }
1019
1020     RootlessStopDrawing(pWin, FALSE);
1021
1022     winRec->x = newX;
1023     winRec->y = newY;
1024     winRec->width = newW;
1025     winRec->height = newH;
1026     winRec->borderWidth = newBW;
1027
1028     /* Unless both dimensions are getting smaller, Resize the frame
1029        before doing gravity repair */
1030
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);
1036     }
1037
1038     RootlessStartDrawing(pWin);
1039
1040     /* If necessary, create a source pixmap pointing at the current
1041        window bits. */
1042
1043     if (need_window_source) {
1044         gResizeDeathBounds[0] = (BoxRec) {
1045         oldX, oldY, oldX2, oldY2};
1046         gResizeDeathPix[0]
1047             = GetScratchPixmapHeader(pScreen, oldW, oldH,
1048                                      winRec->win->drawable.depth,
1049                                      winRec->win->drawable.bitsPerPixel,
1050                                      winRec->bytesPerRow, winRec->pixelData);
1051
1052         SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1053     }
1054
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. */
1058
1059     if (gravity) {
1060         gResizeOldCopyWindowProc = pScreen->CopyWindow;
1061         pScreen->CopyWindow = RootlessResizeCopyWindow;
1062     }
1063
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.
1069
1070        FIXME: border width change! (?) */
1071
1072     if (gravity && weight == RL_GRAVITY_NONE) {
1073         PixmapPtr src, dst;
1074
1075         assert(gResizeDeathCount == 1);
1076
1077         src = gResizeDeathPix[0];
1078         dst = pScreen->GetWindowPixmap(pWin);
1079
1080         RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1081                      rect.x1, rect.y1, rect.x2, rect.y2);
1082
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.. */
1089
1090             ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1091             SetPixmapBaseToScreen(dst, newX, newY);
1092
1093             fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1094                              &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1095
1096             ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1097             SetPixmapBaseToScreen(dst, oldX, oldY);
1098         }
1099     }
1100
1101     return resize_after;
1102 }
1103
1104 static void
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)
1109 {
1110     ScreenPtr pScreen = pWin->drawable.pScreen;
1111     RootlessWindowRec *winRec = WINREC(pWin);
1112     int i;
1113
1114     RootlessStopDrawing(pWin, FALSE);
1115
1116     if (resize_now) {
1117         unsigned int weight;
1118
1119         /* We didn't resize anything earlier, so do it now, now that
1120            we've finished gravitating the bits. */
1121
1122         weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
1123                                  newX, newY, newW, newH, newBW);
1124
1125         SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1126                                              newX + SCREEN_TO_GLOBAL_X,
1127                                              newY + SCREEN_TO_GLOBAL_Y,
1128                                              newW, newH, weight);
1129     }
1130
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? */
1133
1134     RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
1135
1136     for (i = 0; i < 2; i++) {
1137         if (gResizeDeathPix[i] != NULL) {
1138             FreeScratchPixmapHeader(gResizeDeathPix[i]);
1139             gResizeDeathPix[i] = NULL;
1140         }
1141     }
1142
1143     free(gResizeDeathBits);
1144     gResizeDeathBits = NULL;
1145
1146     if (gravity) {
1147         pScreen->CopyWindow = gResizeOldCopyWindowProc;
1148     }
1149 }
1150
1151 /*
1152  * RootlessMoveWindow
1153  *  If kind==VTOther, window border is resizing (and borderWidth is
1154  *  already changed!!@#$)  This case works like window resize, not move.
1155  */
1156 void
1157 RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1158 {
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;
1166     RegionRec saveRoot;
1167
1168     RL_DEBUG_MSG("movewindow start \n");
1169
1170     if (winRec) {
1171         if (kind == VTMove) {
1172             oldX = winRec->x;
1173             oldY = winRec->y;
1174             RootlessRedisplay(pWin);
1175             RootlessStartDrawing(pWin);
1176         }
1177         else {
1178             RL_DEBUG_MSG("movewindow border resizing ");
1179
1180             oldBW = winRec->borderWidth;
1181             oldX = winRec->x;
1182             oldY = winRec->y;
1183             oldW = winRec->width;
1184             oldH = winRec->height;
1185
1186             newBW = wBorderWidth(pWin);
1187             newX = x;
1188             newY = y;
1189             newW = pWin->drawable.width + 2 * newBW;
1190             newH = pWin->drawable.height + 2 * newBW;
1191
1192             resize_after = StartFrameResize(pWin, FALSE,
1193                                             oldX, oldY, oldW, oldH, oldBW,
1194                                             newX, newY, newW, newH, newBW);
1195         }
1196     }
1197
1198     HUGE_ROOT(pWin);
1199     SCREEN_UNWRAP(pScreen, MoveWindow);
1200
1201     if (winRec) {
1202         oldCopyWindowProc = pScreen->CopyWindow;
1203         pScreen->CopyWindow = RootlessNoCopyWindow;
1204     }
1205     pScreen->MoveWindow(pWin, x, y, pSib, kind);
1206     if (winRec) {
1207         pScreen->CopyWindow = oldCopyWindowProc;
1208     }
1209
1210     NORMAL_ROOT(pWin);
1211     SCREEN_WRAP(pScreen, MoveWindow);
1212
1213     if (winRec) {
1214         if (kind == VTMove) {
1215             winRec->x = x;
1216             winRec->y = y;
1217             RootlessStopDrawing(pWin, FALSE);
1218             SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1219                                                x + SCREEN_TO_GLOBAL_X,
1220                                                y + SCREEN_TO_GLOBAL_Y);
1221         }
1222         else {
1223             FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1224                               newX, newY, newW, newH, newBW, resize_after);
1225         }
1226     }
1227
1228     RL_DEBUG_MSG("movewindow end\n");
1229 }
1230
1231 /*
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.
1238  */
1239 void
1240 RootlessResizeWindow(WindowPtr pWin, int x, int y,
1241                      unsigned int w, unsigned int h, WindowPtr pSib)
1242 {
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;
1248     RegionRec saveRoot;
1249
1250     RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
1251
1252     if (pWin->parent) {
1253         if (winRec) {
1254             oldBW = winRec->borderWidth;
1255             oldX = winRec->x;
1256             oldY = winRec->y;
1257             oldW = winRec->width;
1258             oldH = winRec->height;
1259
1260             newBW = oldBW;
1261             newX = x;
1262             newY = y;
1263             newW = w + 2 * newBW;
1264             newH = h + 2 * newBW;
1265
1266             resize_after = StartFrameResize(pWin, TRUE,
1267                                             oldX, oldY, oldW, oldH, oldBW,
1268                                             newX, newY, newW, newH, newBW);
1269         }
1270
1271         HUGE_ROOT(pWin);
1272         SCREEN_UNWRAP(pScreen, ResizeWindow);
1273         pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
1274         SCREEN_WRAP(pScreen, ResizeWindow);
1275         NORMAL_ROOT(pWin);
1276
1277         if (winRec) {
1278             FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
1279                               newX, newY, newW, newH, newBW, resize_after);
1280         }
1281     }
1282     else {
1283         /* Special case for resizing the root window */
1284         BoxRec box;
1285
1286         pWin->drawable.x = x;
1287         pWin->drawable.y = y;
1288         pWin->drawable.width = w;
1289         pWin->drawable.height = h;
1290
1291         box.x1 = x;
1292         box.y1 = y;
1293         box.x2 = x + w;
1294         box.y2 = y + 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);
1300
1301         if (winRec) {
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);
1306         }
1307
1308         miSendExposures(pWin, &pWin->borderClip,
1309                         pWin->drawable.x, pWin->drawable.y);
1310     }
1311
1312     RL_DEBUG_MSG("resizewindow end\n");
1313 }
1314
1315 /*
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
1320  *  change.
1321  */
1322 void
1323 RootlessRepositionWindow(WindowPtr pWin)
1324 {
1325     RootlessWindowRec *winRec = WINREC(pWin);
1326     ScreenPtr pScreen = pWin->drawable.pScreen;
1327
1328     if (winRec == NULL)
1329         return;
1330
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);
1335
1336     RootlessReorderWindow(pWin);
1337 }
1338
1339 /*
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.
1347  */
1348 void
1349 RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
1350 {
1351     ScreenPtr pScreen = pWin->drawable.pScreen;
1352     RootlessWindowRec *winRec = WINREC(pWin);
1353     WindowPtr pTopWin;
1354
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) {
1358         goto out;
1359     }
1360
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... */
1364
1365     pTopWin = TopLevelParent(pWin);
1366     assert(pTopWin != pWin);
1367
1368     pWin->rootlessUnhittable = FALSE;
1369
1370     DeleteProperty(serverClient, pWin, xa_native_window_id());
1371
1372     if (WINREC(pTopWin) != NULL) {
1373         /* We're screwed. */
1374         RootlessDestroyFrame(pWin, winRec);
1375     }
1376     else {
1377         if (!pTopWin->realized && pWin->realized) {
1378             SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
1379         }
1380
1381         /* Switch the frame record from one to the other. */
1382
1383         SETWINREC(pWin, NULL);
1384         SETWINREC(pTopWin, winRec);
1385
1386         RootlessInitializeFrame(pTopWin, winRec);
1387         RootlessReshapeFrame(pTopWin);
1388
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,
1393                                              RL_GRAVITY_NONE);
1394
1395         if (SCREENREC(pScreen)->imp->SwitchWindow) {
1396             SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
1397         }
1398
1399         if (pTopWin->realized && !pWin->realized)
1400             winRec->is_reorder_pending = TRUE;
1401     }
1402
1403  out:
1404     if (SCREENREC(pScreen)->ReparentWindow) {
1405         SCREEN_UNWRAP(pScreen, ReparentWindow);
1406         pScreen->ReparentWindow(pWin, pPriorParent);
1407         SCREEN_WRAP(pScreen, ReparentWindow);
1408     }
1409 }
1410
1411 void
1412 RootlessFlushWindowColormap(WindowPtr pWin)
1413 {
1414     RootlessWindowRec *winRec = WINREC(pWin);
1415     ScreenPtr pScreen = pWin->drawable.pScreen;
1416
1417     if (winRec == NULL)
1418         return;
1419
1420     RootlessStopDrawing(pWin, FALSE);
1421
1422     if (SCREENREC(pScreen)->imp->UpdateColormap)
1423         SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen);
1424 }
1425
1426 /*
1427  * RootlessChangeBorderWidth
1428  *  FIXME: untested!
1429  *  pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1430  *  Frame moves and resizes.
1431  */
1432 void
1433 RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
1434 {
1435     RegionRec saveRoot;
1436     Bool resize_after = FALSE;
1437
1438     RL_DEBUG_MSG("change border width ");
1439
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;
1445
1446         if (winRec) {
1447             oldBW = winRec->borderWidth;
1448             oldX = winRec->x;
1449             oldY = winRec->y;
1450             oldW = winRec->width;
1451             oldH = winRec->height;
1452
1453             newBW = width;
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;
1458
1459             resize_after = StartFrameResize(pWin, FALSE,
1460                                             oldX, oldY, oldW, oldH, oldBW,
1461                                             newX, newY, newW, newH, newBW);
1462         }
1463
1464         HUGE_ROOT(pWin);
1465         SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1466         pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
1467         SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1468         NORMAL_ROOT(pWin);
1469
1470         if (winRec) {
1471             FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1472                               newX, newY, newW, newH, newBW, resize_after);
1473         }
1474     }
1475
1476     RL_DEBUG_MSG("change border width end\n");
1477 }
1478
1479 /*
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
1483  */
1484 void
1485 RootlessOrderAllWindows(Bool include_unhitable)
1486 {
1487     int i;
1488     WindowPtr pWin;
1489
1490     if (windows_hidden)
1491         return;
1492
1493     RL_DEBUG_MSG("RootlessOrderAllWindows() ");
1494     for (i = 0; i < screenInfo.numScreens; i++) {
1495         if (screenInfo.screens[i] == NULL)
1496             continue;
1497         pWin = screenInfo.screens[i]->root;
1498         if (pWin == NULL)
1499             continue;
1500
1501         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1502             if (!pWin->realized)
1503                 continue;
1504             if (RootlessEnsureFrame(pWin) == NULL)
1505                 continue;
1506             if (!include_unhitable && pWin->rootlessUnhittable)
1507                 continue;
1508             RootlessReorderWindow(pWin);
1509         }
1510     }
1511     RL_DEBUG_MSG("RootlessOrderAllWindows() done");
1512 }
1513
1514 void
1515 RootlessEnableRoot(ScreenPtr pScreen)
1516 {
1517     WindowPtr pRoot;
1518
1519     pRoot = pScreen->root;
1520
1521     RootlessEnsureFrame(pRoot);
1522     (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
1523     RootlessReorderWindow(pRoot);
1524 }
1525
1526 void
1527 RootlessDisableRoot(ScreenPtr pScreen)
1528 {
1529     WindowPtr pRoot;
1530     RootlessWindowRec *winRec;
1531
1532     pRoot = pScreen->root;
1533     winRec = WINREC(pRoot);
1534
1535     if (NULL == winRec)
1536         return;
1537
1538     RootlessDestroyFrame(pRoot, winRec);
1539     DeleteProperty(serverClient, pRoot, xa_native_window_id());
1540 }
1541
1542 void
1543 RootlessHideAllWindows(void)
1544 {
1545     int i;
1546     ScreenPtr pScreen;
1547     WindowPtr pWin;
1548     RootlessWindowRec *winRec;
1549
1550     if (windows_hidden)
1551         return;
1552
1553     windows_hidden = TRUE;
1554
1555     for (i = 0; i < screenInfo.numScreens; i++) {
1556         pScreen = screenInfo.screens[i];
1557         if (pScreen == NULL)
1558             continue;
1559         pWin = pScreen->root;
1560         if (pWin == NULL)
1561             continue;
1562
1563         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1564             if (!pWin->realized)
1565                 continue;
1566
1567             RootlessStopDrawing(pWin, FALSE);
1568
1569             winRec = WINREC(pWin);
1570             if (winRec != NULL) {
1571                 if (SCREENREC(pScreen)->imp->HideWindow)
1572                     SCREENREC(pScreen)->imp->HideWindow(winRec->wid);
1573             }
1574         }
1575     }
1576 }
1577
1578 void
1579 RootlessShowAllWindows(void)
1580 {
1581     int i;
1582     ScreenPtr pScreen;
1583     WindowPtr pWin;
1584     RootlessWindowRec *winRec;
1585
1586     if (!windows_hidden)
1587         return;
1588
1589     windows_hidden = FALSE;
1590
1591     for (i = 0; i < screenInfo.numScreens; i++) {
1592         pScreen = screenInfo.screens[i];
1593         if (pScreen == NULL)
1594             continue;
1595         pWin = pScreen->root;
1596         if (pWin == NULL)
1597             continue;
1598
1599         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1600             if (!pWin->realized)
1601                 continue;
1602
1603             winRec = RootlessEnsureFrame(pWin);
1604             if (winRec == NULL)
1605                 continue;
1606
1607             RootlessReorderWindow(pWin);
1608         }
1609
1610         RootlessScreenExpose(pScreen);
1611     }
1612 }
1613
1614 /*
1615  * SetPixmapOfAncestors
1616  *  Set the Pixmaps on all ParentRelative windows up the ancestor chain.
1617  */
1618 void
1619 RootlessSetPixmapOfAncestors(WindowPtr pWin)
1620 {
1621     ScreenPtr pScreen = pWin->drawable.pScreen;
1622     WindowPtr topWin = TopLevelParent(pWin);
1623     RootlessWindowRec *topWinRec = WINREC(topWin);
1624
1625     while (pWin->backgroundState == ParentRelative) {
1626         if (pWin == topWin) {
1627             // disallow ParentRelative background state on top level
1628             XID pixel = 0;
1629
1630             ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
1631             RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
1632             break;
1633         }
1634
1635         pWin = pWin->parent;
1636         pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
1637     }
1638 }