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
RootlessNativeWindowStateChanged(WindowPtr pWin,unsigned int state)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->unhittable = winRec->is_offscreen;
96 }
97 
98 void
RootlessNativeWindowMoved(WindowPtr pWin)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
RootlessCreateWindow(WindowPtr pWin)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
RootlessDestroyFrame(WindowPtr pWin,RootlessWindowPtr winRec)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
RootlessDestroyWindow(WindowPtr pWin)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
RootlessGetShape(WindowPtr pWin,RegionPtr pShape)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
RootlessReshapeFrame(WindowPtr pWin)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
RootlessSetShape(WindowPtr pWin,int kind)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
RootlessChangeWindowAttributes(WindowPtr pWin,unsigned long vmask)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
RootlessPositionWindow(WindowPtr pWin,int x,int y)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
RootlessInitializeFrame(WindowPtr pWin,RootlessWindowRec * winRec)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 *
RootlessEnsureFrame(WindowPtr pWin)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
RootlessRealizeWindow(WindowPtr pWin)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
RootlessFrameForWindow(WindowPtr pWin,Bool create)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
RootlessUnrealizeWindow(WindowPtr pWin)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
RootlessReorderWindow(WindowPtr pWin)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->unhittable != pWin->unhittable))
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
RootlessRestackWindow(WindowPtr pWin,WindowPtr pOldNextSib)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
RootlessNoCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)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
RootlessResizeCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)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  *  PaintWindow. 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
RootlessCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)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 void
RootlessPaintWindow(WindowPtr pWin,RegionPtr prgn,int what)798 RootlessPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
799 {
800     ScreenPtr pScreen = pWin->drawable.pScreen;
801 
802     if (IsFramedWindow(pWin)) {
803         RootlessStartDrawing(pWin);
804         RootlessDamageRegion(pWin, prgn);
805 
806         if (pWin->backgroundState == ParentRelative) {
807             if ((what == PW_BACKGROUND) ||
808                 (what == PW_BORDER && !pWin->borderIsPixel))
809                 RootlessSetPixmapOfAncestors(pWin);
810         }
811     }
812 
813     SCREEN_UNWRAP(pScreen, PaintWindow);
814     pScreen->PaintWindow(pWin, prgn, what);
815     SCREEN_WRAP(pScreen, PaintWindow);
816 }
817 
818 /*
819  * Window resize procedures
820  */
821 
822 enum {
823     WIDTH_SMALLER = 1,
824     HEIGHT_SMALLER = 2,
825 };
826 
827 /*
828  * ResizeWeighting
829  *  Choose gravity to avoid local copies. Do that by looking for
830  *  a corner that doesn't move _relative to the screen_.
831  */
832 static inline unsigned int
ResizeWeighting(int oldX1,int oldY1,int oldX2,int oldY2,int oldBW,int newX1,int newY1,int newX2,int newY2,int newBW)833 ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
834                 int newX1, int newY1, int newX2, int newY2, int newBW)
835 {
836 #ifdef ROOTLESS_RESIZE_GRAVITY
837     if (newBW != oldBW)
838         return RL_GRAVITY_NONE;
839 
840     if (newX1 == oldX1 && newY1 == oldY1)
841         return RL_GRAVITY_NORTH_WEST;
842     else if (newX1 == oldX1 && newY2 == oldY2)
843         return RL_GRAVITY_SOUTH_WEST;
844     else if (newX2 == oldX2 && newY2 == oldY2)
845         return RL_GRAVITY_SOUTH_EAST;
846     else if (newX2 == oldX2 && newY1 == oldY1)
847         return RL_GRAVITY_NORTH_EAST;
848     else
849         return RL_GRAVITY_NONE;
850 #else
851     return RL_GRAVITY_NONE;
852 #endif
853 }
854 
855 /*
856  * StartFrameResize
857  *  Prepare to resize a top-level window. The old window's pixels are
858  *  saved and the implementation is told to change the window size.
859  *  (x,y,w,h) is outer frame of window (outside border)
860  */
861 static Bool
StartFrameResize(WindowPtr pWin,Bool gravity,int oldX,int oldY,int oldW,int oldH,int oldBW,int newX,int newY,int newW,int newH,int newBW)862 StartFrameResize(WindowPtr pWin, Bool gravity,
863                  int oldX, int oldY, int oldW, int oldH, int oldBW,
864                  int newX, int newY, int newW, int newH, int newBW)
865 {
866     ScreenPtr pScreen = pWin->drawable.pScreen;
867     RootlessWindowRec *winRec = WINREC(pWin);
868     Bool need_window_source = FALSE, resize_after = FALSE;
869 
870     BoxRec rect;
871     int oldX2, newX2;
872     int oldY2, newY2;
873     unsigned int weight;
874 
875     oldX2 = oldX + oldW, newX2 = newX + newW;
876     oldY2 = oldY + oldH, newY2 = newY + newH;
877 
878     /* Decide which resize weighting to use */
879     weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
880                              newX, newY, newW, newH, newBW);
881 
882     /* Compute intersection between old and new rects */
883     rect.x1 = max(oldX, newX);
884     rect.y1 = max(oldY, newY);
885     rect.x2 = min(oldX2, newX2);
886     rect.y2 = min(oldY2, newY2);
887 
888     RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
889     RL_DEBUG_MSG("%d %d %d %d %d   %d %d %d %d %d\n",
890                  oldX, oldY, oldW, oldH, oldBW, newX, newY, newW, newH, newBW);
891 
892     RootlessRedisplay(pWin);
893 
894     /* If gravity is true, then we need to have a way of recovering all
895        the original bits in the window for when X rearranges the contents
896        based on the various gravity settings. The obvious way is to just
897        snapshot the entire backing store before resizing it, but that
898        it slow on large windows.
899 
900        So the optimization here is to use the implementation's resize
901        weighting options (if available) to allow us to reason about what
902        is left in the backing store after the resize. We can then only
903        copy what won't be there after the resize, and do a two-stage copy
904        operation.
905 
906        Most of these optimizations are only applied when the top-left
907        corner of the window is fixed, since that's the common case. They
908        could probably be extended with some thought. */
909 
910     gResizeDeathCount = 0;
911 
912     if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
913         unsigned int code = 0;
914 
915         /* Top left corner is anchored. We never need to copy the
916            entire window. */
917 
918         need_window_source = TRUE;
919 
920         /* These comparisons were chosen to avoid setting bits when the sizes
921            are the same. (So the fastest case automatically gets taken when
922            dimensions are unchanging.) */
923 
924         if (newW < oldW)
925             code |= WIDTH_SMALLER;
926         if (newH < oldH)
927             code |= HEIGHT_SMALLER;
928 
929         if (((code ^ (code >> 1)) & 1) == 0) {
930             /* Both dimensions are either getting larger, or both
931                are getting smaller. No need to copy anything. */
932 
933             if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
934                 /* Since the window is getting smaller, we can do gravity
935                    repair on it with it's current size, then resize it
936                    afterwards. */
937 
938                 resize_after = TRUE;
939             }
940 
941             gResizeDeathCount = 1;
942         }
943         else {
944             unsigned int copy_rowbytes, Bpp;
945             unsigned int copy_rect_width, copy_rect_height;
946             BoxRec copy_rect;
947 
948             /* We can get away with a partial copy. 'rect' is the
949                intersection between old and new bounds, so copy
950                everything to the right of or below the intersection. */
951 
952             RootlessStartDrawing(pWin);
953 
954             if (code == WIDTH_SMALLER) {
955                 copy_rect.x1 = rect.x2;
956                 copy_rect.y1 = rect.y1;
957                 copy_rect.x2 = oldX2;
958                 copy_rect.y2 = oldY2;
959             }
960             else if (code == HEIGHT_SMALLER) {
961                 copy_rect.x1 = rect.x1;
962                 copy_rect.y1 = rect.y2;
963                 copy_rect.x2 = oldX2;
964                 copy_rect.y2 = oldY2;
965             }
966             else
967                 OsAbort();
968 
969             Bpp = winRec->win->drawable.bitsPerPixel / 8;
970             copy_rect_width = copy_rect.x2 - copy_rect.x1;
971             copy_rect_height = copy_rect.y2 - copy_rect.y1;
972             copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
973             gResizeDeathBits = xallocarray(copy_rowbytes, copy_rect_height);
974 
975             if (copy_rect_width * copy_rect_height >
976                 rootless_CopyBytes_threshold &&
977                 SCREENREC(pScreen)->imp->CopyBytes) {
978                 SCREENREC(pScreen)->imp->CopyBytes(copy_rect_width * Bpp,
979                                                    copy_rect_height,
980                                                    ((char *) winRec->pixelData)
981                                                    +
982                                                    ((copy_rect.y1 -
983                                                      oldY) *
984                                                     winRec->bytesPerRow)
985                                                    + (copy_rect.x1 -
986                                                       oldX) * Bpp,
987                                                    winRec->bytesPerRow,
988                                                    gResizeDeathBits,
989                                                    copy_rowbytes);
990             }
991             else {
992                 fbBlt((FbBits *) (winRec->pixelData
993                                   +
994                                   ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
995                                   + (copy_rect.x1 - oldX) * Bpp),
996                       winRec->bytesPerRow / sizeof(FbBits), 0,
997                       (FbBits *) gResizeDeathBits,
998                       copy_rowbytes / sizeof(FbBits), 0, copy_rect_width * Bpp,
999                       copy_rect_height, GXcopy, FB_ALLONES, Bpp, 0, 0);
1000             }
1001 
1002             gResizeDeathBounds[1] = copy_rect;
1003             gResizeDeathPix[1]
1004                 = GetScratchPixmapHeader(pScreen, copy_rect_width,
1005                                          copy_rect_height,
1006                                          winRec->win->drawable.depth,
1007                                          winRec->win->drawable.bitsPerPixel,
1008                                          winRec->bytesPerRow,
1009                                          (void *) gResizeDeathBits);
1010 
1011             SetPixmapBaseToScreen(gResizeDeathPix[1],
1012                                   copy_rect.x1, copy_rect.y1);
1013 
1014             gResizeDeathCount = 2;
1015         }
1016     }
1017     else if (gravity) {
1018         /* The general case. Just copy everything. */
1019 
1020         RootlessStartDrawing(pWin);
1021 
1022         gResizeDeathBits = xallocarray(winRec->bytesPerRow, winRec->height);
1023 
1024         memcpy(gResizeDeathBits, winRec->pixelData,
1025                winRec->bytesPerRow * winRec->height);
1026 
1027         gResizeDeathBounds[0] = (BoxRec) {
1028         oldX, oldY, oldX2, oldY2};
1029         gResizeDeathPix[0]
1030             = GetScratchPixmapHeader(pScreen, winRec->width,
1031                                      winRec->height,
1032                                      winRec->win->drawable.depth,
1033                                      winRec->win->drawable.bitsPerPixel,
1034                                      winRec->bytesPerRow,
1035                                      (void *) gResizeDeathBits);
1036 
1037         SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1038         gResizeDeathCount = 1;
1039     }
1040 
1041     RootlessStopDrawing(pWin, FALSE);
1042 
1043     winRec->x = newX;
1044     winRec->y = newY;
1045     winRec->width = newW;
1046     winRec->height = newH;
1047     winRec->borderWidth = newBW;
1048 
1049     /* Unless both dimensions are getting smaller, Resize the frame
1050        before doing gravity repair */
1051 
1052     if (!resize_after) {
1053         SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1054                                              newX + SCREEN_TO_GLOBAL_X,
1055                                              newY + SCREEN_TO_GLOBAL_Y,
1056                                              newW, newH, weight);
1057     }
1058 
1059     RootlessStartDrawing(pWin);
1060 
1061     /* If necessary, create a source pixmap pointing at the current
1062        window bits. */
1063 
1064     if (need_window_source) {
1065         gResizeDeathBounds[0] = (BoxRec) {
1066         oldX, oldY, oldX2, oldY2};
1067         gResizeDeathPix[0]
1068             = GetScratchPixmapHeader(pScreen, oldW, oldH,
1069                                      winRec->win->drawable.depth,
1070                                      winRec->win->drawable.bitsPerPixel,
1071                                      winRec->bytesPerRow, winRec->pixelData);
1072 
1073         SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1074     }
1075 
1076     /* Use custom CopyWindow when moving gravity bits around
1077        ResizeWindow assumes the old window contents are in the same
1078        pixmap, but here they're in deathPix instead. */
1079 
1080     if (gravity) {
1081         gResizeOldCopyWindowProc = pScreen->CopyWindow;
1082         pScreen->CopyWindow = RootlessResizeCopyWindow;
1083     }
1084 
1085     /* If we can't rely on the window server preserving the bits we
1086        need in the position we need, copy the pixels in the
1087        intersection from src to dst. ResizeWindow assumes these pixels
1088        are already present when making gravity adjustments. pWin
1089        currently has new-sized pixmap but is in old position.
1090 
1091        FIXME: border width change! (?) */
1092 
1093     if (gravity && weight == RL_GRAVITY_NONE) {
1094         PixmapPtr src, dst;
1095 
1096         assert(gResizeDeathCount == 1);
1097 
1098         src = gResizeDeathPix[0];
1099         dst = pScreen->GetWindowPixmap(pWin);
1100 
1101         RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1102                      rect.x1, rect.y1, rect.x2, rect.y2);
1103 
1104         /* rect is the intersection of the old location and new location */
1105         if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
1106             /* The window drawable still has the old frame position, which
1107                means that DST doesn't actually point at the origin of our
1108                physical backing store when adjusted by the drawable.x,y
1109                position. So sneakily adjust it temporarily while copying.. */
1110 
1111             ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1112             SetPixmapBaseToScreen(dst, newX, newY);
1113 
1114             fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1115                              &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1116 
1117             ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1118             SetPixmapBaseToScreen(dst, oldX, oldY);
1119         }
1120     }
1121 
1122     return resize_after;
1123 }
1124 
1125 static void
FinishFrameResize(WindowPtr pWin,Bool gravity,int oldX,int oldY,unsigned int oldW,unsigned int oldH,unsigned int oldBW,int newX,int newY,unsigned int newW,unsigned int newH,unsigned int newBW,Bool resize_now)1126 FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
1127                   unsigned int oldW, unsigned int oldH, unsigned int oldBW,
1128                   int newX, int newY, unsigned int newW, unsigned int newH,
1129                   unsigned int newBW, Bool resize_now)
1130 {
1131     ScreenPtr pScreen = pWin->drawable.pScreen;
1132     RootlessWindowRec *winRec = WINREC(pWin);
1133     int i;
1134 
1135     RootlessStopDrawing(pWin, FALSE);
1136 
1137     if (resize_now) {
1138         unsigned int weight;
1139 
1140         /* We didn't resize anything earlier, so do it now, now that
1141            we've finished gravitating the bits. */
1142 
1143         weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
1144                                  newX, newY, newW, newH, newBW);
1145 
1146         SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1147                                              newX + SCREEN_TO_GLOBAL_X,
1148                                              newY + SCREEN_TO_GLOBAL_Y,
1149                                              newW, newH, weight);
1150     }
1151 
1152     /* Redraw everything. FIXME: there must be times when we don't need
1153        to do this. Perhaps when top-left weighting and no gravity? */
1154 
1155     RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
1156 
1157     for (i = 0; i < 2; i++) {
1158         if (gResizeDeathPix[i] != NULL) {
1159             FreeScratchPixmapHeader(gResizeDeathPix[i]);
1160             gResizeDeathPix[i] = NULL;
1161         }
1162     }
1163 
1164     free(gResizeDeathBits);
1165     gResizeDeathBits = NULL;
1166 
1167     if (gravity) {
1168         pScreen->CopyWindow = gResizeOldCopyWindowProc;
1169     }
1170 }
1171 
1172 /*
1173  * RootlessMoveWindow
1174  *  If kind==VTOther, window border is resizing (and borderWidth is
1175  *  already changed!!@#$)  This case works like window resize, not move.
1176  */
1177 void
RootlessMoveWindow(WindowPtr pWin,int x,int y,WindowPtr pSib,VTKind kind)1178 RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1179 {
1180     RootlessWindowRec *winRec = WINREC(pWin);
1181     ScreenPtr pScreen = pWin->drawable.pScreen;
1182     CopyWindowProcPtr oldCopyWindowProc = NULL;
1183     int oldX = 0, oldY = 0, newX = 0, newY = 0;
1184     unsigned int oldW = 0, oldH = 0, oldBW = 0;
1185     unsigned int newW = 0, newH = 0, newBW = 0;
1186     Bool resize_after = FALSE;
1187     RegionRec saveRoot;
1188 
1189     RL_DEBUG_MSG("movewindow start \n");
1190 
1191     if (winRec) {
1192         if (kind == VTMove) {
1193             oldX = winRec->x;
1194             oldY = winRec->y;
1195             RootlessRedisplay(pWin);
1196             RootlessStartDrawing(pWin);
1197         }
1198         else {
1199             RL_DEBUG_MSG("movewindow border resizing ");
1200 
1201             oldBW = winRec->borderWidth;
1202             oldX = winRec->x;
1203             oldY = winRec->y;
1204             oldW = winRec->width;
1205             oldH = winRec->height;
1206 
1207             newBW = wBorderWidth(pWin);
1208             newX = x;
1209             newY = y;
1210             newW = pWin->drawable.width + 2 * newBW;
1211             newH = pWin->drawable.height + 2 * newBW;
1212 
1213             resize_after = StartFrameResize(pWin, FALSE,
1214                                             oldX, oldY, oldW, oldH, oldBW,
1215                                             newX, newY, newW, newH, newBW);
1216         }
1217     }
1218 
1219     HUGE_ROOT(pWin);
1220     SCREEN_UNWRAP(pScreen, MoveWindow);
1221 
1222     if (winRec) {
1223         oldCopyWindowProc = pScreen->CopyWindow;
1224         pScreen->CopyWindow = RootlessNoCopyWindow;
1225     }
1226     pScreen->MoveWindow(pWin, x, y, pSib, kind);
1227     if (winRec) {
1228         pScreen->CopyWindow = oldCopyWindowProc;
1229     }
1230 
1231     NORMAL_ROOT(pWin);
1232     SCREEN_WRAP(pScreen, MoveWindow);
1233 
1234     if (winRec) {
1235         if (kind == VTMove) {
1236             winRec->x = x;
1237             winRec->y = y;
1238             RootlessStopDrawing(pWin, FALSE);
1239             SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1240                                                x + SCREEN_TO_GLOBAL_X,
1241                                                y + SCREEN_TO_GLOBAL_Y);
1242         }
1243         else {
1244             FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1245                               newX, newY, newW, newH, newBW, resize_after);
1246         }
1247     }
1248 
1249     RL_DEBUG_MSG("movewindow end\n");
1250 }
1251 
1252 /*
1253  * RootlessResizeWindow
1254  *  Note: (x, y, w, h) as passed to this procedure don't match the frame
1255  *  definition. (x,y) is corner of very outer edge, *outside* border.
1256  *  w,h is width and height *inside* border, *ignoring* border width.
1257  *  The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
1258  *  is total rect and (x+bw, y+bw, w, h) is inner rect.
1259  */
1260 void
RootlessResizeWindow(WindowPtr pWin,int x,int y,unsigned int w,unsigned int h,WindowPtr pSib)1261 RootlessResizeWindow(WindowPtr pWin, int x, int y,
1262                      unsigned int w, unsigned int h, WindowPtr pSib)
1263 {
1264     RootlessWindowRec *winRec = WINREC(pWin);
1265     ScreenPtr pScreen = pWin->drawable.pScreen;
1266     int oldX = 0, oldY = 0, newX = 0, newY = 0;
1267     unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
1268     Bool resize_after = FALSE;
1269     RegionRec saveRoot;
1270 
1271     RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
1272 
1273     if (pWin->parent) {
1274         if (winRec) {
1275             oldBW = winRec->borderWidth;
1276             oldX = winRec->x;
1277             oldY = winRec->y;
1278             oldW = winRec->width;
1279             oldH = winRec->height;
1280 
1281             newBW = oldBW;
1282             newX = x;
1283             newY = y;
1284             newW = w + 2 * newBW;
1285             newH = h + 2 * newBW;
1286 
1287             resize_after = StartFrameResize(pWin, TRUE,
1288                                             oldX, oldY, oldW, oldH, oldBW,
1289                                             newX, newY, newW, newH, newBW);
1290         }
1291 
1292         HUGE_ROOT(pWin);
1293         SCREEN_UNWRAP(pScreen, ResizeWindow);
1294         pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
1295         SCREEN_WRAP(pScreen, ResizeWindow);
1296         NORMAL_ROOT(pWin);
1297 
1298         if (winRec) {
1299             FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
1300                               newX, newY, newW, newH, newBW, resize_after);
1301         }
1302     }
1303     else {
1304         /* Special case for resizing the root window */
1305         BoxRec box;
1306 
1307         pWin->drawable.x = x;
1308         pWin->drawable.y = y;
1309         pWin->drawable.width = w;
1310         pWin->drawable.height = h;
1311 
1312         box.x1 = x;
1313         box.y1 = y;
1314         box.x2 = x + w;
1315         box.y2 = y + h;
1316         RegionUninit(&pWin->winSize);
1317         RegionInit(&pWin->winSize, &box, 1);
1318         RegionCopy(&pWin->borderSize, &pWin->winSize);
1319         RegionCopy(&pWin->clipList, &pWin->winSize);
1320         RegionCopy(&pWin->borderClip, &pWin->winSize);
1321 
1322         if (winRec) {
1323             SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1324                                                  x + SCREEN_TO_GLOBAL_X,
1325                                                  y + SCREEN_TO_GLOBAL_Y,
1326                                                  w, h, RL_GRAVITY_NONE);
1327         }
1328 
1329         miSendExposures(pWin, &pWin->borderClip,
1330                         pWin->drawable.x, pWin->drawable.y);
1331     }
1332 
1333     RL_DEBUG_MSG("resizewindow end\n");
1334 }
1335 
1336 /*
1337  * RootlessRepositionWindow
1338  *  Called by the implementation when a window needs to be repositioned to
1339  *  its correct location on the screen. This routine is typically needed
1340  *  due to changes in the underlying window system, such as a screen layout
1341  *  change.
1342  */
1343 void
RootlessRepositionWindow(WindowPtr pWin)1344 RootlessRepositionWindow(WindowPtr pWin)
1345 {
1346     RootlessWindowRec *winRec = WINREC(pWin);
1347     ScreenPtr pScreen = pWin->drawable.pScreen;
1348 
1349     if (winRec == NULL)
1350         return;
1351 
1352     RootlessStopDrawing(pWin, FALSE);
1353     SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1354                                        winRec->x + SCREEN_TO_GLOBAL_X,
1355                                        winRec->y + SCREEN_TO_GLOBAL_Y);
1356 
1357     RootlessReorderWindow(pWin);
1358 }
1359 
1360 /*
1361  * RootlessReparentWindow
1362  *  Called after a window has been reparented. Generally windows are not
1363  *  framed until they are mapped. However, a window may be framed early by the
1364  *  implementation calling RootlessFrameForWindow. (e.g. this could be needed
1365  *  to attach a VRAM surface to it.) If the window is subsequently reparented
1366  *  by the window manager before being mapped, we need to give the frame to
1367  *  the new top-level window.
1368  */
1369 void
RootlessReparentWindow(WindowPtr pWin,WindowPtr pPriorParent)1370 RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
1371 {
1372     ScreenPtr pScreen = pWin->drawable.pScreen;
1373     RootlessWindowRec *winRec = WINREC(pWin);
1374     WindowPtr pTopWin;
1375 
1376     /* Check that window is not top-level now, but used to be. */
1377     if (IsRoot(pWin) || IsRoot(pWin->parent)
1378         || IsTopLevel(pWin) || winRec == NULL) {
1379         goto out;
1380     }
1381 
1382     /* If the formerly top-level window has a frame, we want to give the
1383        frame to its new top-level parent. If we can't do that, we'll just
1384        have to jettison it... */
1385 
1386     pTopWin = TopLevelParent(pWin);
1387     assert(pTopWin != pWin);
1388 
1389     pWin->unhittable = FALSE;
1390 
1391     DeleteProperty(serverClient, pWin, xa_native_window_id());
1392 
1393     if (WINREC(pTopWin) != NULL) {
1394         /* We're screwed. */
1395         RootlessDestroyFrame(pWin, winRec);
1396     }
1397     else {
1398         if (!pTopWin->realized && pWin->realized) {
1399             SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
1400         }
1401 
1402         /* Switch the frame record from one to the other. */
1403 
1404         SETWINREC(pWin, NULL);
1405         SETWINREC(pTopWin, winRec);
1406 
1407         RootlessInitializeFrame(pTopWin, winRec);
1408         RootlessReshapeFrame(pTopWin);
1409 
1410         SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1411                                              winRec->x + SCREEN_TO_GLOBAL_X,
1412                                              winRec->y + SCREEN_TO_GLOBAL_Y,
1413                                              winRec->width, winRec->height,
1414                                              RL_GRAVITY_NONE);
1415 
1416         if (SCREENREC(pScreen)->imp->SwitchWindow) {
1417             SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
1418         }
1419 
1420         if (pTopWin->realized && !pWin->realized)
1421             winRec->is_reorder_pending = TRUE;
1422     }
1423 
1424  out:
1425     if (SCREENREC(pScreen)->ReparentWindow) {
1426         SCREEN_UNWRAP(pScreen, ReparentWindow);
1427         pScreen->ReparentWindow(pWin, pPriorParent);
1428         SCREEN_WRAP(pScreen, ReparentWindow);
1429     }
1430 }
1431 
1432 void
RootlessFlushWindowColormap(WindowPtr pWin)1433 RootlessFlushWindowColormap(WindowPtr pWin)
1434 {
1435     RootlessWindowRec *winRec = WINREC(pWin);
1436     ScreenPtr pScreen = pWin->drawable.pScreen;
1437 
1438     if (winRec == NULL)
1439         return;
1440 
1441     RootlessStopDrawing(pWin, FALSE);
1442 
1443     if (SCREENREC(pScreen)->imp->UpdateColormap)
1444         SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen);
1445 }
1446 
1447 /*
1448  * RootlessChangeBorderWidth
1449  *  FIXME: untested!
1450  *  pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1451  *  Frame moves and resizes.
1452  */
1453 void
RootlessChangeBorderWidth(WindowPtr pWin,unsigned int width)1454 RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
1455 {
1456     RegionRec saveRoot;
1457     Bool resize_after = FALSE;
1458 
1459     RL_DEBUG_MSG("change border width ");
1460 
1461     if (width != wBorderWidth(pWin)) {
1462         RootlessWindowRec *winRec = WINREC(pWin);
1463         int oldX = 0, oldY = 0, newX = 0, newY = 0;
1464         unsigned int oldW = 0, oldH = 0, oldBW = 0;
1465         unsigned int newW = 0, newH = 0, newBW = 0;
1466 
1467         if (winRec) {
1468             oldBW = winRec->borderWidth;
1469             oldX = winRec->x;
1470             oldY = winRec->y;
1471             oldW = winRec->width;
1472             oldH = winRec->height;
1473 
1474             newBW = width;
1475             newX = pWin->drawable.x - newBW;
1476             newY = pWin->drawable.y - newBW;
1477             newW = pWin->drawable.width + 2 * newBW;
1478             newH = pWin->drawable.height + 2 * newBW;
1479 
1480             resize_after = StartFrameResize(pWin, FALSE,
1481                                             oldX, oldY, oldW, oldH, oldBW,
1482                                             newX, newY, newW, newH, newBW);
1483         }
1484 
1485         HUGE_ROOT(pWin);
1486         SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1487         pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
1488         SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1489         NORMAL_ROOT(pWin);
1490 
1491         if (winRec) {
1492             FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1493                               newX, newY, newW, newH, newBW, resize_after);
1494         }
1495     }
1496 
1497     RL_DEBUG_MSG("change border width end\n");
1498 }
1499 
1500 /*
1501  * RootlessOrderAllWindows
1502  * Brings all X11 windows to the top of the window stack
1503  * (i.e in front of Aqua windows) -- called when X11.app is given focus
1504  */
1505 void
RootlessOrderAllWindows(Bool include_unhitable)1506 RootlessOrderAllWindows(Bool include_unhitable)
1507 {
1508     int i;
1509     WindowPtr pWin;
1510 
1511     if (windows_hidden)
1512         return;
1513 
1514     RL_DEBUG_MSG("RootlessOrderAllWindows() ");
1515     for (i = 0; i < screenInfo.numScreens; i++) {
1516         if (screenInfo.screens[i] == NULL)
1517             continue;
1518         pWin = screenInfo.screens[i]->root;
1519         if (pWin == NULL)
1520             continue;
1521 
1522         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1523             if (!pWin->realized)
1524                 continue;
1525             if (RootlessEnsureFrame(pWin) == NULL)
1526                 continue;
1527             if (!include_unhitable && pWin->unhittable)
1528                 continue;
1529             RootlessReorderWindow(pWin);
1530         }
1531     }
1532     RL_DEBUG_MSG("RootlessOrderAllWindows() done");
1533 }
1534 
1535 void
RootlessEnableRoot(ScreenPtr pScreen)1536 RootlessEnableRoot(ScreenPtr pScreen)
1537 {
1538     WindowPtr pRoot;
1539 
1540     pRoot = pScreen->root;
1541 
1542     RootlessEnsureFrame(pRoot);
1543     (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
1544     RootlessReorderWindow(pRoot);
1545 }
1546 
1547 void
RootlessDisableRoot(ScreenPtr pScreen)1548 RootlessDisableRoot(ScreenPtr pScreen)
1549 {
1550     WindowPtr pRoot;
1551     RootlessWindowRec *winRec;
1552 
1553     pRoot = pScreen->root;
1554     winRec = WINREC(pRoot);
1555 
1556     if (NULL == winRec)
1557         return;
1558 
1559     RootlessDestroyFrame(pRoot, winRec);
1560     DeleteProperty(serverClient, pRoot, xa_native_window_id());
1561 }
1562 
1563 void
RootlessHideAllWindows(void)1564 RootlessHideAllWindows(void)
1565 {
1566     int i;
1567     ScreenPtr pScreen;
1568     WindowPtr pWin;
1569     RootlessWindowRec *winRec;
1570 
1571     if (windows_hidden)
1572         return;
1573 
1574     windows_hidden = TRUE;
1575 
1576     for (i = 0; i < screenInfo.numScreens; i++) {
1577         pScreen = screenInfo.screens[i];
1578         if (pScreen == NULL)
1579             continue;
1580         pWin = pScreen->root;
1581         if (pWin == NULL)
1582             continue;
1583 
1584         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1585             if (!pWin->realized)
1586                 continue;
1587 
1588             RootlessStopDrawing(pWin, FALSE);
1589 
1590             winRec = WINREC(pWin);
1591             if (winRec != NULL) {
1592                 if (SCREENREC(pScreen)->imp->HideWindow)
1593                     SCREENREC(pScreen)->imp->HideWindow(winRec->wid);
1594             }
1595         }
1596     }
1597 }
1598 
1599 void
RootlessShowAllWindows(void)1600 RootlessShowAllWindows(void)
1601 {
1602     int i;
1603     ScreenPtr pScreen;
1604     WindowPtr pWin;
1605     RootlessWindowRec *winRec;
1606 
1607     if (!windows_hidden)
1608         return;
1609 
1610     windows_hidden = FALSE;
1611 
1612     for (i = 0; i < screenInfo.numScreens; i++) {
1613         pScreen = screenInfo.screens[i];
1614         if (pScreen == NULL)
1615             continue;
1616         pWin = pScreen->root;
1617         if (pWin == NULL)
1618             continue;
1619 
1620         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1621             if (!pWin->realized)
1622                 continue;
1623 
1624             winRec = RootlessEnsureFrame(pWin);
1625             if (winRec == NULL)
1626                 continue;
1627 
1628             RootlessReorderWindow(pWin);
1629         }
1630 
1631         RootlessScreenExpose(pScreen);
1632     }
1633 }
1634 
1635 /*
1636  * SetPixmapOfAncestors
1637  *  Set the Pixmaps on all ParentRelative windows up the ancestor chain.
1638  */
1639 void
RootlessSetPixmapOfAncestors(WindowPtr pWin)1640 RootlessSetPixmapOfAncestors(WindowPtr pWin)
1641 {
1642     ScreenPtr pScreen = pWin->drawable.pScreen;
1643     WindowPtr topWin = TopLevelParent(pWin);
1644     RootlessWindowRec *topWinRec = WINREC(topWin);
1645 
1646     while (pWin->backgroundState == ParentRelative) {
1647         if (pWin == topWin) {
1648             // disallow ParentRelative background state on top level
1649             XID pixel = 0;
1650 
1651             ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
1652             RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
1653             break;
1654         }
1655 
1656         pWin = pWin->parent;
1657         pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
1658     }
1659 }
1660