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>
46 extern int darwinMainScreenX, darwinMainScreenY;
47 extern 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
70 DEFINE_ATOM_HELPER(xa_native_window_id, "_NATIVE_WINDOW_ID")
71
72 static 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
81 void
RootlessNativeWindowStateChanged(WindowPtr pWin,unsigned int state)82 RootlessNativeWindowStateChanged(WindowPtr pWin, unsigned int state)
83 {
84 RootlessWindowRec *winRec;
85
86 if (pWin == NULL)
87 return;
88
89 winRec = WINREC(pWin);
90 if (winRec == NULL)
91 return;
92
93 winRec->is_offscreen = ((state & XP_WINDOW_STATE_OFFSCREEN) != 0);
94 winRec->is_obscured = ((state & XP_WINDOW_STATE_OBSCURED) != 0);
95 pWin->unhittable = winRec->is_offscreen;
96 }
97
98 void
RootlessNativeWindowMoved(WindowPtr pWin)99 RootlessNativeWindowMoved(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 */
147 Bool
RootlessCreateWindow(WindowPtr pWin)148 RootlessCreateWindow(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 */
182 static void
RootlessDestroyFrame(WindowPtr pWin,RootlessWindowPtr winRec)183 RootlessDestroyFrame(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 */
194 Bool
RootlessDestroyWindow(WindowPtr pWin)195 RootlessDestroyWindow(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
211 static Bool
RootlessGetShape(WindowPtr pWin,RegionPtr pShape)212 RootlessGetShape(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 */
231 static void
RootlessReshapeFrame(WindowPtr pWin)232 RootlessReshapeFrame(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 */
274 void
RootlessSetShape(WindowPtr pWin,int kind)275 RootlessSetShape(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 */
289 Bool
RootlessChangeWindowAttributes(WindowPtr pWin,unsigned long vmask)290 RootlessChangeWindowAttributes(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 */
321 Bool
RootlessPositionWindow(WindowPtr pWin,int x,int y)322 RootlessPositionWindow(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 */
354 static void
RootlessInitializeFrame(WindowPtr pWin,RootlessWindowRec * winRec)355 RootlessInitializeFrame(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 */
375 static RootlessWindowRec *
RootlessEnsureFrame(WindowPtr pWin)376 RootlessEnsureFrame(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 */
437 Bool
RootlessRealizeWindow(WindowPtr pWin)438 RootlessRealizeWindow(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 */
483 RootlessFrameID
RootlessFrameForWindow(WindowPtr pWin,Bool create)484 RootlessFrameForWindow(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 */
509 Bool
RootlessUnrealizeWindow(WindowPtr pWin)510 RootlessUnrealizeWindow(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 */
539 void
RootlessReorderWindow(WindowPtr pWin)540 RootlessReorderWindow(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->unhittable != pWin->unhittable))
573 newPrevW = newPrevW->prevSib;
574
575 newPrev = newPrevW != NULL ? WINREC(newPrevW) : NULL;
576 newPrevID = newPrev != NULL ? newPrev->wid : 0;
577
578 /* If it exists, reorder the frame above us first. */
579
580 if (newPrev && newPrev->is_reorder_pending) {
581 newPrev->is_reorder_pending = FALSE;
582 RootlessReorderWindow(newPrevW);
583 }
584
585 SCREENREC(pScreen)->imp->RestackFrame(winRec->wid, newPrevID);
586 }
587 }
588
589 /*
590 * RootlessRestackWindow
591 * This is a hook for when DIX changes the window stacking order.
592 * The window has already been inserted into its new position in the
593 * DIX window stack. We need to change the order of the physical
594 * window to match.
595 */
596 void
RootlessRestackWindow(WindowPtr pWin,WindowPtr pOldNextSib)597 RootlessRestackWindow(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.
628 static void *gResizeDeathBits = NULL;
629 static int gResizeDeathCount = 0;
630 static PixmapPtr gResizeDeathPix[2] = { NULL, NULL };
631
632 static BoxRec gResizeDeathBounds[2];
633 static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
634
635 /*
636 * RootlessNoCopyWindow
637 * CopyWindow() that doesn't do anything. For MoveWindow() of
638 * top-level windows.
639 */
640 static void
RootlessNoCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)641 RootlessNoCopyWindow(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 */
659 static void
RootlessResizeCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)660 RootlessResizeCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg,
661 RegionPtr prgnSrc)
662 {
663 ScreenPtr pScreen = pWin->drawable.pScreen;
664 RegionRec rgnDst;
665 int dx, dy;
666
667 RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x) ", pWin);
668
669 /* Don't unwrap pScreen->CopyWindow.
670 The bogus rewrap with RootlessCopyWindow causes a crash if
671 CopyWindow is called again during the same resize. */
672
673 if (gResizeDeathCount == 0)
674 return;
675
676 RootlessStartDrawing(pWin);
677
678 dx = ptOldOrg.x - pWin->drawable.x;
679 dy = ptOldOrg.y - pWin->drawable.y;
680 RegionTranslate(prgnSrc, -dx, -dy);
681 RegionNull(&rgnDst);
682 RegionIntersect(&rgnDst, &pWin->borderClip, prgnSrc);
683
684 if (gResizeDeathCount == 1) {
685 /* Simple case, we only have a single source pixmap. */
686
687 miCopyRegion(&gResizeDeathPix[0]->drawable,
688 &pScreen->GetWindowPixmap(pWin)->drawable, 0,
689 &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
690 }
691 else {
692 int i;
693 RegionRec clip, clipped;
694
695 /* More complex case, N source pixmaps (usually two). So we
696 intersect the destination with each source and copy those bits. */
697
698 for (i = 0; i < gResizeDeathCount; i++) {
699 RegionInit(&clip, gResizeDeathBounds + 0, 1);
700 RegionNull(&clipped);
701 RegionIntersect(&rgnDst, &clip, &clipped);
702
703 miCopyRegion(&gResizeDeathPix[i]->drawable,
704 &pScreen->GetWindowPixmap(pWin)->drawable, 0,
705 &clipped, dx, dy, fbCopyWindowProc, 0, 0);
706
707 RegionUninit(&clipped);
708 RegionUninit(&clip);
709 }
710 }
711
712 /* Don't update - resize will update everything */
713 RegionUninit(&rgnDst);
714
715 fbValidateDrawable(&pWin->drawable);
716
717 RL_DEBUG_MSG("resizecopywindowFB end\n");
718 }
719
720 /*
721 * RootlessCopyWindow
722 * Update *new* location of window. Old location is redrawn with
723 * PaintWindow. Cloned from fbCopyWindow.
724 * The original always draws on the root pixmap, which we don't have.
725 * Instead, draw on the parent window's pixmap.
726 */
727 void
RootlessCopyWindow(WindowPtr pWin,DDXPointRec ptOldOrg,RegionPtr prgnSrc)728 RootlessCopyWindow(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 void
RootlessPaintWindow(WindowPtr pWin,RegionPtr prgn,int what)798 RootlessPaintWindow(WindowPtr pWin, RegionPtr prgn, int what)
799 {
800 ScreenPtr pScreen = pWin->drawable.pScreen;
801
802 if (IsFramedWindow(pWin)) {
803 RootlessStartDrawing(pWin);
804 RootlessDamageRegion(pWin, prgn);
805
806 if (pWin->backgroundState == ParentRelative) {
807 if ((what == PW_BACKGROUND) ||
808 (what == PW_BORDER && !pWin->borderIsPixel))
809 RootlessSetPixmapOfAncestors(pWin);
810 }
811 }
812
813 SCREEN_UNWRAP(pScreen, PaintWindow);
814 pScreen->PaintWindow(pWin, prgn, what);
815 SCREEN_WRAP(pScreen, PaintWindow);
816 }
817
818 /*
819 * Window resize procedures
820 */
821
822 enum {
823 WIDTH_SMALLER = 1,
824 HEIGHT_SMALLER = 2,
825 };
826
827 /*
828 * ResizeWeighting
829 * Choose gravity to avoid local copies. Do that by looking for
830 * a corner that doesn't move _relative to the screen_.
831 */
832 static inline unsigned int
ResizeWeighting(int oldX1,int oldY1,int oldX2,int oldY2,int oldBW,int newX1,int newY1,int newX2,int newY2,int newBW)833 ResizeWeighting(int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
834 int newX1, int newY1, int newX2, int newY2, int newBW)
835 {
836 #ifdef ROOTLESS_RESIZE_GRAVITY
837 if (newBW != oldBW)
838 return RL_GRAVITY_NONE;
839
840 if (newX1 == oldX1 && newY1 == oldY1)
841 return RL_GRAVITY_NORTH_WEST;
842 else if (newX1 == oldX1 && newY2 == oldY2)
843 return RL_GRAVITY_SOUTH_WEST;
844 else if (newX2 == oldX2 && newY2 == oldY2)
845 return RL_GRAVITY_SOUTH_EAST;
846 else if (newX2 == oldX2 && newY1 == oldY1)
847 return RL_GRAVITY_NORTH_EAST;
848 else
849 return RL_GRAVITY_NONE;
850 #else
851 return RL_GRAVITY_NONE;
852 #endif
853 }
854
855 /*
856 * StartFrameResize
857 * Prepare to resize a top-level window. The old window's pixels are
858 * saved and the implementation is told to change the window size.
859 * (x,y,w,h) is outer frame of window (outside border)
860 */
861 static Bool
StartFrameResize(WindowPtr pWin,Bool gravity,int oldX,int oldY,int oldW,int oldH,int oldBW,int newX,int newY,int newW,int newH,int newBW)862 StartFrameResize(WindowPtr pWin, Bool gravity,
863 int oldX, int oldY, int oldW, int oldH, int oldBW,
864 int newX, int newY, int newW, int newH, int newBW)
865 {
866 ScreenPtr pScreen = pWin->drawable.pScreen;
867 RootlessWindowRec *winRec = WINREC(pWin);
868 Bool need_window_source = FALSE, resize_after = FALSE;
869
870 BoxRec rect;
871 int oldX2, newX2;
872 int oldY2, newY2;
873 unsigned int weight;
874
875 oldX2 = oldX + oldW, newX2 = newX + newW;
876 oldY2 = oldY + oldH, newY2 = newY + newH;
877
878 /* Decide which resize weighting to use */
879 weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
880 newX, newY, newW, newH, newBW);
881
882 /* Compute intersection between old and new rects */
883 rect.x1 = max(oldX, newX);
884 rect.y1 = max(oldY, newY);
885 rect.x2 = min(oldX2, newX2);
886 rect.y2 = min(oldY2, newY2);
887
888 RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
889 RL_DEBUG_MSG("%d %d %d %d %d %d %d %d %d %d\n",
890 oldX, oldY, oldW, oldH, oldBW, newX, newY, newW, newH, newBW);
891
892 RootlessRedisplay(pWin);
893
894 /* If gravity is true, then we need to have a way of recovering all
895 the original bits in the window for when X rearranges the contents
896 based on the various gravity settings. The obvious way is to just
897 snapshot the entire backing store before resizing it, but that
898 it slow on large windows.
899
900 So the optimization here is to use the implementation's resize
901 weighting options (if available) to allow us to reason about what
902 is left in the backing store after the resize. We can then only
903 copy what won't be there after the resize, and do a two-stage copy
904 operation.
905
906 Most of these optimizations are only applied when the top-left
907 corner of the window is fixed, since that's the common case. They
908 could probably be extended with some thought. */
909
910 gResizeDeathCount = 0;
911
912 if (gravity && weight == RL_GRAVITY_NORTH_WEST) {
913 unsigned int code = 0;
914
915 /* Top left corner is anchored. We never need to copy the
916 entire window. */
917
918 need_window_source = TRUE;
919
920 /* These comparisons were chosen to avoid setting bits when the sizes
921 are the same. (So the fastest case automatically gets taken when
922 dimensions are unchanging.) */
923
924 if (newW < oldW)
925 code |= WIDTH_SMALLER;
926 if (newH < oldH)
927 code |= HEIGHT_SMALLER;
928
929 if (((code ^ (code >> 1)) & 1) == 0) {
930 /* Both dimensions are either getting larger, or both
931 are getting smaller. No need to copy anything. */
932
933 if (code == (WIDTH_SMALLER | HEIGHT_SMALLER)) {
934 /* Since the window is getting smaller, we can do gravity
935 repair on it with it's current size, then resize it
936 afterwards. */
937
938 resize_after = TRUE;
939 }
940
941 gResizeDeathCount = 1;
942 }
943 else {
944 unsigned int copy_rowbytes, Bpp;
945 unsigned int copy_rect_width, copy_rect_height;
946 BoxRec copy_rect;
947
948 /* We can get away with a partial copy. 'rect' is the
949 intersection between old and new bounds, so copy
950 everything to the right of or below the intersection. */
951
952 RootlessStartDrawing(pWin);
953
954 if (code == WIDTH_SMALLER) {
955 copy_rect.x1 = rect.x2;
956 copy_rect.y1 = rect.y1;
957 copy_rect.x2 = oldX2;
958 copy_rect.y2 = oldY2;
959 }
960 else if (code == HEIGHT_SMALLER) {
961 copy_rect.x1 = rect.x1;
962 copy_rect.y1 = rect.y2;
963 copy_rect.x2 = oldX2;
964 copy_rect.y2 = oldY2;
965 }
966 else
967 OsAbort();
968
969 Bpp = winRec->win->drawable.bitsPerPixel / 8;
970 copy_rect_width = copy_rect.x2 - copy_rect.x1;
971 copy_rect_height = copy_rect.y2 - copy_rect.y1;
972 copy_rowbytes = ((copy_rect_width * Bpp) + 31) & ~31;
973 gResizeDeathBits = xallocarray(copy_rowbytes, copy_rect_height);
974
975 if (copy_rect_width * copy_rect_height >
976 rootless_CopyBytes_threshold &&
977 SCREENREC(pScreen)->imp->CopyBytes) {
978 SCREENREC(pScreen)->imp->CopyBytes(copy_rect_width * Bpp,
979 copy_rect_height,
980 ((char *) winRec->pixelData)
981 +
982 ((copy_rect.y1 -
983 oldY) *
984 winRec->bytesPerRow)
985 + (copy_rect.x1 -
986 oldX) * Bpp,
987 winRec->bytesPerRow,
988 gResizeDeathBits,
989 copy_rowbytes);
990 }
991 else {
992 fbBlt((FbBits *) (winRec->pixelData
993 +
994 ((copy_rect.y1 - oldY) * winRec->bytesPerRow)
995 + (copy_rect.x1 - oldX) * Bpp),
996 winRec->bytesPerRow / sizeof(FbBits), 0,
997 (FbBits *) gResizeDeathBits,
998 copy_rowbytes / sizeof(FbBits), 0, copy_rect_width * Bpp,
999 copy_rect_height, GXcopy, FB_ALLONES, Bpp, 0, 0);
1000 }
1001
1002 gResizeDeathBounds[1] = copy_rect;
1003 gResizeDeathPix[1]
1004 = GetScratchPixmapHeader(pScreen, copy_rect_width,
1005 copy_rect_height,
1006 winRec->win->drawable.depth,
1007 winRec->win->drawable.bitsPerPixel,
1008 winRec->bytesPerRow,
1009 (void *) gResizeDeathBits);
1010
1011 SetPixmapBaseToScreen(gResizeDeathPix[1],
1012 copy_rect.x1, copy_rect.y1);
1013
1014 gResizeDeathCount = 2;
1015 }
1016 }
1017 else if (gravity) {
1018 /* The general case. Just copy everything. */
1019
1020 RootlessStartDrawing(pWin);
1021
1022 gResizeDeathBits = xallocarray(winRec->bytesPerRow, winRec->height);
1023
1024 memcpy(gResizeDeathBits, winRec->pixelData,
1025 winRec->bytesPerRow * winRec->height);
1026
1027 gResizeDeathBounds[0] = (BoxRec) {
1028 oldX, oldY, oldX2, oldY2};
1029 gResizeDeathPix[0]
1030 = GetScratchPixmapHeader(pScreen, winRec->width,
1031 winRec->height,
1032 winRec->win->drawable.depth,
1033 winRec->win->drawable.bitsPerPixel,
1034 winRec->bytesPerRow,
1035 (void *) gResizeDeathBits);
1036
1037 SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1038 gResizeDeathCount = 1;
1039 }
1040
1041 RootlessStopDrawing(pWin, FALSE);
1042
1043 winRec->x = newX;
1044 winRec->y = newY;
1045 winRec->width = newW;
1046 winRec->height = newH;
1047 winRec->borderWidth = newBW;
1048
1049 /* Unless both dimensions are getting smaller, Resize the frame
1050 before doing gravity repair */
1051
1052 if (!resize_after) {
1053 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1054 newX + SCREEN_TO_GLOBAL_X,
1055 newY + SCREEN_TO_GLOBAL_Y,
1056 newW, newH, weight);
1057 }
1058
1059 RootlessStartDrawing(pWin);
1060
1061 /* If necessary, create a source pixmap pointing at the current
1062 window bits. */
1063
1064 if (need_window_source) {
1065 gResizeDeathBounds[0] = (BoxRec) {
1066 oldX, oldY, oldX2, oldY2};
1067 gResizeDeathPix[0]
1068 = GetScratchPixmapHeader(pScreen, oldW, oldH,
1069 winRec->win->drawable.depth,
1070 winRec->win->drawable.bitsPerPixel,
1071 winRec->bytesPerRow, winRec->pixelData);
1072
1073 SetPixmapBaseToScreen(gResizeDeathPix[0], oldX, oldY);
1074 }
1075
1076 /* Use custom CopyWindow when moving gravity bits around
1077 ResizeWindow assumes the old window contents are in the same
1078 pixmap, but here they're in deathPix instead. */
1079
1080 if (gravity) {
1081 gResizeOldCopyWindowProc = pScreen->CopyWindow;
1082 pScreen->CopyWindow = RootlessResizeCopyWindow;
1083 }
1084
1085 /* If we can't rely on the window server preserving the bits we
1086 need in the position we need, copy the pixels in the
1087 intersection from src to dst. ResizeWindow assumes these pixels
1088 are already present when making gravity adjustments. pWin
1089 currently has new-sized pixmap but is in old position.
1090
1091 FIXME: border width change! (?) */
1092
1093 if (gravity && weight == RL_GRAVITY_NONE) {
1094 PixmapPtr src, dst;
1095
1096 assert(gResizeDeathCount == 1);
1097
1098 src = gResizeDeathPix[0];
1099 dst = pScreen->GetWindowPixmap(pWin);
1100
1101 RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1102 rect.x1, rect.y1, rect.x2, rect.y2);
1103
1104 /* rect is the intersection of the old location and new location */
1105 if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL) {
1106 /* The window drawable still has the old frame position, which
1107 means that DST doesn't actually point at the origin of our
1108 physical backing store when adjusted by the drawable.x,y
1109 position. So sneakily adjust it temporarily while copying.. */
1110
1111 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1112 SetPixmapBaseToScreen(dst, newX, newY);
1113
1114 fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1115 &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1116
1117 ((PixmapPtr) dst)->devPrivate.ptr = winRec->pixelData;
1118 SetPixmapBaseToScreen(dst, oldX, oldY);
1119 }
1120 }
1121
1122 return resize_after;
1123 }
1124
1125 static void
FinishFrameResize(WindowPtr pWin,Bool gravity,int oldX,int oldY,unsigned int oldW,unsigned int oldH,unsigned int oldBW,int newX,int newY,unsigned int newW,unsigned int newH,unsigned int newBW,Bool resize_now)1126 FinishFrameResize(WindowPtr pWin, Bool gravity, int oldX, int oldY,
1127 unsigned int oldW, unsigned int oldH, unsigned int oldBW,
1128 int newX, int newY, unsigned int newW, unsigned int newH,
1129 unsigned int newBW, Bool resize_now)
1130 {
1131 ScreenPtr pScreen = pWin->drawable.pScreen;
1132 RootlessWindowRec *winRec = WINREC(pWin);
1133 int i;
1134
1135 RootlessStopDrawing(pWin, FALSE);
1136
1137 if (resize_now) {
1138 unsigned int weight;
1139
1140 /* We didn't resize anything earlier, so do it now, now that
1141 we've finished gravitating the bits. */
1142
1143 weight = ResizeWeighting(oldX, oldY, oldW, oldH, oldBW,
1144 newX, newY, newW, newH, newBW);
1145
1146 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1147 newX + SCREEN_TO_GLOBAL_X,
1148 newY + SCREEN_TO_GLOBAL_Y,
1149 newW, newH, weight);
1150 }
1151
1152 /* Redraw everything. FIXME: there must be times when we don't need
1153 to do this. Perhaps when top-left weighting and no gravity? */
1154
1155 RootlessDamageRect(pWin, -newBW, -newBW, newW, newH);
1156
1157 for (i = 0; i < 2; i++) {
1158 if (gResizeDeathPix[i] != NULL) {
1159 FreeScratchPixmapHeader(gResizeDeathPix[i]);
1160 gResizeDeathPix[i] = NULL;
1161 }
1162 }
1163
1164 free(gResizeDeathBits);
1165 gResizeDeathBits = NULL;
1166
1167 if (gravity) {
1168 pScreen->CopyWindow = gResizeOldCopyWindowProc;
1169 }
1170 }
1171
1172 /*
1173 * RootlessMoveWindow
1174 * If kind==VTOther, window border is resizing (and borderWidth is
1175 * already changed!!@#$) This case works like window resize, not move.
1176 */
1177 void
RootlessMoveWindow(WindowPtr pWin,int x,int y,WindowPtr pSib,VTKind kind)1178 RootlessMoveWindow(WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1179 {
1180 RootlessWindowRec *winRec = WINREC(pWin);
1181 ScreenPtr pScreen = pWin->drawable.pScreen;
1182 CopyWindowProcPtr oldCopyWindowProc = NULL;
1183 int oldX = 0, oldY = 0, newX = 0, newY = 0;
1184 unsigned int oldW = 0, oldH = 0, oldBW = 0;
1185 unsigned int newW = 0, newH = 0, newBW = 0;
1186 Bool resize_after = FALSE;
1187 RegionRec saveRoot;
1188
1189 RL_DEBUG_MSG("movewindow start \n");
1190
1191 if (winRec) {
1192 if (kind == VTMove) {
1193 oldX = winRec->x;
1194 oldY = winRec->y;
1195 RootlessRedisplay(pWin);
1196 RootlessStartDrawing(pWin);
1197 }
1198 else {
1199 RL_DEBUG_MSG("movewindow border resizing ");
1200
1201 oldBW = winRec->borderWidth;
1202 oldX = winRec->x;
1203 oldY = winRec->y;
1204 oldW = winRec->width;
1205 oldH = winRec->height;
1206
1207 newBW = wBorderWidth(pWin);
1208 newX = x;
1209 newY = y;
1210 newW = pWin->drawable.width + 2 * newBW;
1211 newH = pWin->drawable.height + 2 * newBW;
1212
1213 resize_after = StartFrameResize(pWin, FALSE,
1214 oldX, oldY, oldW, oldH, oldBW,
1215 newX, newY, newW, newH, newBW);
1216 }
1217 }
1218
1219 HUGE_ROOT(pWin);
1220 SCREEN_UNWRAP(pScreen, MoveWindow);
1221
1222 if (winRec) {
1223 oldCopyWindowProc = pScreen->CopyWindow;
1224 pScreen->CopyWindow = RootlessNoCopyWindow;
1225 }
1226 pScreen->MoveWindow(pWin, x, y, pSib, kind);
1227 if (winRec) {
1228 pScreen->CopyWindow = oldCopyWindowProc;
1229 }
1230
1231 NORMAL_ROOT(pWin);
1232 SCREEN_WRAP(pScreen, MoveWindow);
1233
1234 if (winRec) {
1235 if (kind == VTMove) {
1236 winRec->x = x;
1237 winRec->y = y;
1238 RootlessStopDrawing(pWin, FALSE);
1239 SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1240 x + SCREEN_TO_GLOBAL_X,
1241 y + SCREEN_TO_GLOBAL_Y);
1242 }
1243 else {
1244 FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1245 newX, newY, newW, newH, newBW, resize_after);
1246 }
1247 }
1248
1249 RL_DEBUG_MSG("movewindow end\n");
1250 }
1251
1252 /*
1253 * RootlessResizeWindow
1254 * Note: (x, y, w, h) as passed to this procedure don't match the frame
1255 * definition. (x,y) is corner of very outer edge, *outside* border.
1256 * w,h is width and height *inside* border, *ignoring* border width.
1257 * The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
1258 * is total rect and (x+bw, y+bw, w, h) is inner rect.
1259 */
1260 void
RootlessResizeWindow(WindowPtr pWin,int x,int y,unsigned int w,unsigned int h,WindowPtr pSib)1261 RootlessResizeWindow(WindowPtr pWin, int x, int y,
1262 unsigned int w, unsigned int h, WindowPtr pSib)
1263 {
1264 RootlessWindowRec *winRec = WINREC(pWin);
1265 ScreenPtr pScreen = pWin->drawable.pScreen;
1266 int oldX = 0, oldY = 0, newX = 0, newY = 0;
1267 unsigned int oldW = 0, oldH = 0, oldBW = 0, newW = 0, newH = 0, newBW = 0;
1268 Bool resize_after = FALSE;
1269 RegionRec saveRoot;
1270
1271 RL_DEBUG_MSG("resizewindow start (win 0x%x) ", pWin);
1272
1273 if (pWin->parent) {
1274 if (winRec) {
1275 oldBW = winRec->borderWidth;
1276 oldX = winRec->x;
1277 oldY = winRec->y;
1278 oldW = winRec->width;
1279 oldH = winRec->height;
1280
1281 newBW = oldBW;
1282 newX = x;
1283 newY = y;
1284 newW = w + 2 * newBW;
1285 newH = h + 2 * newBW;
1286
1287 resize_after = StartFrameResize(pWin, TRUE,
1288 oldX, oldY, oldW, oldH, oldBW,
1289 newX, newY, newW, newH, newBW);
1290 }
1291
1292 HUGE_ROOT(pWin);
1293 SCREEN_UNWRAP(pScreen, ResizeWindow);
1294 pScreen->ResizeWindow(pWin, x, y, w, h, pSib);
1295 SCREEN_WRAP(pScreen, ResizeWindow);
1296 NORMAL_ROOT(pWin);
1297
1298 if (winRec) {
1299 FinishFrameResize(pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
1300 newX, newY, newW, newH, newBW, resize_after);
1301 }
1302 }
1303 else {
1304 /* Special case for resizing the root window */
1305 BoxRec box;
1306
1307 pWin->drawable.x = x;
1308 pWin->drawable.y = y;
1309 pWin->drawable.width = w;
1310 pWin->drawable.height = h;
1311
1312 box.x1 = x;
1313 box.y1 = y;
1314 box.x2 = x + w;
1315 box.y2 = y + h;
1316 RegionUninit(&pWin->winSize);
1317 RegionInit(&pWin->winSize, &box, 1);
1318 RegionCopy(&pWin->borderSize, &pWin->winSize);
1319 RegionCopy(&pWin->clipList, &pWin->winSize);
1320 RegionCopy(&pWin->borderClip, &pWin->winSize);
1321
1322 if (winRec) {
1323 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1324 x + SCREEN_TO_GLOBAL_X,
1325 y + SCREEN_TO_GLOBAL_Y,
1326 w, h, RL_GRAVITY_NONE);
1327 }
1328
1329 miSendExposures(pWin, &pWin->borderClip,
1330 pWin->drawable.x, pWin->drawable.y);
1331 }
1332
1333 RL_DEBUG_MSG("resizewindow end\n");
1334 }
1335
1336 /*
1337 * RootlessRepositionWindow
1338 * Called by the implementation when a window needs to be repositioned to
1339 * its correct location on the screen. This routine is typically needed
1340 * due to changes in the underlying window system, such as a screen layout
1341 * change.
1342 */
1343 void
RootlessRepositionWindow(WindowPtr pWin)1344 RootlessRepositionWindow(WindowPtr pWin)
1345 {
1346 RootlessWindowRec *winRec = WINREC(pWin);
1347 ScreenPtr pScreen = pWin->drawable.pScreen;
1348
1349 if (winRec == NULL)
1350 return;
1351
1352 RootlessStopDrawing(pWin, FALSE);
1353 SCREENREC(pScreen)->imp->MoveFrame(winRec->wid, pScreen,
1354 winRec->x + SCREEN_TO_GLOBAL_X,
1355 winRec->y + SCREEN_TO_GLOBAL_Y);
1356
1357 RootlessReorderWindow(pWin);
1358 }
1359
1360 /*
1361 * RootlessReparentWindow
1362 * Called after a window has been reparented. Generally windows are not
1363 * framed until they are mapped. However, a window may be framed early by the
1364 * implementation calling RootlessFrameForWindow. (e.g. this could be needed
1365 * to attach a VRAM surface to it.) If the window is subsequently reparented
1366 * by the window manager before being mapped, we need to give the frame to
1367 * the new top-level window.
1368 */
1369 void
RootlessReparentWindow(WindowPtr pWin,WindowPtr pPriorParent)1370 RootlessReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
1371 {
1372 ScreenPtr pScreen = pWin->drawable.pScreen;
1373 RootlessWindowRec *winRec = WINREC(pWin);
1374 WindowPtr pTopWin;
1375
1376 /* Check that window is not top-level now, but used to be. */
1377 if (IsRoot(pWin) || IsRoot(pWin->parent)
1378 || IsTopLevel(pWin) || winRec == NULL) {
1379 goto out;
1380 }
1381
1382 /* If the formerly top-level window has a frame, we want to give the
1383 frame to its new top-level parent. If we can't do that, we'll just
1384 have to jettison it... */
1385
1386 pTopWin = TopLevelParent(pWin);
1387 assert(pTopWin != pWin);
1388
1389 pWin->unhittable = FALSE;
1390
1391 DeleteProperty(serverClient, pWin, xa_native_window_id());
1392
1393 if (WINREC(pTopWin) != NULL) {
1394 /* We're screwed. */
1395 RootlessDestroyFrame(pWin, winRec);
1396 }
1397 else {
1398 if (!pTopWin->realized && pWin->realized) {
1399 SCREENREC(pScreen)->imp->UnmapFrame(winRec->wid);
1400 }
1401
1402 /* Switch the frame record from one to the other. */
1403
1404 SETWINREC(pWin, NULL);
1405 SETWINREC(pTopWin, winRec);
1406
1407 RootlessInitializeFrame(pTopWin, winRec);
1408 RootlessReshapeFrame(pTopWin);
1409
1410 SCREENREC(pScreen)->imp->ResizeFrame(winRec->wid, pScreen,
1411 winRec->x + SCREEN_TO_GLOBAL_X,
1412 winRec->y + SCREEN_TO_GLOBAL_Y,
1413 winRec->width, winRec->height,
1414 RL_GRAVITY_NONE);
1415
1416 if (SCREENREC(pScreen)->imp->SwitchWindow) {
1417 SCREENREC(pScreen)->imp->SwitchWindow(winRec, pWin);
1418 }
1419
1420 if (pTopWin->realized && !pWin->realized)
1421 winRec->is_reorder_pending = TRUE;
1422 }
1423
1424 out:
1425 if (SCREENREC(pScreen)->ReparentWindow) {
1426 SCREEN_UNWRAP(pScreen, ReparentWindow);
1427 pScreen->ReparentWindow(pWin, pPriorParent);
1428 SCREEN_WRAP(pScreen, ReparentWindow);
1429 }
1430 }
1431
1432 void
RootlessFlushWindowColormap(WindowPtr pWin)1433 RootlessFlushWindowColormap(WindowPtr pWin)
1434 {
1435 RootlessWindowRec *winRec = WINREC(pWin);
1436 ScreenPtr pScreen = pWin->drawable.pScreen;
1437
1438 if (winRec == NULL)
1439 return;
1440
1441 RootlessStopDrawing(pWin, FALSE);
1442
1443 if (SCREENREC(pScreen)->imp->UpdateColormap)
1444 SCREENREC(pScreen)->imp->UpdateColormap(winRec->wid, pScreen);
1445 }
1446
1447 /*
1448 * RootlessChangeBorderWidth
1449 * FIXME: untested!
1450 * pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1451 * Frame moves and resizes.
1452 */
1453 void
RootlessChangeBorderWidth(WindowPtr pWin,unsigned int width)1454 RootlessChangeBorderWidth(WindowPtr pWin, unsigned int width)
1455 {
1456 RegionRec saveRoot;
1457 Bool resize_after = FALSE;
1458
1459 RL_DEBUG_MSG("change border width ");
1460
1461 if (width != wBorderWidth(pWin)) {
1462 RootlessWindowRec *winRec = WINREC(pWin);
1463 int oldX = 0, oldY = 0, newX = 0, newY = 0;
1464 unsigned int oldW = 0, oldH = 0, oldBW = 0;
1465 unsigned int newW = 0, newH = 0, newBW = 0;
1466
1467 if (winRec) {
1468 oldBW = winRec->borderWidth;
1469 oldX = winRec->x;
1470 oldY = winRec->y;
1471 oldW = winRec->width;
1472 oldH = winRec->height;
1473
1474 newBW = width;
1475 newX = pWin->drawable.x - newBW;
1476 newY = pWin->drawable.y - newBW;
1477 newW = pWin->drawable.width + 2 * newBW;
1478 newH = pWin->drawable.height + 2 * newBW;
1479
1480 resize_after = StartFrameResize(pWin, FALSE,
1481 oldX, oldY, oldW, oldH, oldBW,
1482 newX, newY, newW, newH, newBW);
1483 }
1484
1485 HUGE_ROOT(pWin);
1486 SCREEN_UNWRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1487 pWin->drawable.pScreen->ChangeBorderWidth(pWin, width);
1488 SCREEN_WRAP(pWin->drawable.pScreen, ChangeBorderWidth);
1489 NORMAL_ROOT(pWin);
1490
1491 if (winRec) {
1492 FinishFrameResize(pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1493 newX, newY, newW, newH, newBW, resize_after);
1494 }
1495 }
1496
1497 RL_DEBUG_MSG("change border width end\n");
1498 }
1499
1500 /*
1501 * RootlessOrderAllWindows
1502 * Brings all X11 windows to the top of the window stack
1503 * (i.e in front of Aqua windows) -- called when X11.app is given focus
1504 */
1505 void
RootlessOrderAllWindows(Bool include_unhitable)1506 RootlessOrderAllWindows(Bool include_unhitable)
1507 {
1508 int i;
1509 WindowPtr pWin;
1510
1511 if (windows_hidden)
1512 return;
1513
1514 RL_DEBUG_MSG("RootlessOrderAllWindows() ");
1515 for (i = 0; i < screenInfo.numScreens; i++) {
1516 if (screenInfo.screens[i] == NULL)
1517 continue;
1518 pWin = screenInfo.screens[i]->root;
1519 if (pWin == NULL)
1520 continue;
1521
1522 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1523 if (!pWin->realized)
1524 continue;
1525 if (RootlessEnsureFrame(pWin) == NULL)
1526 continue;
1527 if (!include_unhitable && pWin->unhittable)
1528 continue;
1529 RootlessReorderWindow(pWin);
1530 }
1531 }
1532 RL_DEBUG_MSG("RootlessOrderAllWindows() done");
1533 }
1534
1535 void
RootlessEnableRoot(ScreenPtr pScreen)1536 RootlessEnableRoot(ScreenPtr pScreen)
1537 {
1538 WindowPtr pRoot;
1539
1540 pRoot = pScreen->root;
1541
1542 RootlessEnsureFrame(pRoot);
1543 (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
1544 RootlessReorderWindow(pRoot);
1545 }
1546
1547 void
RootlessDisableRoot(ScreenPtr pScreen)1548 RootlessDisableRoot(ScreenPtr pScreen)
1549 {
1550 WindowPtr pRoot;
1551 RootlessWindowRec *winRec;
1552
1553 pRoot = pScreen->root;
1554 winRec = WINREC(pRoot);
1555
1556 if (NULL == winRec)
1557 return;
1558
1559 RootlessDestroyFrame(pRoot, winRec);
1560 DeleteProperty(serverClient, pRoot, xa_native_window_id());
1561 }
1562
1563 void
RootlessHideAllWindows(void)1564 RootlessHideAllWindows(void)
1565 {
1566 int i;
1567 ScreenPtr pScreen;
1568 WindowPtr pWin;
1569 RootlessWindowRec *winRec;
1570
1571 if (windows_hidden)
1572 return;
1573
1574 windows_hidden = TRUE;
1575
1576 for (i = 0; i < screenInfo.numScreens; i++) {
1577 pScreen = screenInfo.screens[i];
1578 if (pScreen == NULL)
1579 continue;
1580 pWin = pScreen->root;
1581 if (pWin == NULL)
1582 continue;
1583
1584 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1585 if (!pWin->realized)
1586 continue;
1587
1588 RootlessStopDrawing(pWin, FALSE);
1589
1590 winRec = WINREC(pWin);
1591 if (winRec != NULL) {
1592 if (SCREENREC(pScreen)->imp->HideWindow)
1593 SCREENREC(pScreen)->imp->HideWindow(winRec->wid);
1594 }
1595 }
1596 }
1597 }
1598
1599 void
RootlessShowAllWindows(void)1600 RootlessShowAllWindows(void)
1601 {
1602 int i;
1603 ScreenPtr pScreen;
1604 WindowPtr pWin;
1605 RootlessWindowRec *winRec;
1606
1607 if (!windows_hidden)
1608 return;
1609
1610 windows_hidden = FALSE;
1611
1612 for (i = 0; i < screenInfo.numScreens; i++) {
1613 pScreen = screenInfo.screens[i];
1614 if (pScreen == NULL)
1615 continue;
1616 pWin = pScreen->root;
1617 if (pWin == NULL)
1618 continue;
1619
1620 for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib) {
1621 if (!pWin->realized)
1622 continue;
1623
1624 winRec = RootlessEnsureFrame(pWin);
1625 if (winRec == NULL)
1626 continue;
1627
1628 RootlessReorderWindow(pWin);
1629 }
1630
1631 RootlessScreenExpose(pScreen);
1632 }
1633 }
1634
1635 /*
1636 * SetPixmapOfAncestors
1637 * Set the Pixmaps on all ParentRelative windows up the ancestor chain.
1638 */
1639 void
RootlessSetPixmapOfAncestors(WindowPtr pWin)1640 RootlessSetPixmapOfAncestors(WindowPtr pWin)
1641 {
1642 ScreenPtr pScreen = pWin->drawable.pScreen;
1643 WindowPtr topWin = TopLevelParent(pWin);
1644 RootlessWindowRec *topWinRec = WINREC(topWin);
1645
1646 while (pWin->backgroundState == ParentRelative) {
1647 if (pWin == topWin) {
1648 // disallow ParentRelative background state on top level
1649 XID pixel = 0;
1650
1651 ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
1652 RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
1653 break;
1654 }
1655
1656 pWin = pWin->parent;
1657 pScreen->SetWindowPixmap(pWin, topWinRec->pixmap);
1658 }
1659 }
1660