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