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