Imported Upstream version 1.15.1
[deb_xorg-server.git] / miext / rootless / rootlessWindow.c
CommitLineData
a09e091a
JB
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->rootlessUnhittable = 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 dont get restacked
565 * relative to onscreen ones (but that the offscreen ones maintain
566 * their stacking order if they are explicitly asked to Reorder
567 */
568
569 newPrevW = pWin->prevSib;
570 while (newPrevW &&
571 (WINREC(newPrevW) == NULL || !newPrevW->realized ||
572 newPrevW->rootlessUnhittable != pWin->rootlessUnhittable))
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 pointer 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 * 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 RootlessWindowRec *winRec;
755 WindowPtr top;
756
757 top = TopLevelParent(pWin);
758 if (top == NULL) {
759 RL_DEBUG_MSG("no parent\n");
760 goto out;
761 }
762
763 winRec = WINREC(top);
764 if (winRec == NULL) {
765 RL_DEBUG_MSG("not framed\n");
766 goto out;
767 }
768
769 /* Move region to window local coords */
770 RegionTranslate(&rgnDst, -winRec->x, -winRec->y);
771
772 RootlessStopDrawing(pWin, FALSE);
773
774 SCREENREC(pScreen)->imp->CopyWindow(winRec->wid,
775 RegionNumRects(&rgnDst),
776 RegionRects(&rgnDst), dx, dy);
777 }
778 else {
779 RootlessStartDrawing(pWin);
780
781 miCopyRegion((DrawablePtr) pWin, (DrawablePtr) pWin,
782 0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
783
784 /* prgnSrc has been translated to dst position */
785 RootlessDamageRegion(pWin, prgnSrc);
786 }
787
788 out:
789 RegionUninit(&rgnDst);
790 fbValidateDrawable(&pWin->drawable);
791
792 SCREEN_WRAP(pScreen, CopyWindow);
793
794 RL_DEBUG_MSG("copywindowFB end\n");
795}
796
797/*
798 * Window resize procedures
799 */
800
801enum {
802 WIDTH_SMALLER = 1,
803 HEIGHT_SMALLER = 2,
804};
805
806/*
807 * ResizeWeighting
808 * Choose gravity to avoid local copies. Do that by looking for
809 * a corner that doesn't move _relative to the screen_.
810 */
811static inline unsigned int
812ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
813 int newX1, int newY1, int newX2, int newY2, int newBW)
814{
815#ifdef ROOTLESS_RESIZE_GRAVITY
816 if (newBW != oldBW)
817 return RL_GRAVITY_NONE;
818
819 if (newX1 == oldX1 && newY1 == oldY1)
820 return RL_GRAVITY_NORTH_WEST;
821 else if (newX1 == oldX1 && newY2 == oldY2)
822 return RL_GRAVITY_SOUTH_WEST;
823 else if (newX2 == oldX2 && newY2 == oldY2)
824 return RL_GRAVITY_SOUTH_EAST;
825 else if (newX2 == oldX2 && newY1 == oldY1)
826 return RL_GRAVITY_NORTH_EAST;
827 else
828 return RL_GRAVITY_NONE;
829#else
830 return RL_GRAVITY_NONE;
831#endif
832}
833
834/*
835 * StartFrameResize
836 * Prepare to resize a top-level window. The old window's pixels are
837 * saved and the implementation is told to change the window size.
838 * (x,y,w,h) is outer frame of window (outside border)
839 */
840static Bool
841StartFrameResize(WindowPtr pWin, Bool gravity,
842 int oldX, int oldY, int oldW, int oldH, int oldBW,
843 int newX, int newY, int newW, int newH, int newBW)
844{
845 ScreenPtr pScreen = pWin->drawable.pScreen;
846 RootlessWindowRec *winRec = WINREC(pWin);
847 Bool need_window_source = FALSE, resize_after = FALSE;
848
849 BoxRec rect;
850 int oldX2, newX2;
851 int oldY2, newY2;
852 unsigned int weight;
853
854 oldX2 = oldX + oldW, newX2 = newX + newW;
855 oldY2 = oldY + oldH, newY2 = newY + newH;
856
857 /* Decide which resize weighting to use */
858 weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
859 newX, newY, newW, newH, newBW);
860
861 /* Compute intersection between old and new rects */
862 rect.x1 = max(oldX, newX);
863 rect.y1 = max(oldY, newY);
864 rect.x2 = min(oldX2, newX2);
865 rect.y2 = min(oldY2, newY2);
866
867 RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
868 RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n",
869 oldX, oldY, oldW, oldH, oldBW, newX, newY, newW, newH, newBW);
870
871 RootlessRedisplay(pWin);
872
873 /* If gravity is true, then we need to have a way of recovering all
874 the original bits in the window for when X rearranges the contents
875 based on the various gravity settings. The obvious way is to just
876 snapshot the entire backing store before resizing it, but that
877 it slow on large windows.
878
879 So the optimization here is to use the implementation's resize
880 weighting options (if available) to allow us to reason about what
881 is left in the backing store after the resize. We can then only
882 copy what won't be there after the resize, and do a two-stage copy
883 operation.
884
885 Most of these optimizations are only applied when the top-left
886 corner of the window is fixed, since that's the common case. They
887 could probably be extended with some thought. */
888
889 gResizeDeathCount = 0;
890
891 if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
892 unsigned int code = 0;
893
894 /* Top left corner is anchored. We never need to copy the
895 entire window. */
896
897 need_window_source = TRUE;
898
899 /* These comparisons were chosen to avoid setting bits when the sizes
900 are the same. (So the fastest case automatically gets taken when
901 dimensions are unchanging.) */
902
903 if (newW < oldW)
904 code |= WIDTH_SMALLER;
905 if (newH < oldH)
906 code |= HEIGHT_SMALLER;
907
908 if (((code ^ (code >> 1)) & 1) == 0) {
909 /* Both dimensions are either getting larger, or both
910 are getting smaller. No need to copy anything. */
911
912 if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
913 /* Since the window is getting smaller, we can do gravity
914 repair on it with it's current size, then resize it
915 afterwards. */
916
917 resize_after = TRUE;
918 }
919
920 gResizeDeathCount = 1;
921 }
922 else {
923 unsigned int copy_rowbytes, Bpp;
924 unsigned int copy_rect_width, copy_rect_height;
925 BoxRec copy_rect;
926
927 /* We can get away with a partial copy. 'rect' is the
928 intersection between old and new bounds, so copy
929 everything to the right of or below the intersection. */
930
931 RootlessStartDrawing(pWin);
932
933 if (code == WIDTH_SMALLER) {
934 copy_rect.x1 = rect.x2;
935 copy_rect.y1 = rect.y1;
936 copy_rect.x2 = oldX2;
937 copy_rect.y2 = oldY2;
938 }
939 else if (code == HEIGHT_SMALLER) {
940 copy_rect.x1 = rect.x1;
941 copy_rect.y1 = rect.y2;
942 copy_rect.x2 = oldX2;
943 copy_rect.y2 = oldY2;
944 }
945 else
946 OsAbort();
947
948 Bpp = winRec->win->drawable.bitsPerPixel / 8;
949 copy_rect_width = copy_rect.x2 - copy_rect.x1;
950 copy_rect_height = copy_rect.y2 - copy_rect.y1;
951 copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
952 gResizeDeathBits = malloc(copy_rowbytes * copy_rect_height);
953
954 if (copy_rect_width * copy_rect_height >
955 rootless_CopyBytes_threshold &&
956 SCREENREC(pScreen)->imp->CopyBytes) {
957 SCREENREC(pScreen)->imp->CopyBytes(copy_rect_width * Bpp,
958 copy_rect_height,
959 ((char *) winRec->pixelData)
960 +
961 ((copy_rect.y1 -
962 oldY) *
963 winRec->bytesPerRow)
964 + (copy_rect.x1 -
965 oldX) * Bpp,
966 winRec->bytesPerRow,
967 gResizeDeathBits,
968 copy_rowbytes);
969 }
970 else {
971 fbBlt((FbBits *) (winRec->pixelData
972 +
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, copy_rect_width * Bpp,
978 copy_rect_height, GXcopy, FB_ALLONES, Bpp, 0, 0);
979 }
980
981 gResizeDeathBounds[1] = copy_rect;
982 gResizeDeathPix[1]
983 = GetScratchPixmapHeader(pScreen, copy_rect_width,
984 copy_rect_height,
985 winRec->win->drawable.depth,
986 winRec->win->drawable.bitsPerPixel,
987 winRec->bytesPerRow,
988 (void *) gResizeDeathBits);
989
990 SetPixmapBaseToScreen(gResizeDeathPix[1],
991 copy_rect.x1, copy_rect.y1);
992
993 gResizeDeathCount = 2;
994 }
995 }
996 else if (gravity) {
997 /* The general case. Just copy everything. */
998
999 RootlessStartDrawing(pWin);
1000
1001 gResizeDeathBits = malloc(winRec->bytesPerRow * winRec->height);
1002
1003 memcpy(gResizeDeathBits, winRec->pixelData,
1004 winRec->bytesPerRow * winRec->height);
1005
1006 gResizeDeathBounds[0] = (BoxRec) {
1007 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) {
1045 oldX, oldY, oldX2, oldY2};
1046 gResizeDeathPix[0]
1047 = GetScratchPixmapHeader(pScreen, oldW, oldH,
1048 winRec->win->drawable.depth,
1049 winRec->win->drawable.bitsPerPixel,
1050 winRec->bytesPerRow, winRec->pixelData);
1051
1052 SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1053 }
1054
1055 /* Use custom CopyWindow when moving gravity bits around
1056 ResizeWindow assumes the old window contents are in the same
1057 pixmap, but here they're in deathPix instead. */
1058
1059 if (gravity) {
1060 gResizeOldCopyWindowProc = pScreen->CopyWindow;
1061 pScreen->CopyWindow = RootlessResizeCopyWindow;
1062 }
1063
1064 /* If we can't rely on the window server preserving the bits we
1065 need in the position we need, copy the pixels in the
1066 intersection from src to dst. ResizeWindow assumes these pixels
1067 are already present when making gravity adjustments. pWin
1068 currently has new-sized pixmap but is in old position.
1069
1070 FIXME: border width change! (?) */
1071
1072 if (gravity && weight == RL_GRAVITY_NONE) {
1073 PixmapPtr src, dst;
1074
1075 assert(gResizeDeathCount == 1);
1076
1077 src = gResizeDeathPix[0];
1078 dst = pScreen->GetWindowPixmap(pWin);
1079
1080 RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1081 rect.x1, rect.y1, rect.x2, rect.y2);
1082
1083 /* rect is the intersection of the old location and new location */
1084 if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
1085 /* The window drawable still has the old frame position, which
1086 means that DST doesn't actually point at the origin of our
1087 physical backing store when adjusted by the drawable.x,y
1088 position. So sneakily adjust it temporarily while copying.. */
1089
1090 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1091 SetPixmapBaseToScreen(dst, newX, newY);
1092
1093 fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1094 &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1095
1096 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1097 SetPixmapBaseToScreen(dst, oldX, oldY);
1098 }
1099 }
1100
1101 return resize_after;
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 * RootlessMoveWindow
1153 * If kind==VTOther, window border is resizing (and borderWidth is
1154 * already changed!!@#$) This case works like window resize, not move.
1155 */
1156void
1157RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1158{
1159 RootlessWindowRec *winRec = WINREC(pWin);
1160 ScreenPtr pScreen = pWin->drawable.pScreen;
1161 CopyWindowProcPtr oldCopyWindowProc = NULL;
1162 int oldX = 0, oldY = 0, newX = 0, newY = 0;
1163 unsigned int oldW = 0, oldH = 0, oldBW = 0;
1164 unsigned int newW = 0, newH = 0, newBW = 0;
1165 Bool resize_after = FALSE;
1166 RegionRec saveRoot;
1167
1168 RL_DEBUG_MSG("movewindow start \n");
1169
1170 if (winRec) {
1171 if (kind == VTMove) {
1172 oldX = winRec->x;
1173 oldY = winRec->y;
1174 RootlessRedisplay(pWin);
1175 RootlessStartDrawing(pWin);
1176 }
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 }
1222 else {
1223 FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1224 newX, newY, newW, newH, newBW, resize_after);
1225 }
1226 }
1227
1228 RL_DEBUG_MSG("movewindow end\n");
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 }
1282 else {
1283 /* Special case for resizing the root window */
1284 BoxRec box;
1285
1286 pWin->drawable.x = x;
1287 pWin->drawable.y = y;
1288 pWin->drawable.width = w;
1289 pWin->drawable.height = h;
1290
1291 box.x1 = x;
1292 box.y1 = y;
1293 box.x2 = x + w;
1294 box.y2 = y + h;
1295 RegionUninit(&pWin->winSize);
1296 RegionInit(&pWin->winSize, &box, 1);
1297 RegionCopy(&pWin->borderSize, &pWin->winSize);
1298 RegionCopy(&pWin->clipList, &pWin->winSize);
1299 RegionCopy(&pWin->borderClip, &pWin->winSize);
1300
1301 if (winRec) {
1302 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1303 x + SCREEN_TO_GLOBAL_X,
1304 y + SCREEN_TO_GLOBAL_Y,
1305 w, h, RL_GRAVITY_NONE);
1306 }
1307
1308 miSendExposures(pWin, &pWin->borderClip,
1309 pWin->drawable.x, pWin->drawable.y);
1310 }
1311
1312 RL_DEBUG_MSG("resizewindow end\n");
1313}
1314
1315/*
1316 * RootlessRepositionWindow
1317 * Called by the implementation when a window needs to be repositioned to
1318 * its correct location on the screen. This routine is typically needed
1319 * due to changes in the underlying window system, such as a screen layout
1320 * change.
1321 */
1322void
1323RootlessRepositionWindow(WindowPtr pWin)
1324{
1325 RootlessWindowRec *winRec = WINREC(pWin);
1326 ScreenPtr pScreen = pWin->drawable.pScreen;
1327
1328 if (winRec == NULL)
1329 return;
1330
1331 RootlessStopDrawing(pWin, FALSE);
1332 SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1333 winRec->x + SCREEN_TO_GLOBAL_X,
1334 winRec->y + SCREEN_TO_GLOBAL_Y);
1335
1336 RootlessReorderWindow(pWin);
1337}
1338
1339/*
1340 * RootlessReparentWindow
1341 * Called after a window has been reparented. Generally windows are not
1342 * framed until they are mapped. However, a window may be framed early by the
1343 * implementation calling RootlessFrameForWindow. (e.g. this could be needed
1344 * to attach a VRAM surface to it.) If the window is subsequently reparented
1345 * by the window manager before being mapped, we need to give the frame to
1346 * the new top-level window.
1347 */
1348void
1349RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
1350{
1351 ScreenPtr pScreen = pWin->drawable.pScreen;
1352 RootlessWindowRec *winRec = WINREC(pWin);
1353 WindowPtr pTopWin;
1354
1355 /* Check that window is not top-level now, but used to be. */
1356 if (IsRoot(pWin) || IsRoot(pWin->parent)
1357 || IsTopLevel(pWin) || winRec == NULL) {
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 }
1376 else {
1377 if (!pTopWin->realized && pWin->realized) {
1378 SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
1379 }
1380
1381 /* Switch the frame record from one to the other. */
1382
1383 SETWINREC(pWin, NULL);
1384 SETWINREC(pTopWin, winRec);
1385
1386 RootlessInitializeFrame(pTopWin, winRec);
1387 RootlessReshapeFrame(pTopWin);
1388
1389 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1390 winRec->x + SCREEN_TO_GLOBAL_X,
1391 winRec->y + SCREEN_TO_GLOBAL_Y,
1392 winRec->width, winRec->height,
1393 RL_GRAVITY_NONE);
1394
1395 if (SCREENREC(pScreen)->imp->SwitchWindow) {
1396 SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
1397 }
1398
1399 if (pTopWin->realized && !pWin->realized)
1400 winRec->is_reorder_pending = TRUE;
1401 }
1402
1403 out:
1404 if (SCREENREC(pScreen)->ReparentWindow) {
1405 SCREEN_UNWRAP(pScreen, ReparentWindow);
1406 pScreen->ReparentWindow(pWin, pPriorParent);
1407 SCREEN_WRAP(pScreen, ReparentWindow);
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)
1496 continue;
1497 pWin = screenInfo.screens[i]->root;
1498 if (pWin == NULL)
1499 continue;
1500
1501 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1502 if (!pWin->realized)
1503 continue;
1504 if (RootlessEnsureFrame(pWin) == NULL)
1505 continue;
1506 if (!include_unhitable && pWin->rootlessUnhittable)
1507 continue;
1508 RootlessReorderWindow(pWin);
1509 }
1510 }
1511 RL_DEBUG_MSG("RootlessOrderAllWindows() done");
1512}
1513
1514void
1515RootlessEnableRoot(ScreenPtr pScreen)
1516{
1517 WindowPtr pRoot;
1518
1519 pRoot = pScreen->root;
1520
1521 RootlessEnsureFrame(pRoot);
1522 (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
1523 RootlessReorderWindow(pRoot);
1524}
1525
1526void
1527RootlessDisableRoot(ScreenPtr pScreen)
1528{
1529 WindowPtr pRoot;
1530 RootlessWindowRec *winRec;
1531
1532 pRoot = pScreen->root;
1533 winRec = WINREC(pRoot);
1534
1535 if (NULL == winRec)
1536 return;
1537
1538 RootlessDestroyFrame(pRoot, winRec);
1539 DeleteProperty(serverClient, pRoot, xa_native_window_id());
1540}
1541
1542void
1543RootlessHideAllWindows(void)
1544{
1545 int i;
1546 ScreenPtr pScreen;
1547 WindowPtr pWin;
1548 RootlessWindowRec *winRec;
1549
1550 if (windows_hidden)
1551 return;
1552
1553 windows_hidden = TRUE;
1554
1555 for (i = 0; i < screenInfo.numScreens; i++) {
1556 pScreen = screenInfo.screens[i];
1557 if (pScreen == NULL)
1558 continue;
1559 pWin = pScreen->root;
1560 if (pWin == NULL)
1561 continue;
1562
1563 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1564 if (!pWin->realized)
1565 continue;
1566
1567 RootlessStopDrawing(pWin, FALSE);
1568
1569 winRec = WINREC(pWin);
1570 if (winRec != NULL) {
1571 if (SCREENREC(pScreen)->imp->HideWindow)
1572 SCREENREC(pScreen)->imp->HideWindow(winRec->wid);
1573 }
1574 }
1575 }
1576}
1577
1578void
1579RootlessShowAllWindows(void)
1580{
1581 int i;
1582 ScreenPtr pScreen;
1583 WindowPtr pWin;
1584 RootlessWindowRec *winRec;
1585
1586 if (!windows_hidden)
1587 return;
1588
1589 windows_hidden = FALSE;
1590
1591 for (i = 0; i < screenInfo.numScreens; i++) {
1592 pScreen = screenInfo.screens[i];
1593 if (pScreen == NULL)
1594 continue;
1595 pWin = pScreen->root;
1596 if (pWin == NULL)
1597 continue;
1598
1599 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1600 if (!pWin->realized)
1601 continue;
1602
1603 winRec = RootlessEnsureFrame(pWin);
1604 if (winRec == NULL)
1605 continue;
1606
1607 RootlessReorderWindow(pWin);
1608 }
1609
1610 RootlessScreenExpose(pScreen);
1611 }
1612}
1613
1614/*
1615 * SetPixmapOfAncestors
1616 * Set the Pixmaps on all ParentRelative windows up the ancestor chain.
1617 */
1618void
1619RootlessSetPixmapOfAncestors(WindowPtr pWin)
1620{
1621 ScreenPtr pScreen = pWin->drawable.pScreen;
1622 WindowPtr topWin = TopLevelParent(pWin);
1623 RootlessWindowRec *topWinRec = WINREC(topWin);
1624
1625 while (pWin->backgroundState == ParentRelative) {
1626 if (pWin == topWin) {
1627 // disallow ParentRelative background state on top level
1628 XID pixel = 0;
1629
1630 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
1631 RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
1632 break;
1633 }
1634
1635 pWin = pWin->parent;
1636 pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
1637 }
1638}