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