rootlessWindow.c revision 4642e01f
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#ifdef __APPLE__
40//#include <X11/Xlib.h>
41#include <X11/Xatom.h>
42#include "mi.h"
43#include "pixmapstr.h"
44#include "windowstr.h"
45#include <Xplugin.h>
46//#include <X11/extensions/applewm.h>
47extern int darwinMainScreenX, darwinMainScreenY;
48#endif
49#include "fb.h"
50
51#define AppleWMNumWindowLevels 5
52
53#include "rootlessCommon.h"
54#include "rootlessWindow.h"
55
56#ifdef ROOTLESS_GLOBAL_COORDS
57#define SCREEN_TO_GLOBAL_X \
58    (dixScreenOrigins[pScreen->myNum].x + rootlessGlobalOffsetX)
59#define SCREEN_TO_GLOBAL_Y \
60    (dixScreenOrigins[pScreen->myNum].y + rootlessGlobalOffsetY)
61#else
62#define SCREEN_TO_GLOBAL_X 0
63#define SCREEN_TO_GLOBAL_Y 0
64#endif
65
66#define MAKE_WINDOW_ID(x)		((xp_window_id)((size_t)(x)))
67
68#define DEFINE_ATOM_HELPER(func,atom_name)                      \
69  static Atom func (void) {                                       \
70    static unsigned int generation = 0;                             \
71    static Atom atom;                                           \
72    if (generation != serverGeneration) {                       \
73      generation = serverGeneration;                          \
74      atom = MakeAtom (atom_name, strlen (atom_name), TRUE);  \
75    }                                                           \
76    return atom;                                                \
77  }
78
79DEFINE_ATOM_HELPER (xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN")
80DEFINE_ATOM_HELPER (xa_native_window_id, "_NATIVE_WINDOW_ID")
81DEFINE_ATOM_HELPER (xa_apple_no_order_in, "_APPLE_NO_ORDER_IN")
82
83static Bool no_configure_window;
84static Bool windows_hidden;
85// TODO - abstract xp functions
86
87static inline int
88configure_window (xp_window_id id, unsigned int mask,
89                  const xp_window_changes *values)
90{
91  if (!no_configure_window)
92    return xp_configure_window (id, mask, values);
93  else
94    return XP_Success;
95}
96
97/*static inline unsigned long
98current_time_in_seconds (void)
99{
100  unsigned long t = 0;
101
102  t += currentTime.milliseconds / 1000;
103  t += currentTime.months * 4294967;
104
105  return t;
106  } */
107
108static inline Bool
109rootlessHasRoot (ScreenPtr pScreen)
110{
111  return WINREC (WindowTable[pScreen->myNum]) != NULL;
112}
113
114void
115RootlessNativeWindowStateChanged (WindowPtr pWin, unsigned int state)
116{
117  RootlessWindowRec *winRec;
118
119  if (pWin == NULL) return;
120
121  winRec = WINREC (pWin);
122  if (winRec == NULL) return;
123
124  winRec->is_offscreen = ((state & XP_WINDOW_STATE_OFFSCREEN) != 0);
125  winRec->is_obscured = ((state & XP_WINDOW_STATE_OBSCURED) != 0);
126  pWin->rootlessUnhittable = winRec->is_offscreen;
127}
128
129void RootlessNativeWindowMoved (WindowPtr pWin) {
130    xp_box bounds;
131    int sx, sy, err;
132    XID vlist[2];
133    Mask mask;
134    ClientPtr pClient;
135    RootlessWindowRec *winRec;
136
137    winRec = WINREC(pWin);
138
139    if (xp_get_window_bounds (MAKE_WINDOW_ID(winRec->wid), &bounds) != Success) return;
140
141    sx = dixScreenOrigins[pWin->drawable.pScreen->myNum].x + darwinMainScreenX;
142    sy = dixScreenOrigins[pWin->drawable.pScreen->myNum].y + darwinMainScreenY;
143
144    /* Fake up a ConfigureWindow packet to resize the window to the current bounds. */
145    vlist[0] = (INT16) bounds.x1 - sx;
146    vlist[1] = (INT16) bounds.y1 - sy;
147    mask = CWX | CWY;
148
149    /* pretend we're the owner of the window! */
150    err = dixLookupClient(&pClient, pWin->drawable.id, NullClient, DixUnknownAccess);
151    if(err != Success) {
152        ErrorF("RootlessNativeWindowMoved(): Failed to lookup window: 0x%x\n", (unsigned int)pWin->drawable.id);
153        return;
154    }
155
156    /* Don't want to do anything to the physical window (avoids
157     notification-response feedback loops) */
158
159    no_configure_window = TRUE;
160    ConfigureWindow (pWin, mask, vlist, pClient);
161    no_configure_window = FALSE;
162}
163
164/* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */
165static void
166set_screen_origin (WindowPtr pWin)
167{
168  long data[2];
169
170  if (!IsRoot (pWin))
171    return;
172
173  /* FIXME: move this to an extension? */
174
175  data[0] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].x
176	     + darwinMainScreenX);
177  data[1] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].y
178	     + darwinMainScreenY);
179
180  dixChangeWindowProperty(serverClient, pWin, xa_native_screen_origin(),
181			  XA_INTEGER, 32, PropModeReplace, 2, data, TRUE);
182}
183
184/*
185 * RootlessCreateWindow
186 *  For now, don't create a physical window until either the window is
187 *  realized, or we really need it (e.g. to attach VRAM surfaces to).
188 *  Do reset the window size so it's not clipped by the root window.
189 */
190Bool
191RootlessCreateWindow(WindowPtr pWin)
192{
193    Bool result;
194    RegionRec saveRoot;
195
196    SETWINREC(pWin, NULL);
197    dixSetPrivate(&pWin->devPrivates, rootlessWindowOldPixmapPrivateKey, NULL);
198
199    SCREEN_UNWRAP(pWin->drawable.pScreen, CreateWindow);
200
201    if (!IsRoot(pWin)) {
202        /* win/border size set by DIX, not by wrapped CreateWindow, so
203           correct it here. Don't HUGE_ROOT when pWin is the root! */
204
205        HUGE_ROOT(pWin);
206        SetWinSize(pWin);
207        SetBorderSize(pWin);
208    }
209
210    result = pWin->drawable.pScreen->CreateWindow(pWin);
211
212    if (pWin->parent) {
213        NORMAL_ROOT(pWin);
214    }
215
216    SCREEN_WRAP(pWin->drawable.pScreen, CreateWindow);
217
218    return result;
219}
220
221
222/*
223 * RootlessDestroyFrame
224 *  Destroy the physical window associated with the given window.
225 */
226static void
227RootlessDestroyFrame(WindowPtr pWin, RootlessWindowPtr winRec)
228{
229    ScreenPtr pScreen = pWin->drawable.pScreen;
230
231    SCREENREC(pScreen)->imp->DestroyFrame(winRec->wid);
232
233#ifdef ROOTLESS_TRACK_DAMAGE
234    REGION_UNINIT(pScreen, &winRec->damage);
235#endif
236
237    xfree(winRec);
238    SETWINREC(pWin, NULL);
239}
240
241
242/*
243 * RootlessDestroyWindow
244 *  Destroy the physical window associated with the given window.
245 */
246Bool
247RootlessDestroyWindow(WindowPtr pWin)
248{
249    RootlessWindowRec *winRec = WINREC(pWin);
250    Bool result;
251
252    if (winRec != NULL) {
253        RootlessDestroyFrame(pWin, winRec);
254    }
255
256    SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
257    result = pWin->drawable.pScreen->DestroyWindow(pWin);
258    SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
259
260    return result;
261}
262
263
264
265static Bool
266RootlessGetShape(WindowPtr pWin, RegionPtr pShape)
267{
268    ScreenPtr pScreen = pWin->drawable.pScreen;
269
270    /*
271     * Avoid a warning.
272     * REGION_NULL and the other macros don't actually seem to use pScreen.
273     */
274    (void)pScreen;
275
276    if (wBoundingShape(pWin) == NULL)
277        return FALSE;
278
279    /* wBoundingShape is relative to *inner* origin of window.
280       Translate by borderWidth to get the outside-relative position. */
281
282    REGION_NULL(pScreen, pShape);
283    REGION_COPY(pScreen, pShape, wBoundingShape(pWin));
284    REGION_TRANSLATE(pScreen, pShape, pWin->borderWidth, pWin->borderWidth);
285
286    return TRUE;
287}
288
289
290/*
291 * RootlessReshapeFrame
292 *  Set the frame shape.
293 */
294static void RootlessReshapeFrame(WindowPtr pWin)
295{
296    RootlessWindowRec *winRec = WINREC(pWin);
297    ScreenPtr pScreen = pWin->drawable.pScreen;
298    RegionRec newShape;
299    RegionPtr pShape;
300
301    // If the window is not yet framed, do nothing
302    if (winRec == NULL)
303        return;
304
305    if (IsRoot(pWin))
306        return;
307
308    RootlessStopDrawing(pWin, FALSE);
309
310    pShape = RootlessGetShape(pWin, &newShape) ? &newShape : NULL;
311
312#ifdef ROOTLESSDEBUG
313    RL_DEBUG_MSG("reshaping...");
314    if (pShape != NULL) {
315        RL_DEBUG_MSG("numrects %d, extents %d %d %d %d ",
316                     REGION_NUM_RECTS(&newShape),
317                     newShape.extents.x1, newShape.extents.y1,
318                     newShape.extents.x2, newShape.extents.y2);
319    } else {
320        RL_DEBUG_MSG("no shape ");
321    }
322#endif
323
324    SCREENREC(pScreen)->imp->ReshapeFrame(winRec->wid, pShape);
325
326    if (pShape != NULL)
327        REGION_UNINIT(pScreen, &newShape);
328}
329
330
331/*
332 * RootlessSetShape
333 *  Shape is usually set before a window is mapped and the window will
334 *  not have a frame associated with it. In this case, the frame will be
335 *  shaped when the window is framed.
336 */
337void
338RootlessSetShape(WindowPtr pWin)
339{
340    ScreenPtr pScreen = pWin->drawable.pScreen;
341
342    SCREEN_UNWRAP(pScreen, SetShape);
343    pScreen->SetShape(pWin);
344    SCREEN_WRAP(pScreen, SetShape);
345
346    RootlessReshapeFrame(pWin);
347}
348
349
350
351/* Disallow ParentRelative background on top-level windows
352   because the root window doesn't really have the right background.
353 */
354Bool
355RootlessChangeWindowAttributes(WindowPtr pWin, unsigned long vmask)
356{
357    Bool result;
358    ScreenPtr pScreen = pWin->drawable.pScreen;
359
360    RL_DEBUG_MSG("change window attributes start ");
361
362    SCREEN_UNWRAP(pScreen, ChangeWindowAttributes);
363    result = pScreen->ChangeWindowAttributes(pWin, vmask);
364    SCREEN_WRAP(pScreen, ChangeWindowAttributes);
365
366    if (WINREC(pWin)) {
367        // disallow ParentRelative background state
368        if (pWin->backgroundState == ParentRelative) {
369            XID pixel = 0;
370            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
371        }
372    }
373
374    RL_DEBUG_MSG("change window attributes end\n");
375    return result;
376}
377
378
379/*
380 * RootlessPositionWindow
381 *  This is a hook for when DIX moves or resizes a window.
382 *  Update the frame position now although the physical window is moved
383 *  in RootlessMoveWindow. (x, y) are *inside* position. After this,
384 *  mi and fb are expecting the pixmap to be at the new location.
385 */
386Bool
387RootlessPositionWindow(WindowPtr pWin, int x, int y)
388{
389    ScreenPtr pScreen = pWin->drawable.pScreen;
390    RootlessWindowRec *winRec = WINREC(pWin);
391    Bool result;
392
393    RL_DEBUG_MSG("positionwindow start (win 0x%x @ %i, %i)\n", pWin, x, y);
394
395    if (winRec) {
396        if (winRec->is_drawing) {
397            // Reset frame's pixmap and move it to the new position.
398            int bw = wBorderWidth(pWin);
399
400            winRec->pixmap->devPrivate.ptr = winRec->pixelData;
401            SetPixmapBaseToScreen(winRec->pixmap, x - bw, y - bw);
402
403#ifdef ROOTLESS_TRACK_DAMAGE
404            // Move damaged region to correspond to new window position
405            if (REGION_NOTEMPTY(pScreen, &winRec->damage)) {
406                REGION_TRANSLATE(pScreen, &winRec->damage,
407                                 x - bw - winRec->x,
408                                 y - bw - winRec->y);
409            }
410#endif
411        }
412    }
413
414    SCREEN_UNWRAP(pScreen, PositionWindow);
415    result = pScreen->PositionWindow(pWin, x, y);
416    SCREEN_WRAP(pScreen, PositionWindow);
417
418    RL_DEBUG_MSG("positionwindow end\n");
419    return result;
420}
421
422
423/*
424 * RootlessInitializeFrame
425 *  Initialize some basic attributes of the frame. Note that winRec
426 *  may already have valid data in it, so don't overwrite anything
427 *  valuable.
428 */
429static void
430RootlessInitializeFrame(WindowPtr pWin, RootlessWindowRec *winRec)
431{
432    DrawablePtr d = &pWin->drawable;
433    int bw = wBorderWidth(pWin);
434
435    winRec->win = pWin;
436
437    winRec->x = d->x - bw;
438    winRec->y = d->y - bw;
439    winRec->width = d->width + 2*bw;
440    winRec->height = d->height + 2*bw;
441    winRec->borderWidth = bw;
442
443#ifdef ROOTLESS_TRACK_DAMAGE
444    REGION_NULL(pScreen, &winRec->damage);
445#endif
446}
447
448
449Bool
450RootlessColormapCallback (void *data, int first_color, int n_colors, uint32_t *colors)
451{
452    return (RootlessResolveColormap (data, first_color, n_colors, colors) ? XP_Success : XP_BadMatch);
453}
454
455/*
456 * RootlessEnsureFrame
457 *  Make sure the given window is framed. If the window doesn't have a
458 *  physical window associated with it, attempt to create one. If that
459 *  is unsuccessful, return NULL.
460 */
461static RootlessWindowRec *
462RootlessEnsureFrame(WindowPtr pWin)
463{
464    ScreenPtr pScreen = pWin->drawable.pScreen;
465    RootlessWindowRec *winRec;
466    RegionRec shape;
467    RegionPtr pShape = NULL;
468
469    if (WINREC(pWin) != NULL)
470        return WINREC(pWin);
471
472    if (!IsTopLevel(pWin) && !IsRoot(pWin))
473        return NULL;
474
475    if (pWin->drawable.class != InputOutput)
476        return NULL;
477
478    winRec = xalloc(sizeof(RootlessWindowRec));
479
480    if (!winRec)
481        return NULL;
482
483    RootlessInitializeFrame(pWin, winRec);
484
485    winRec->is_drawing = FALSE;
486    winRec->is_reorder_pending = FALSE;
487    winRec->pixmap = NULL;
488    winRec->wid = NULL;
489
490    SETWINREC(pWin, winRec);
491
492    // Set the frame's shape if the window is shaped
493    if (RootlessGetShape(pWin, &shape))
494        pShape = &shape;
495
496    RL_DEBUG_MSG("creating frame ");
497
498    if (!SCREENREC(pScreen)->imp->CreateFrame(winRec, pScreen,
499                                              winRec->x + SCREEN_TO_GLOBAL_X,
500                                              winRec->y + SCREEN_TO_GLOBAL_Y,
501                                              pShape))
502    {
503        RL_DEBUG_MSG("implementation failed to create frame!\n");
504        xfree(winRec);
505        SETWINREC(pWin, NULL);
506        return NULL;
507    }
508
509    if (pWin->drawable.depth == 8)
510      RootlessFlushWindowColormap(pWin);
511
512    if (pShape != NULL)
513        REGION_UNINIT(pScreen, &shape);
514
515    return winRec;
516}
517
518
519/*
520 * RootlessRealizeWindow
521 *  The frame is usually created here and not in CreateWindow so that
522 *  windows do not eat memory until they are realized.
523 */
524Bool
525RootlessRealizeWindow(WindowPtr pWin)
526{
527    Bool result;
528    RegionRec saveRoot;
529    ScreenPtr pScreen = pWin->drawable.pScreen;
530
531    RL_DEBUG_MSG("realizewindow start (win 0x%x) ", pWin);
532
533    if ((IsTopLevel(pWin) && pWin->drawable.class == InputOutput)) {
534        RootlessWindowRec *winRec;
535
536        winRec = RootlessEnsureFrame(pWin);
537        if (winRec == NULL)
538            return FALSE;
539
540        winRec->is_reorder_pending = TRUE;
541
542        RL_DEBUG_MSG("Top level window ");
543
544        // Disallow ParentRelative background state on top-level windows.
545        // This might have been set before the window was mapped.
546        if (pWin->backgroundState == ParentRelative) {
547            XID pixel = 0;
548            ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
549        }
550    }
551
552    if (!IsRoot(pWin)) HUGE_ROOT(pWin);
553    SCREEN_UNWRAP(pScreen, RealizeWindow);
554    result = pScreen->RealizeWindow(pWin);
555    SCREEN_WRAP(pScreen, RealizeWindow);
556    if (!IsRoot(pWin)) NORMAL_ROOT(pWin);
557
558    RL_DEBUG_MSG("realizewindow end\n");
559    return result;
560}
561
562
563/*
564 * RootlessFrameForWindow
565 *  Returns the frame ID for the physical window displaying the given window.
566 *  If CREATE is true and the window has no frame, attempt to create one.
567 */
568RootlessFrameID
569RootlessFrameForWindow(WindowPtr pWin, Bool create)
570{
571    WindowPtr pTopWin;
572    RootlessWindowRec *winRec;
573
574    pTopWin = TopLevelParent(pWin);
575    if (pTopWin == NULL)
576        return NULL;
577
578    winRec = WINREC(pTopWin);
579
580    if (winRec == NULL && create && pWin->drawable.class == InputOutput) {
581        winRec = RootlessEnsureFrame(pTopWin);
582    }
583
584    if (winRec == NULL)
585        return NULL;
586
587    return winRec->wid;
588}
589
590
591/*
592 * RootlessUnrealizeWindow
593 *  Unmap the physical window.
594 */
595Bool
596RootlessUnrealizeWindow(WindowPtr pWin)
597{
598    ScreenPtr pScreen = pWin->drawable.pScreen;
599    RootlessWindowRec *winRec = WINREC(pWin);
600    Bool result;
601
602    RL_DEBUG_MSG("unrealizewindow start ");
603
604    if (winRec) {
605        RootlessStopDrawing(pWin, FALSE);
606
607        SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
608
609        winRec->is_reorder_pending = FALSE;
610    }
611
612    SCREEN_UNWRAP(pScreen, UnrealizeWindow);
613    result = pScreen->UnrealizeWindow(pWin);
614    SCREEN_WRAP(pScreen, UnrealizeWindow);
615
616    RL_DEBUG_MSG("unrealizewindow end\n");
617    return result;
618}
619
620
621/*
622 * RootlessReorderWindow
623 *  Reorder the frame associated with the given window so that it's
624 *  physically above the window below it in the X stacking order.
625 */
626void
627RootlessReorderWindow(WindowPtr pWin)
628{
629    RootlessWindowRec *winRec = WINREC(pWin);
630
631    if (pWin->realized && winRec != NULL && !winRec->is_reorder_pending && !windows_hidden) {
632        WindowPtr newPrevW;
633        RootlessWindowRec *newPrev;
634        RootlessFrameID newPrevID;
635        ScreenPtr pScreen = pWin->drawable.pScreen;
636
637        /* Check if the implementation wants the frame to not be reordered
638           even though the X11 window is restacked. This can be useful if
639           frames are ordered-in with animation so that the reordering is not
640           done until the animation is complete. */
641        if (SCREENREC(pScreen)->imp->DoReorderWindow) {
642            if (!SCREENREC(pScreen)->imp->DoReorderWindow(winRec))
643                return;
644        }
645
646        RootlessStopDrawing(pWin, FALSE);
647
648        /* Find the next window above this one that has a mapped frame. */
649
650        newPrevW = pWin->prevSib;
651        while (newPrevW && (WINREC(newPrevW) == NULL || !newPrevW->realized))
652            newPrevW = newPrevW->prevSib;
653
654        newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
655        newPrevID = newPrev != NULL ? newPrev->wid : 0;
656
657        /* If it exists, reorder the frame above us first. */
658
659        if (newPrev && newPrev->is_reorder_pending) {
660            newPrev->is_reorder_pending = FALSE;
661            RootlessReorderWindow(newPrevW);
662        }
663
664        SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
665    }
666}
667
668
669/*
670 * RootlessRestackWindow
671 *  This is a hook for when DIX changes the window stacking order.
672 *  The window has already been inserted into its new position in the
673 *  DIX window stack. We need to change the order of the physical
674 *  window to match.
675 */
676void
677RootlessRestackWindow(WindowPtr pWin, WindowPtr pOldNextSib)
678{
679    RegionRec saveRoot;
680    RootlessWindowRec *winRec = WINREC(pWin);
681    ScreenPtr pScreen = pWin->drawable.pScreen;
682
683    RL_DEBUG_MSG("restackwindow start ");
684    if (winRec)
685        RL_DEBUG_MSG("restack top level \n");
686
687    HUGE_ROOT(pWin);
688    SCREEN_UNWRAP(pScreen, RestackWindow);
689
690    if (pScreen->RestackWindow)
691        pScreen->RestackWindow(pWin, pOldNextSib);
692
693    SCREEN_WRAP(pScreen, RestackWindow);
694    NORMAL_ROOT(pWin);
695
696    if (winRec && pWin->viewable) {
697        RootlessReorderWindow(pWin);
698    }
699
700    RL_DEBUG_MSG("restackwindow end\n");
701}
702
703/*
704 * Specialized window copy procedures
705 */
706
707// Globals needed during window resize and move.
708static pointer gResizeDeathBits = NULL;
709static int gResizeDeathCount = 0;
710static PixmapPtr gResizeDeathPix[2] = {NULL, NULL};
711static BoxRec gResizeDeathBounds[2];
712static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
713
714/*
715 * RootlessNoCopyWindow
716 *  CopyWindow() that doesn't do anything. For MoveWindow() of
717 *  top-level windows.
718 */
719static void
720RootlessNoCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
721                     RegionPtr prgnSrc)
722{
723    // some code expects the region to be translated
724    int dx = ptOldOrg.x - pWin->drawable.x;
725    int dy = ptOldOrg.y - pWin->drawable.y;
726
727    RL_DEBUG_MSG("ROOTLESSNOCOPYWINDOW ");
728
729    REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
730}
731
732
733/*
734 * RootlessResizeCopyWindow
735 *  CopyWindow used during ResizeWindow for gravity moves. Based on
736 *  fbCopyWindow. The original always draws on the root pixmap, which
737 *  we don't have. Instead, draw on the parent window's pixmap.
738 *  Resize version: the old location's pixels are in gResizeCopyWindowSource.
739 */
740static void
741RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
742                         RegionPtr prgnSrc)
743{
744    ScreenPtr pScreen = pWin->drawable.pScreen;
745    RegionRec   rgnDst;
746    int         dx, dy;
747
748    RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
749
750    /* Don't unwrap pScreen->CopyWindow.
751       The bogus rewrap with RootlessCopyWindow causes a crash if
752       CopyWindow is called again during the same resize. */
753
754    if (gResizeDeathCount == 0)
755        return;
756
757    RootlessStartDrawing(pWin);
758
759    dx = ptOldOrg.x - pWin->drawable.x;
760    dy = ptOldOrg.y - pWin->drawable.y;
761    REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
762    REGION_NULL(pScreen, &rgnDst);
763    REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
764
765    if (gResizeDeathCount == 1) {
766        /* Simple case, we only have a single source pixmap. */
767
768        fbCopyRegion(&gResizeDeathPix[0]->drawable,
769                     &pScreen->GetWindowPixmap(pWin)->drawable, 0,
770                     &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
771    }
772    else {
773        int i;
774        RegionRec clip, clipped;
775
776        /* More complex case, N source pixmaps (usually two). So we
777           intersect the destination with each source and copy those bits. */
778
779        for (i = 0; i < gResizeDeathCount; i++) {
780            REGION_INIT(pScreen, &clip, gResizeDeathBounds + 0, 1);
781            REGION_NULL(pScreen, &clipped);
782            REGION_INTERSECT(pScreen, &rgnDst, &clip, &clipped);
783
784            fbCopyRegion(&gResizeDeathPix[i]->drawable,
785                         &pScreen->GetWindowPixmap(pWin)->drawable, 0,
786                         &clipped, dx, dy, fbCopyWindowProc, 0, 0);
787
788            REGION_UNINIT(pScreen, &clipped);
789            REGION_UNINIT(pScreen, &clip);
790        }
791    }
792
793    /* Don't update - resize will update everything */
794    REGION_UNINIT(pScreen, &rgnDst);
795
796    fbValidateDrawable(&pWin->drawable);
797
798    RL_DEBUG_MSG("resizecopywindowFB end\n");
799}
800
801
802/*
803 * RootlessCopyWindow
804 *  Update *new* location of window. Old location is redrawn with
805 *  miPaintWindow. Cloned from fbCopyWindow.
806 *  The original always draws on the root pixmap, which we don't have.
807 *  Instead, draw on the parent window's pixmap.
808 */
809void
810RootlessCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
811{
812    ScreenPtr pScreen = pWin->drawable.pScreen;
813    RegionRec   rgnDst;
814    int         dx, dy;
815    BoxPtr extents;
816    int area;
817
818    RL_DEBUG_MSG("copywindowFB start (win 0x%x) ", pWin);
819
820    SCREEN_UNWRAP(pScreen, CopyWindow);
821
822    dx = ptOldOrg.x - pWin->drawable.x;
823    dy = ptOldOrg.y - pWin->drawable.y;
824    REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
825
826    REGION_NULL(pScreen, &rgnDst);
827    REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
828
829    extents = REGION_EXTENTS(pScreen, &rgnDst);
830    area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
831
832    /* If the area exceeds threshold, use the implementation's
833       accelerated version. */
834    if (area > rootless_CopyWindow_threshold &&
835        SCREENREC(pScreen)->imp->CopyWindow)
836    {
837        RootlessWindowRec *winRec;
838        WindowPtr top;
839
840        top = TopLevelParent(pWin);
841        if (top == NULL) {
842            RL_DEBUG_MSG("no parent\n");
843            goto out;
844        }
845
846        winRec = WINREC(top);
847        if (winRec == NULL) {
848            RL_DEBUG_MSG("not framed\n");
849            goto out;
850        }
851
852        /* Move region to window local coords */
853        REGION_TRANSLATE(pScreen, &rgnDst, -winRec->x, -winRec->y);
854
855        RootlessStopDrawing(pWin, FALSE);
856
857        SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
858                                            REGION_NUM_RECTS(&rgnDst),
859                                            REGION_RECTS(&rgnDst),
860                                            dx, dy);
861    }
862    else {
863        RootlessStartDrawing(pWin);
864
865        fbCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
866                     0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
867
868        /* prgnSrc has been translated to dst position */
869        RootlessDamageRegion(pWin, prgnSrc);
870    }
871
872out:
873    REGION_UNINIT(pScreen, &rgnDst);
874    fbValidateDrawable(&pWin->drawable);
875
876    SCREEN_WRAP(pScreen, CopyWindow);
877
878    RL_DEBUG_MSG("copywindowFB end\n");
879}
880
881
882/*
883 * Window resize procedures
884 */
885
886enum {
887    WIDTH_SMALLER = 1,
888    HEIGHT_SMALLER = 2,
889};
890
891
892/*
893 * ResizeWeighting
894 *  Choose gravity to avoid local copies. Do that by looking for
895 *  a corner that doesn't move _relative to the screen_.
896 */
897static inline unsigned int
898ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
899                int newX1, int newY1, int newX2, int newY2, int newBW)
900{
901#ifdef ROOTLESS_RESIZE_GRAVITY
902    if (newBW != oldBW)
903        return RL_GRAVITY_NONE;
904
905    if (newX1 == oldX1 && newY1 == oldY1)
906        return RL_GRAVITY_NORTH_WEST;
907    else if (newX1 == oldX1 && newY2 == oldY2)
908        return RL_GRAVITY_SOUTH_WEST;
909    else if (newX2 == oldX2 && newY2 == oldY2)
910        return RL_GRAVITY_SOUTH_EAST;
911    else if (newX2 == oldX2 && newY1 == oldY1)
912        return RL_GRAVITY_NORTH_EAST;
913    else
914        return RL_GRAVITY_NONE;
915#else
916    return RL_GRAVITY_NONE;
917#endif
918}
919
920
921/*
922 * StartFrameResize
923 *  Prepare to resize a top-level window. The old window's pixels are
924 *  saved and the implementation is told to change the window size.
925 *  (x,y,w,h) is outer frame of window (outside border)
926 */
927static Bool
928StartFrameResize(WindowPtr pWin, Bool gravity,
929                 int oldX, int oldY, int oldW, int oldH, int oldBW,
930                 int newX, int newY, int newW, int newH, int newBW)
931{
932    ScreenPtr pScreen = pWin->drawable.pScreen;
933    RootlessWindowRec *winRec = WINREC(pWin);
934    Bool need_window_source = FALSE, resize_after = FALSE;
935
936    BoxRec rect;
937    int oldX2, newX2;
938    int oldY2, newY2;
939    unsigned int weight;
940
941    oldX2 = oldX + oldW, newX2 = newX + newW;
942    oldY2 = oldY + oldH, newY2 = newY + newH;
943
944    /* Decide which resize weighting to use */
945    weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
946                             newX, newY, newW, newH, newBW);
947
948    /* Compute intersection between old and new rects */
949    rect.x1 = max(oldX, newX);
950    rect.y1 = max(oldY, newY);
951    rect.x2 = min(oldX2, newX2);
952    rect.y2 = min(oldY2, newY2);
953
954    RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
955    RL_DEBUG_MSG("%d %d %d %d %d   %d %d %d %d %d\n",
956                 oldX, oldY, oldW, oldH, oldBW,
957                 newX, newY, newW, newH, newBW);
958
959    RootlessRedisplay(pWin);
960
961    /* If gravity is true, then we need to have a way of recovering all
962       the original bits in the window for when X rearranges the contents
963       based on the various gravity settings. The obvious way is to just
964       snapshot the entire backing store before resizing it, but that
965       it slow on large windows.
966
967       So the optimization here is to use the implementation's resize
968       weighting options (if available) to allow us to reason about what
969       is left in the backing store after the resize. We can then only
970       copy what won't be there after the resize, and do a two-stage copy
971       operation.
972
973       Most of these optimizations are only applied when the top-left
974       corner of the window is fixed, since that's the common case. They
975       could probably be extended with some thought. */
976
977    gResizeDeathCount = 0;
978
979    if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
980        unsigned int code = 0;
981
982        /* Top left corner is anchored. We never need to copy the
983           entire window. */
984
985        need_window_source = TRUE;
986
987        /* These comparisons were chosen to avoid setting bits when the sizes
988        are the same. (So the fastest case automatically gets taken when
989        dimensions are unchanging.) */
990
991        if (newW < oldW)
992            code |= WIDTH_SMALLER;
993        if (newH < oldH)
994            code |= HEIGHT_SMALLER;
995
996        if (((code ^ (code >> 1)) & 1) == 0) {
997            /* Both dimensions are either getting larger, or both
998               are getting smaller. No need to copy anything. */
999
1000            if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
1001                /* Since the window is getting smaller, we can do gravity
1002                   repair on it with it's current size, then resize it
1003                   afterwards. */
1004
1005                resize_after = TRUE;
1006            }
1007
1008            gResizeDeathCount = 1;
1009        }
1010        else {
1011            unsigned int copy_rowbytes, Bpp;
1012            unsigned int copy_rect_width, copy_rect_height;
1013            BoxRec copy_rect;
1014
1015            /* We can get away with a partial copy. 'rect' is the
1016               intersection between old and new bounds, so copy
1017               everything to the right of or below the intersection. */
1018
1019            RootlessStartDrawing(pWin);
1020
1021            if (code == WIDTH_SMALLER) {
1022                copy_rect.x1 = rect.x2;
1023                copy_rect.y1 = rect.y1;
1024                copy_rect.x2 = oldX2;
1025                copy_rect.y2 = oldY2;
1026            }
1027            else if (code == HEIGHT_SMALLER) {
1028                copy_rect.x1 = rect.x1;
1029                copy_rect.y1 = rect.y2;
1030                copy_rect.x2 = oldX2;
1031                copy_rect.y2 = oldY2;
1032            }
1033            else
1034                abort();
1035
1036            Bpp = winRec->win->drawable.bitsPerPixel / 8;
1037            copy_rect_width = copy_rect.x2 - copy_rect.x1;
1038            copy_rect_height = copy_rect.y2 - copy_rect.y1;
1039            copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
1040            gResizeDeathBits = xalloc(copy_rowbytes
1041                                      * copy_rect_height);
1042
1043            if (copy_rect_width * copy_rect_height >
1044                        rootless_CopyBytes_threshold &&
1045                SCREENREC(pScreen)->imp->CopyBytes)
1046            {
1047                SCREENREC(pScreen)->imp->CopyBytes(
1048                    copy_rect_width * Bpp, copy_rect_height,
1049                    ((char *) winRec->pixelData)
1050                    + ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
1051                    + (copy_rect.x1 - oldX) * Bpp, winRec->bytesPerRow,
1052                    gResizeDeathBits, copy_rowbytes);
1053            } else {
1054                fbBlt((FbBits *) (winRec->pixelData
1055                      + ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
1056                      + (copy_rect.x1 - oldX) * Bpp),
1057                      winRec->bytesPerRow / sizeof(FbBits), 0,
1058                      (FbBits *) gResizeDeathBits,
1059                      copy_rowbytes / sizeof(FbBits), 0,
1060                      copy_rect_width * Bpp, copy_rect_height,
1061                      GXcopy, FB_ALLONES, Bpp, 0, 0);
1062            }
1063
1064            gResizeDeathBounds[1] = copy_rect;
1065            gResizeDeathPix[1]
1066                = GetScratchPixmapHeader(pScreen, copy_rect_width,
1067                                         copy_rect_height,
1068                                         winRec->win->drawable.depth,
1069                                         winRec->win->drawable.bitsPerPixel,
1070                                         winRec->bytesPerRow,
1071                                         (void *) gResizeDeathBits);
1072
1073            SetPixmapBaseToScreen(gResizeDeathPix[1],
1074                                  copy_rect.x1, copy_rect.y1);
1075
1076            gResizeDeathCount = 2;
1077        }
1078    }
1079    else if (gravity) {
1080        /* The general case. Just copy everything. */
1081
1082        RootlessStartDrawing(pWin);
1083
1084        gResizeDeathBits = xalloc(winRec->bytesPerRow * winRec->height);
1085
1086        memcpy(gResizeDeathBits, winRec->pixelData,
1087               winRec->bytesPerRow * winRec->height);
1088
1089        gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
1090        gResizeDeathPix[0]
1091            = GetScratchPixmapHeader(pScreen, winRec->width,
1092                                     winRec->height,
1093                                     winRec->win->drawable.depth,
1094                                     winRec->win->drawable.bitsPerPixel,
1095                                     winRec->bytesPerRow,
1096                                     (void *) gResizeDeathBits);
1097
1098        SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1099        gResizeDeathCount = 1;
1100    }
1101
1102    RootlessStopDrawing(pWin, FALSE);
1103
1104    winRec->x = newX;
1105    winRec->y = newY;
1106    winRec->width = newW;
1107    winRec->height = newH;
1108    winRec->borderWidth = newBW;
1109
1110    /* Unless both dimensions are getting smaller, Resize the frame
1111       before doing gravity repair */
1112
1113    if (!resize_after) {
1114        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1115                                             newX + SCREEN_TO_GLOBAL_X,
1116                                             newY + SCREEN_TO_GLOBAL_Y,
1117                                             newW, newH, weight);
1118    }
1119
1120    RootlessStartDrawing(pWin);
1121
1122    /* If necessary, create a source pixmap pointing at the current
1123       window bits. */
1124
1125    if (need_window_source) {
1126        gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
1127        gResizeDeathPix[0]
1128            = GetScratchPixmapHeader(pScreen, oldW, oldH,
1129                                     winRec->win->drawable.depth,
1130                                     winRec->win->drawable.bitsPerPixel,
1131                                     winRec->bytesPerRow, winRec->pixelData);
1132
1133        SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1134    }
1135
1136    /* Use custom CopyWindow when moving gravity bits around
1137       ResizeWindow assumes the old window contents are in the same
1138       pixmap, but here they're in deathPix instead. */
1139
1140    if (gravity) {
1141        gResizeOldCopyWindowProc = pScreen->CopyWindow;
1142        pScreen->CopyWindow = RootlessResizeCopyWindow;
1143    }
1144
1145    /* If we can't rely on the window server preserving the bits we
1146       need in the position we need, copy the pixels in the
1147       intersection from src to dst. ResizeWindow assumes these pixels
1148       are already present when making gravity adjustments. pWin
1149       currently has new-sized pixmap but is in old position.
1150
1151       FIXME: border width change! (?) */
1152
1153    if (gravity && weight == RL_GRAVITY_NONE) {
1154        PixmapPtr src, dst;
1155
1156        assert(gResizeDeathCount == 1);
1157
1158        src = gResizeDeathPix[0];
1159        dst = pScreen->GetWindowPixmap(pWin);
1160
1161        RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1162                     rect.x1, rect.y1, rect.x2, rect.y2);
1163
1164        /* rect is the intersection of the old location and new location */
1165        if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
1166            /* The window drawable still has the old frame position, which
1167               means that DST doesn't actually point at the origin of our
1168               physical backing store when adjusted by the drawable.x,y
1169               position. So sneakily adjust it temporarily while copying.. */
1170
1171            ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1172            SetPixmapBaseToScreen(dst, newX, newY);
1173
1174            fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1175                             &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1176
1177            ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1178            SetPixmapBaseToScreen(dst, oldX, oldY);
1179        }
1180    }
1181
1182    return resize_after;
1183}
1184
1185
1186static void
1187FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
1188                  unsigned int oldW, unsigned int oldH, unsigned int oldBW,
1189                  int newX, int newY, unsigned int newW, unsigned int newH,
1190                  unsigned int newBW, Bool resize_now)
1191{
1192    ScreenPtr pScreen = pWin->drawable.pScreen;
1193    RootlessWindowRec *winRec = WINREC(pWin);
1194    int i;
1195
1196    RootlessStopDrawing(pWin, FALSE);
1197
1198    if (resize_now) {
1199        unsigned int weight;
1200
1201        /* We didn't resize anything earlier, so do it now, now that
1202           we've finished gravitating the bits. */
1203
1204        weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
1205                                 newX, newY, newW, newH, newBW);
1206
1207        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1208                                             newX + SCREEN_TO_GLOBAL_X,
1209                                             newY + SCREEN_TO_GLOBAL_Y,
1210                                             newW, newH, weight);
1211    }
1212
1213    /* Redraw everything. FIXME: there must be times when we don't need
1214       to do this. Perhaps when top-left weighting and no gravity? */
1215
1216    RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
1217
1218    for (i = 0; i < 2; i++) {
1219        if (gResizeDeathPix[i] != NULL) {
1220            FreeScratchPixmapHeader(gResizeDeathPix[i]);
1221            gResizeDeathPix[i] = NULL;
1222        }
1223    }
1224
1225    if (gResizeDeathBits != NULL) {
1226        xfree(gResizeDeathBits);
1227        gResizeDeathBits = NULL;
1228    }
1229
1230    if (gravity) {
1231        pScreen->CopyWindow = gResizeOldCopyWindowProc;
1232    }
1233}
1234
1235
1236/*
1237 * RootlessMoveWindow
1238 *  If kind==VTOther, window border is resizing (and borderWidth is
1239 *  already changed!!@#$)  This case works like window resize, not move.
1240 */
1241void
1242RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1243{
1244    RootlessWindowRec *winRec = WINREC(pWin);
1245    ScreenPtr pScreen = pWin->drawable.pScreen;
1246    CopyWindowProcPtr oldCopyWindowProc = NULL;
1247    int oldX = 0, oldY = 0, newX = 0, newY = 0;
1248    unsigned int oldW = 0, oldH = 0, oldBW = 0;
1249    unsigned int newW = 0, newH = 0, newBW = 0;
1250    Bool resize_after = FALSE;
1251    RegionRec saveRoot;
1252
1253    RL_DEBUG_MSG("movewindow start \n");
1254
1255    if (winRec) {
1256        if (kind == VTMove) {
1257            oldX = winRec->x;
1258            oldY = winRec->y;
1259            RootlessRedisplay(pWin);
1260            RootlessStartDrawing(pWin);
1261        } else {
1262            RL_DEBUG_MSG("movewindow border resizing ");
1263
1264            oldBW = winRec->borderWidth;
1265            oldX = winRec->x;
1266            oldY = winRec->y;
1267            oldW = winRec->width;
1268            oldH = winRec->height;
1269
1270            newBW = wBorderWidth(pWin);
1271            newX = x;
1272            newY = y;
1273            newW = pWin->drawable.width  + 2*newBW;
1274            newH = pWin->drawable.height + 2*newBW;
1275
1276            resize_after = StartFrameResize(pWin, FALSE,
1277                                            oldX, oldY, oldW, oldH, oldBW,
1278                                            newX, newY, newW, newH, newBW);
1279        }
1280    }
1281
1282    HUGE_ROOT(pWin);
1283    SCREEN_UNWRAP(pScreen, MoveWindow);
1284
1285    if (winRec) {
1286        oldCopyWindowProc = pScreen->CopyWindow;
1287        pScreen->CopyWindow = RootlessNoCopyWindow;
1288    }
1289    pScreen->MoveWindow(pWin, x, y, pSib, kind);
1290    if (winRec) {
1291        pScreen->CopyWindow = oldCopyWindowProc;
1292    }
1293
1294    NORMAL_ROOT(pWin);
1295    SCREEN_WRAP(pScreen, MoveWindow);
1296
1297    if (winRec) {
1298        if (kind == VTMove) {
1299            winRec->x = x;
1300            winRec->y = y;
1301            RootlessStopDrawing(pWin, FALSE);
1302            SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1303                                               x + SCREEN_TO_GLOBAL_X,
1304                                               y + SCREEN_TO_GLOBAL_Y);
1305        } else {
1306            FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1307                              newX, newY, newW, newH, newBW, resize_after);
1308        }
1309    }
1310
1311    RL_DEBUG_MSG("movewindow end\n");
1312}
1313
1314
1315/*
1316 * RootlessResizeWindow
1317 *  Note: (x, y, w, h) as passed to this procedure don't match the frame
1318 *  definition. (x,y) is corner of very outer edge, *outside* border.
1319 *  w,h is width and height *inside* border, *ignoring* border width.
1320 *  The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
1321 *  is total rect and (x+bw, y+bw, w, h) is inner rect.
1322 */
1323void
1324RootlessResizeWindow(WindowPtr pWin, int x, int y,
1325                     unsigned int w, unsigned int h, WindowPtr pSib)
1326{
1327    RootlessWindowRec *winRec = WINREC(pWin);
1328    ScreenPtr pScreen = pWin->drawable.pScreen;
1329    int oldX = 0, oldY = 0, newX = 0, newY = 0;
1330    unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
1331    Bool resize_after = FALSE;
1332    RegionRec saveRoot;
1333
1334    RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
1335
1336    if(pWin->parent) {
1337        if (winRec) {
1338            oldBW = winRec->borderWidth;
1339            oldX = winRec->x;
1340            oldY = winRec->y;
1341            oldW = winRec->width;
1342            oldH = winRec->height;
1343
1344            newBW = oldBW;
1345            newX = x;
1346            newY = y;
1347            newW = w + 2*newBW;
1348            newH = h + 2*newBW;
1349
1350            resize_after = StartFrameResize(pWin, TRUE,
1351                                            oldX, oldY, oldW, oldH, oldBW,
1352                                            newX, newY, newW, newH, newBW);
1353        }
1354
1355        HUGE_ROOT(pWin);
1356        SCREEN_UNWRAP(pScreen, ResizeWindow);
1357        pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
1358        SCREEN_WRAP(pScreen, ResizeWindow);
1359        NORMAL_ROOT(pWin);
1360
1361        if (winRec) {
1362            FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
1363                              newX, newY, newW, newH, newBW, resize_after);
1364        }
1365    } else {
1366        /* Special case for resizing the root window */
1367        BoxRec box;
1368
1369        pWin->drawable.x = x;
1370        pWin->drawable.y = y;
1371        pWin->drawable.width = w;
1372        pWin->drawable.height = h;
1373
1374        box.x1 = x; box.y1 = y;
1375        box.x2 = x + w; box.y2 = y + h;
1376        REGION_UNINIT(pScreen, &pWin->winSize);
1377        REGION_INIT(pScreen, &pWin->winSize, &box, 1);
1378        REGION_COPY(pScreen, &pWin->borderSize, &pWin->winSize);
1379        REGION_COPY(pScreen, &pWin->clipList, &pWin->winSize);
1380        REGION_COPY(pScreen, &pWin->borderClip, &pWin->winSize);
1381
1382        miSendExposures(pWin, &pWin->borderClip,
1383                        pWin->drawable.x, pWin->drawable.y);
1384    }
1385
1386    RL_DEBUG_MSG("resizewindow end\n");
1387}
1388
1389
1390/*
1391 * RootlessRepositionWindow
1392 *  Called by the implementation when a window needs to be repositioned to
1393 *  its correct location on the screen. This routine is typically needed
1394 *  due to changes in the underlying window system, such as a screen layout
1395 *  change.
1396 */
1397void
1398RootlessRepositionWindow(WindowPtr pWin)
1399{
1400    RootlessWindowRec *winRec = WINREC(pWin);
1401    ScreenPtr pScreen = pWin->drawable.pScreen;
1402
1403    if (winRec == NULL)
1404        return;
1405
1406    RootlessStopDrawing(pWin, FALSE);
1407    SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1408                                       winRec->x + SCREEN_TO_GLOBAL_X,
1409                                       winRec->y + SCREEN_TO_GLOBAL_Y);
1410
1411    RootlessReorderWindow(pWin);
1412}
1413
1414
1415/*
1416 * RootlessReparentWindow
1417 *  Called after a window has been reparented. Generally windows are not
1418 *  framed until they are mapped. However, a window may be framed early by the
1419 *  implementation calling RootlessFrameForWindow. (e.g. this could be needed
1420 *  to attach a VRAM surface to it.) If the window is subsequently reparented
1421 *  by the window manager before being mapped, we need to give the frame to
1422 *  the new top-level window.
1423 */
1424void
1425RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
1426{
1427    ScreenPtr pScreen = pWin->drawable.pScreen;
1428    RootlessWindowRec *winRec = WINREC(pWin);
1429    WindowPtr pTopWin;
1430
1431    /* Check that window is not top-level now, but used to be. */
1432    if (IsRoot(pWin) || IsRoot(pWin->parent)
1433        || IsTopLevel(pWin) || winRec == NULL)
1434    {
1435        goto out;
1436    }
1437
1438    /* If the formerly top-level window has a frame, we want to give the
1439       frame to its new top-level parent. If we can't do that, we'll just
1440       have to jettison it... */
1441
1442    pTopWin = TopLevelParent(pWin);
1443    assert(pTopWin != pWin);
1444
1445    pWin->rootlessUnhittable = FALSE;
1446
1447    DeleteProperty (serverClient, pWin, xa_native_window_id ());
1448
1449    if (WINREC(pTopWin) != NULL) {
1450        /* We're screwed. */
1451        RootlessDestroyFrame(pWin, winRec);
1452    } else {
1453        if (!pTopWin->realized && pWin->realized) {
1454            SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
1455        }
1456
1457        /* Switch the frame record from one to the other. */
1458
1459        SETWINREC(pWin, NULL);
1460        SETWINREC(pTopWin, winRec);
1461
1462        RootlessInitializeFrame(pTopWin, winRec);
1463        RootlessReshapeFrame(pTopWin);
1464
1465        SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1466                                             winRec->x + SCREEN_TO_GLOBAL_X,
1467                                             winRec->y + SCREEN_TO_GLOBAL_Y,
1468                                             winRec->width, winRec->height,
1469                                             RL_GRAVITY_NONE);
1470
1471        if (SCREENREC(pScreen)->imp->SwitchWindow) {
1472            SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
1473        }
1474
1475        if (pTopWin->realized && !pWin->realized)
1476            winRec->is_reorder_pending = TRUE;
1477    }
1478
1479out:
1480    if (SCREENREC(pScreen)->ReparentWindow) {
1481        SCREEN_UNWRAP(pScreen, ReparentWindow);
1482        pScreen->ReparentWindow(pWin, pPriorParent);
1483        SCREEN_WRAP(pScreen, ReparentWindow);
1484    }
1485}
1486
1487
1488void
1489RootlessFlushWindowColormap (WindowPtr pWin)
1490{
1491  RootlessWindowRec *winRec = WINREC (pWin);
1492  xp_window_changes wc;
1493
1494  if (winRec == NULL)
1495    return;
1496
1497  RootlessStopDrawing (pWin, FALSE);
1498
1499  /* This is how we tell xp that the colormap may have changed. */
1500
1501  wc.colormap = RootlessColormapCallback;
1502  wc.colormap_data = pWin->drawable.pScreen;
1503
1504  configure_window (MAKE_WINDOW_ID(winRec->wid), XP_COLORMAP, &wc);
1505}
1506
1507/*
1508 * RootlessChangeBorderWidth
1509 *  FIXME: untested!
1510 *  pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1511 *  Frame moves and resizes.
1512 */
1513void
1514RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
1515{
1516    RegionRec saveRoot;
1517    Bool resize_after = FALSE;
1518
1519    RL_DEBUG_MSG("change border width ");
1520
1521    if (width != wBorderWidth(pWin)) {
1522        RootlessWindowRec *winRec = WINREC(pWin);
1523        int oldX = 0, oldY = 0, newX = 0, newY = 0;
1524        unsigned int oldW = 0, oldH = 0, oldBW = 0;
1525        unsigned int newW = 0, newH = 0, newBW = 0;
1526
1527        if (winRec) {
1528            oldBW = winRec->borderWidth;
1529            oldX = winRec->x;
1530            oldY = winRec->y;
1531            oldW = winRec->width;
1532            oldH = winRec->height;
1533
1534            newBW = width;
1535            newX = pWin->drawable.x - newBW;
1536            newY = pWin->drawable.y - newBW;
1537            newW = pWin->drawable.width  + 2*newBW;
1538            newH = pWin->drawable.height + 2*newBW;
1539
1540            resize_after = StartFrameResize(pWin, FALSE,
1541                                            oldX, oldY, oldW, oldH, oldBW,
1542                                            newX, newY, newW, newH, newBW);
1543        }
1544
1545        HUGE_ROOT(pWin);
1546        SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1547        pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
1548        SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1549        NORMAL_ROOT(pWin);
1550
1551        if (winRec) {
1552            FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1553                              newX, newY, newW, newH, newBW, resize_after);
1554        }
1555    }
1556
1557    RL_DEBUG_MSG("change border width end\n");
1558}
1559
1560/*
1561 * RootlessOrderAllWindows
1562 * Brings all X11 windows to the top of the window stack
1563 * (i.e in front of Aqua windows) -- called when X11.app is given focus
1564 */
1565void
1566RootlessOrderAllWindows (void)
1567{
1568    int i;
1569    WindowPtr pWin;
1570
1571    if (windows_hidden)
1572        return;
1573
1574    RL_DEBUG_MSG("RootlessOrderAllWindows() ");
1575    for (i = 0; i < screenInfo.numScreens; i++) {
1576      if (screenInfo.screens[i] == NULL) continue;
1577      pWin = WindowTable[i];
1578      if (pWin == NULL) continue;
1579
1580      for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1581	if (!pWin->realized) continue;
1582	if (RootlessEnsureFrame(pWin) == NULL) continue;
1583	RootlessReorderWindow (pWin);
1584      }
1585    }
1586    RL_DEBUG_MSG("RootlessOrderAllWindows() done");
1587}
1588
1589void
1590RootlessEnableRoot (ScreenPtr pScreen)
1591{
1592    WindowPtr pRoot;
1593    pRoot = WindowTable[pScreen->myNum];
1594
1595    RootlessEnsureFrame (pRoot);
1596    (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
1597    RootlessReorderWindow (pRoot);
1598}
1599
1600void
1601RootlessDisableRoot (ScreenPtr pScreen)
1602{
1603    WindowPtr pRoot;
1604    RootlessWindowRec *winRec;
1605
1606    pRoot = WindowTable[pScreen->myNum];
1607    winRec = WINREC (pRoot);
1608
1609    if (NULL == winRec)
1610	return;
1611
1612    RootlessDestroyFrame (pRoot, winRec);
1613    /*
1614     * gstaplin: I fixed the usage of this DeleteProperty so that it would compile.
1615     * QUESTION: Where is this xa_native_window_id set?
1616     */
1617    DeleteProperty (serverClient, pRoot, xa_native_window_id ());
1618}
1619
1620void
1621RootlessHideAllWindows (void)
1622{
1623    int i;
1624    ScreenPtr pScreen;
1625    WindowPtr pWin;
1626    RootlessWindowRec *winRec;
1627    xp_window_changes wc;
1628
1629    if (windows_hidden)
1630        return;
1631
1632    windows_hidden = TRUE;
1633
1634    for (i = 0; i < screenInfo.numScreens; i++)
1635    {
1636        pScreen = screenInfo.screens[i];
1637        pWin = WindowTable[i];
1638        if (pScreen == NULL || pWin == NULL)
1639            continue;
1640
1641        for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib)
1642        {
1643            if (!pWin->realized)
1644                continue;
1645
1646            RootlessStopDrawing (pWin, FALSE);
1647
1648            winRec = WINREC (pWin);
1649            if (winRec != NULL)
1650            {
1651                wc.stack_mode = XP_UNMAPPED;
1652                wc.sibling = 0;
1653                configure_window (MAKE_WINDOW_ID(winRec->wid), XP_STACKING, &wc);
1654            }
1655        }
1656    }
1657}
1658
1659void
1660RootlessShowAllWindows (void)
1661{
1662    int i;
1663    ScreenPtr pScreen;
1664    WindowPtr pWin;
1665    RootlessWindowRec *winRec;
1666
1667    if (!windows_hidden)
1668        return;
1669
1670    windows_hidden = FALSE;
1671
1672    for (i = 0; i < screenInfo.numScreens; i++)
1673    {
1674        pScreen = screenInfo.screens[i];
1675        pWin = WindowTable[i];
1676        if (pScreen == NULL || pWin == NULL)
1677            continue;
1678
1679        for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib)
1680        {
1681            if (!pWin->realized)
1682                continue;
1683
1684            winRec = RootlessEnsureFrame (pWin);
1685            if (winRec == NULL)
1686                continue;
1687
1688            RootlessReorderWindow (pWin);
1689        }
1690
1691        RootlessScreenExpose (pScreen);
1692    }
1693}
1694