Change mirror tool options
[synfig.git] / synfig-osx / launcher / rootless-window.c
1 /*
2  * Rootless window management
3  */
4 /*
5  * Copyright (c) 2001 Greg Parker. All Rights Reserved.
6  * Copyright (c) 2002 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 /* Portions of this file are based on fbwindow.c, which contains the
32  * following copyright:
33  *
34  * Copyright © 1998 Keith Packard
35  */
36 /* $XFree86: xc/programs/Xserver/hw/darwin/quartz/rootlessWindow.c,v 1.11 2002/09/28 00:43:39 torrey Exp $ */
37
38 #include "rootless-common.h"
39 #include "rootless-window.h"
40 #include "darwin.h"
41 #include "Xplugin.h"
42 #include "x-hash.h"
43 #include "x-list.h"
44 #define _APPLEWM_SERVER_
45 #include "applewmstr.h"
46
47 #include "fb.h"
48 #include "propertyst.h"
49
50 #ifdef PANORAMIX
51 #include "panoramiX.h"
52 #include "panoramiXsrv.h"
53 #endif
54
55 #include <X11/Xatom.h>
56 #include <pthread.h>
57
58 #define DEFINE_ATOM_HELPER(func,atom_name)                      \
59 static Atom func (void) {                                       \
60     static unsigned int generation;                             \
61     static Atom atom;                                           \
62     if (generation != serverGeneration) {                       \
63         generation = serverGeneration;                          \
64         atom = MakeAtom (atom_name, strlen (atom_name), TRUE);  \
65     }                                                           \
66     return atom;                                                \
67 }
68
69 DEFINE_ATOM_HELPER (xa_native_screen_origin, "_NATIVE_SCREEN_ORIGIN")
70 DEFINE_ATOM_HELPER (xa_native_window_id, "_NATIVE_WINDOW_ID")
71 DEFINE_ATOM_HELPER (xa_apple_no_order_in, "_APPLE_NO_ORDER_IN")
72
73 /* Maps xp_window_id -> AquaWindowRec */
74 static x_hash_table *window_hash;
75 static pthread_mutex_t window_hash_mutex;
76
77 static Bool no_configure_window;
78 static Bool windows_hidden;
79
80 static const int normal_window_levels[AppleWMNumWindowLevels+1] = {
81     0, 3, 4, 5, LONG_MIN + 30, LONG_MIN + 29,
82 };
83 static const int rooted_window_levels[AppleWMNumWindowLevels+1] = {
84     202, 203, 204, 205, 201, 200
85 };
86
87 static inline xp_error
88 configure_window (xp_window_id id, unsigned int mask,
89                   const xp_window_changes *values)
90 {
91     if (!no_configure_window)
92         return xp_configure_window (id, mask, values);
93     else
94         return XP_Success;
95 }
96
97 static inline unsigned long
98 current_time_in_seconds (void)
99 {
100     unsigned long t = 0;
101
102     t += currentTime.milliseconds / 1000;
103     t += currentTime.months * 4294967;
104
105     return t;
106 }
107
108 static inline Bool
109 rootlessHasRoot (ScreenPtr pScreen)
110 {
111     return WINREC (WindowTable[pScreen->myNum]) != NULL;
112 }
113
114 void
115 RootlessNativeWindowStateChanged (xp_window_id id, unsigned int state)
116 {
117     WindowPtr pWin;
118     RootlessWindowRec *winRec;
119
120     pWin = RootlessGetXWindow (id);
121     if (pWin == NULL)
122         return;
123
124     winRec = WINREC (pWin);
125     if (winRec == NULL)
126         return;
127
128     winRec->is_offscreen = (state & XP_WINDOW_STATE_OFFSCREEN) != 0;
129     winRec->is_obscured = (state & XP_WINDOW_STATE_OBSCURED) != 0;
130
131 #ifdef ROOTLESS
132     pWin->rootlessUnhittable = winRec->is_offscreen;
133 #endif
134 }
135
136 void
137 RootlessNativeWindowMoved (xp_window_id id)
138 {
139     WindowPtr pWin;
140     xp_box bounds;
141     int sx, sy;
142     XID vlist[2];
143     Mask mask;
144     ClientPtr client;
145
146     pWin = RootlessGetXWindow (id);
147     if (pWin == NULL)
148         return;
149
150     if (xp_get_window_bounds (id, &bounds) != Success)
151         return;
152
153     sx = dixScreenOrigins[pWin->drawable.pScreen->myNum].x + darwinMainScreenX;
154     sy = dixScreenOrigins[pWin->drawable.pScreen->myNum].y + darwinMainScreenY;
155
156     /* Fake up a ConfigureWindow packet to resize the window to the
157        current bounds. */
158
159     vlist[0] = (INT16) bounds.x1 - sx;
160     vlist[1] = (INT16) bounds.y1 - sy;
161     mask = CWX | CWY;
162
163     /* pretend we're the owner of the window! */
164     client = LookupClient (pWin->drawable.id, NullClient);
165
166     /* Don't want to do anything to the physical window (avoids
167        notification-response feedback loops) */
168
169     no_configure_window = TRUE;
170     ConfigureWindow (pWin, mask, vlist, client);
171     no_configure_window = FALSE;
172 }
173
174 /* Updates the _NATIVE_SCREEN_ORIGIN property on the given root window. */
175 static void
176 set_screen_origin (WindowPtr pWin)
177 {
178     long data[2];
179
180     if (!IsRoot (pWin))
181         return;
182
183     /* FIXME: move this to an extension? */
184
185     data[0] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].x
186                + darwinMainScreenX);
187     data[1] = (dixScreenOrigins[pWin->drawable.pScreen->myNum].y
188                + darwinMainScreenY);
189
190     ChangeWindowProperty (pWin, xa_native_screen_origin (), XA_INTEGER,
191                           32, PropModeReplace, 2, data, TRUE);
192 }
193
194 /* For now, don't create a physical window until either the window is
195    realized, or we really need it (e.g. to attach VRAM surfaces to).
196    Do reset the window size so it's not clipped by the root window. */
197 Bool
198 RootlessCreateWindow (WindowPtr pWin)
199 {
200     Bool result;
201     RegionRec saveRoot;
202
203     SCREEN_UNWRAP (pWin->drawable.pScreen, CreateWindow);
204
205     if (!IsRoot (pWin))
206     {
207         /* win/border size set by DIX, not by wrapped CreateWindow, so
208            correct it here. Don't HUGE_ROOT when pWin is the root! */
209
210         HUGE_ROOT (pWin);
211         SetWinSize (pWin);
212         SetBorderSize (pWin);
213     }
214     else
215     {
216         set_screen_origin (pWin);
217     }
218
219     result = pWin->drawable.pScreen->CreateWindow (pWin);
220
221     if (pWin->parent)
222         NORMAL_ROOT (pWin);
223
224     SCREEN_WRAP (pWin->drawable.pScreen, CreateWindow);
225
226     return result;
227 }
228
229 /* Destroy the physical window associated with the given window */
230 static void
231 rootlessDestroyFrame (WindowPtr pWin, RootlessWindowRec *winRec)
232 {
233     RootlessStopDrawing (pWin, FALSE);
234
235     pthread_mutex_lock (&window_hash_mutex);
236     x_hash_table_remove (window_hash, (void *) winRec->wid);
237     pthread_mutex_unlock (&window_hash_mutex);
238
239     xp_destroy_window (winRec->wid);
240
241     xfree (winRec);
242     WINREC (pWin) = NULL;
243 }
244
245 Bool
246 RootlessDestroyWindow (WindowPtr pWin)
247 {
248     RootlessWindowRec *winRec = WINREC(pWin);
249     Bool result;
250
251     if (winRec != NULL)
252         rootlessDestroyFrame (pWin, winRec);
253
254     /* winRec is gone now */
255
256     SCREEN_UNWRAP(pWin->drawable.pScreen, DestroyWindow);
257
258     result = pWin->drawable.pScreen->DestroyWindow (pWin);
259
260     SCREEN_WRAP(pWin->drawable.pScreen, DestroyWindow);
261
262     return result;
263 }
264
265 #ifdef SHAPE
266 static Bool
267 RootlessGetShape (WindowPtr pWin, RegionPtr pShape)
268 {
269     if (wBoundingShape (pWin) == NULL)
270         return FALSE;
271
272     /* wBoundingShape is relative to *inner* origin of window.
273        Translate by borderWidth to get the outside-relative position. */
274
275     REGION_INIT (pScreen, pShape, NullBox, 0);
276     REGION_COPY (pScreen, pShape, wBoundingShape (pWin));
277     REGION_TRANSLATE (pScreen, pShape, pWin->borderWidth, pWin->borderWidth);
278
279     return TRUE;
280 }
281
282 /* boundingShape = outside border (like borderClip)
283    clipShape = inside border (like clipList)
284    Both are in window-local coordinates
285    We only care about boundingShape (FIXME true?)
286
287    RootlessReallySetShape is used in several places other than SetShape.
288    Most importantly, SetShape is often called on unmapped windows, so we
289    have to wait until the window is mapped to reshape the frame. */
290 static void
291 rootlessSetShape (WindowPtr pWin)
292 {
293     RootlessWindowRec *winRec = WINREC (pWin);
294
295     RegionRec newShape;
296     RegionPtr pShape;
297     xp_window_changes wc;
298
299     if (winRec == NULL)
300         return;
301
302     RootlessStopDrawing (pWin, FALSE);
303
304     pShape = RootlessGetShape (pWin, &newShape) ? &newShape : NULL;
305
306     RL_DEBUG_MSG("reshaping...");
307     RL_DEBUG_MSG("numrects %d, extents %d %d %d %d\n",
308                  REGION_NUM_RECTS(&newShape),
309                  newShape.extents.x1, newShape.extents.y1,
310                  newShape.extents.x2, newShape.extents.y2);
311
312     RootlessDisableUpdate (pWin);
313
314     if (pShape != NULL)
315     {
316         wc.shape_nrects = REGION_NUM_RECTS (pShape);
317         wc.shape_rects = REGION_RECTS (pShape);
318     }
319     else
320     {
321         wc.shape_nrects = -1;
322         wc.shape_rects = NULL;
323     }
324
325     wc.shape_tx = wc.shape_ty = 0;
326
327     configure_window (winRec->wid, XP_SHAPE, &wc);
328     
329     if (pShape != NULL)
330         REGION_UNINIT(pScreen, &newShape);
331 }
332
333 void
334 RootlessSetShape (WindowPtr pWin)
335 {
336     ScreenPtr pScreen = pWin->drawable.pScreen;
337
338     SCREEN_UNWRAP (pScreen, SetShape);
339
340     pScreen->SetShape (pWin);
341
342     SCREEN_WRAP (pScreen, SetShape);
343
344     rootlessSetShape (pWin);
345 }
346 #endif
347
348 /* Disallow ParentRelative background on top-level windows
349    because the root window doesn't really have the right background
350    and fb will try to draw on the root instead of on the window.
351    ParentRelative prevention is also in PaintWindowBackground/Border()
352    so it is no longer really needed here. */
353 Bool
354 RootlessChangeWindowAttributes (WindowPtr pWin, unsigned long vmask)
355 {
356     Bool result;
357     ScreenPtr pScreen = pWin->drawable.pScreen;
358
359     RL_DEBUG_MSG("change window attributes start\n");
360
361     SCREEN_UNWRAP (pScreen, ChangeWindowAttributes);
362
363     result = pScreen->ChangeWindowAttributes (pWin, vmask);
364
365     SCREEN_WRAP (pScreen, ChangeWindowAttributes);
366
367     if (WINREC (pWin) != NULL)
368     {
369         /* disallow ParentRelative background state */
370
371         if (pWin->backgroundState == ParentRelative)
372         {
373             XID pixel = 0;
374             ChangeWindowAttributes (pWin, CWBackPixel, &pixel, serverClient);
375         }
376     }
377
378     RL_DEBUG_MSG("change window attributes end\n");
379     return result;
380 }
381
382 /* This is a hook for when DIX moves or resizes a window.
383    Update the frame position now. (x, y) are *inside* position.
384    After this, mi and fb are expecting the pixmap to be at the new location. */
385 Bool
386 RootlessPositionWindow (WindowPtr pWin, int x, int y)
387 {
388     ScreenPtr pScreen = pWin->drawable.pScreen;
389     RootlessWindowRec *winRec = WINREC (pWin);
390     Bool result;
391
392     RL_DEBUG_MSG("positionwindow start (win 0x%x)\n", pWin);
393
394     if (winRec != NULL)
395     {
396         if (winRec->is_drawing)
397         {
398             /* Reset frame's pixmap and move it to the new position. */
399             int bw = wBorderWidth (pWin);
400
401             winRec->pixmap->devPrivate.ptr = winRec->data;
402             TranslatePixmapBase (winRec->pixmap, - (x - bw), - (y - bw));
403         }
404     }
405
406     SCREEN_UNWRAP (pScreen, PositionWindow);
407
408     result = pScreen->PositionWindow (pWin, x, y);
409
410     SCREEN_WRAP(pScreen, PositionWindow);
411
412     RL_DEBUG_MSG("positionwindow end\n");
413     return result;
414 }
415
416 /* Initialize some basic attributes of the frame. Note that winRec
417    may already have valid data in it, so don't overwrite anything
418    valuable. */
419 static void
420 rootlessInitializeFrame (WindowPtr pWin, RootlessWindowRec *winRec)
421 {
422     DrawablePtr d = &pWin->drawable;
423     int bw = wBorderWidth (pWin);
424
425     winRec->win = pWin;
426
427     winRec->x = d->x - bw;
428     winRec->y = d->y - bw;
429     winRec->width = d->width + 2*bw;
430     winRec->height = d->height + 2*bw;
431     winRec->borderWidth = bw;
432 }
433
434 static void
435 rootlessSetNativeProperty (RootlessWindowRec *winRec)
436 {
437     xp_error err;
438     unsigned int native_id;
439     long data;
440
441     err = xp_get_native_window (winRec->wid, &native_id);
442     if (err == Success)
443     {
444         /* FIXME: move this to an extension? */
445
446         data = native_id;
447         ChangeWindowProperty (winRec->win, xa_native_window_id (),
448                               XA_INTEGER, 32, PropModeReplace, 1, &data, TRUE);
449     }
450 }
451
452 static xp_error
453 rootlessColormapCallback (void *data, int first_color,
454                           int n_colors, uint32_t *colors)
455 {
456     return (RootlessResolveColormap (data, first_color, n_colors, colors)
457             ? XP_Success : XP_BadMatch);
458 }
459
460 /* If the given window doesn't have a physical window associated with it,
461    attempt to create one. If that's unsuccessful, return null. */
462 static RootlessWindowRec *
463 rootlessEnsureFrame (WindowPtr pWin)
464 {
465     ScreenPtr pScreen = pWin->drawable.pScreen;
466     RootlessWindowRec *winRec;
467     RegionRec shape;
468     RegionPtr pShape = NULL;
469
470     xp_window_changes wc;
471     unsigned int mask;
472     xp_error err;
473     int sx, sy;
474
475     if (WINREC (pWin) != NULL)
476         return WINREC (pWin);
477
478     if (pWin->drawable.class != InputOutput)
479         return NULL;
480
481     winRec = xalloc (sizeof(RootlessWindowRec));
482
483     if (!winRec)
484         return NULL;
485
486     rootlessInitializeFrame (pWin, winRec);
487
488     winRec->is_drawing = FALSE;
489     winRec->pixmap = NULL;
490     winRec->wid = 0;
491     winRec->is_update_disabled = FALSE;
492     winRec->is_reorder_pending = FALSE;
493     winRec->level = !IsRoot (pWin) ? 0 : AppleWMNumWindowLevels;
494     WINREC(pWin) = winRec;
495
496 #ifdef SHAPE
497     if (RootlessGetShape (pWin, &shape))
498         pShape = &shape;
499 #endif
500
501     sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX;
502     sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY;
503
504     mask = 0;
505
506     wc.x = sx + winRec->x;
507     wc.y = sy + winRec->y;
508     wc.width = winRec->width;
509     wc.height = winRec->height;
510     wc.bit_gravity = XP_GRAVITY_NONE;
511     mask |= XP_BOUNDS;
512
513     if (pWin->drawable.depth == 8)
514     {
515         wc.depth = XP_DEPTH_INDEX8;
516         wc.colormap = rootlessColormapCallback;
517         wc.colormap_data = pScreen;
518         mask |= XP_COLORMAP;
519     }
520     else if (pWin->drawable.depth == 15)
521         wc.depth = XP_DEPTH_RGB555;
522     else if (pWin->drawable.depth == 24)
523         wc.depth = XP_DEPTH_ARGB8888;
524     else
525         wc.depth = XP_DEPTH_NIL;
526     mask |= XP_DEPTH;
527
528     if (pShape != NULL)
529     {
530         wc.shape_nrects = REGION_NUM_RECTS (pShape);
531         wc.shape_rects = REGION_RECTS (pShape);
532         wc.shape_tx = wc.shape_ty = 0;
533         mask |= XP_SHAPE;
534     }
535
536     if (!rootlessHasRoot (pScreen))
537         wc.window_level = normal_window_levels[winRec->level];
538     else
539         wc.window_level = rooted_window_levels[winRec->level];
540     mask |= XP_WINDOW_LEVEL;
541
542     err = xp_create_window (mask, &wc, &winRec->wid);
543
544     if (err != Success)
545     {
546         xfree (winRec);
547         return NULL;
548     }
549         
550     if (window_hash == NULL)
551     {
552         window_hash = x_hash_table_new (NULL, NULL, NULL, NULL);
553         pthread_mutex_init (&window_hash_mutex, NULL);
554     }
555
556     pthread_mutex_lock (&window_hash_mutex);
557     x_hash_table_insert (window_hash, (void *) winRec->wid, winRec);
558     pthread_mutex_unlock (&window_hash_mutex);
559
560     rootlessSetNativeProperty (winRec);
561
562     if (pShape != NULL)
563         REGION_UNINIT (pScreen, &shape);
564
565     return winRec;
566 }
567
568 /* The frame is usually created here and not in CreateWindow so that
569    windows do not eat memory until they are realized. */
570 Bool
571 RootlessRealizeWindow(WindowPtr pWin)
572 {
573     Bool result = FALSE;
574     RegionRec saveRoot;
575     ScreenPtr pScreen = pWin->drawable.pScreen;
576     XID pixel;
577
578     RL_DEBUG_MSG("realizewindow start (win 0x%x)\n", pWin);
579
580     if (IsTopLevel (pWin) && pWin->drawable.class == InputOutput)
581     {
582         RootlessWindowRec *winRec;
583
584         winRec = rootlessEnsureFrame (pWin);
585         if (winRec == NULL)
586             return NULL;
587
588         winRec->is_reorder_pending = TRUE;
589
590         /* Disallow ParentRelative background state on top-level windows.
591            This might have been set before the window was mapped. */
592
593         if (pWin->backgroundState == ParentRelative)
594         {
595             pixel = 0;
596             ChangeWindowAttributes (pWin, CWBackPixel, &pixel, serverClient);
597         }
598     }
599
600     if (!IsRoot(pWin)) HUGE_ROOT(pWin);
601     SCREEN_UNWRAP (pScreen, RealizeWindow);
602
603     result = pScreen->RealizeWindow (pWin);
604
605     SCREEN_WRAP (pScreen, RealizeWindow);
606     if (!IsRoot(pWin)) NORMAL_ROOT(pWin);
607
608     RL_DEBUG_MSG("realizewindow end\n");
609     return result;
610 }
611
612 void
613 RootlessEnableRoot (ScreenPtr pScreen)
614 {
615     WindowPtr pRoot;
616     pRoot = WindowTable[pScreen->myNum];
617
618     rootlessEnsureFrame (pRoot);
619     (*pScreen->ClearToBackground) (pRoot, 0, 0, 0, 0, TRUE);
620     RootlessReorderWindow (pRoot);
621 }
622
623 void
624 RootlessDisableRoot (ScreenPtr pScreen)
625 {
626     WindowPtr pRoot;
627     RootlessWindowRec *winRec;
628
629     pRoot = WindowTable[pScreen->myNum];
630     winRec = WINREC (pRoot);
631
632     if (winRec != NULL)
633     {
634         rootlessDestroyFrame (pRoot, winRec);
635         DeleteProperty (pRoot, xa_native_window_id ());
636     }
637 }
638
639 void
640 RootlessHideAllWindows (void)
641 {
642     int i;
643     ScreenPtr pScreen;
644     WindowPtr pWin;
645     RootlessWindowRec *winRec;
646     xp_window_changes wc;
647
648     if (windows_hidden)
649         return;
650
651     windows_hidden = TRUE;
652
653     for (i = 0; i < screenInfo.numScreens; i++)
654     {
655         pScreen = screenInfo.screens[i];
656         pWin = WindowTable[i];
657         if (pScreen == NULL || pWin == NULL)
658             continue;
659
660         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib)
661         {
662             if (!pWin->realized)
663                 continue;
664
665             RootlessStopDrawing (pWin, FALSE);
666
667             winRec = WINREC (pWin);
668             if (winRec != NULL)
669             {
670                 wc.stack_mode = XP_UNMAPPED;
671                 wc.sibling = 0;
672                 configure_window (winRec->wid, XP_STACKING, &wc);
673             }
674         }
675     }
676 }
677
678 void
679 RootlessShowAllWindows (void)
680 {
681     int i;
682     ScreenPtr pScreen;
683     WindowPtr pWin;
684     RootlessWindowRec *winRec;
685
686     if (!windows_hidden)
687         return;
688
689     windows_hidden = FALSE;
690
691     for (i = 0; i < screenInfo.numScreens; i++)
692     {
693         pScreen = screenInfo.screens[i];
694         pWin = WindowTable[i];
695         if (pScreen == NULL || pWin == NULL)
696             continue;
697
698         for (pWin = pWin->firstChild; pWin != NULL; pWin = pWin->nextSib)
699         {
700             if (!pWin->realized)
701                 continue;
702
703             winRec = rootlessEnsureFrame (pWin);
704             if (winRec == NULL)
705                 continue;
706
707             RootlessReorderWindow (pWin);
708         }
709
710         RootlessScreenExpose (pScreen);
711     }
712 }
713
714 void
715 RootlessSetWindowLevel (WindowPtr pWin, int level)
716 {
717     RootlessWindowRec *winRec;
718     xp_window_changes wc;
719
720     winRec = WINREC (pWin);
721     if (!IsTopLevel (pWin) || winRec == NULL || winRec->level == level)
722         return;
723
724     RootlessStopDrawing (pWin, FALSE);
725
726     winRec->level = level;
727
728     if (!rootlessHasRoot (pWin->drawable.pScreen))
729         wc.window_level = normal_window_levels[level];
730     else
731         wc.window_level = rooted_window_levels[level];
732
733     configure_window (winRec->wid, XP_WINDOW_LEVEL, &wc);
734 }
735
736 /* Return the id of the physical window displaying the given window. If
737    CREATE is true and the window has no frame, attempt to create one. */
738 xp_window_id
739 RootlessGetPhysicalWindow (WindowPtr pWin, Bool create)
740 {
741     RootlessWindowRec *winRec;
742
743     if (TopLevelParent (pWin) == NULL)
744         return 0;
745
746     winRec = WINREC (pWin);
747
748     if (winRec == NULL && create && !IsRoot (pWin)
749         && pWin->drawable.class == InputOutput)
750     {
751         rootlessEnsureFrame (pWin);
752         winRec = WINREC (pWin);
753     }
754
755     if (winRec == NULL)
756         return 0;
757
758     return winRec->wid;
759 }
760
761 /* Given the id of a physical window, try to find the top-level (or root)
762    X window that it represents. */
763 WindowPtr
764 RootlessGetXWindow (xp_window_id wid)
765 {
766     RootlessWindowRec *winRec;
767
768     if (window_hash == NULL)
769         return NULL;
770
771     winRec = x_hash_table_lookup (window_hash, (void *) wid, NULL);
772
773     return winRec != NULL ? winRec->win : NULL;
774 }
775
776 /* Number is an appkit window number. Returns true if X is displaying
777    a window with that number. */
778 int
779 RootlessKnowsWindowNumber (int number)
780 {
781     Bool ret;
782     xp_window_id wid;
783
784     /* need to lock, since this function can be called by any thread */
785
786     if (window_hash == NULL)
787         return FALSE;
788
789     pthread_mutex_lock (&window_hash_mutex);
790
791     if (xp_lookup_native_window (number, &wid))
792         ret = RootlessGetXWindow (wid) != NULL;
793     else
794         ret = FALSE;
795
796     pthread_mutex_unlock (&window_hash_mutex);
797
798     return ret;
799 }
800
801 Bool
802 RootlessUnrealizeWindow (WindowPtr pWin)
803 {
804     ScreenPtr pScreen = pWin->drawable.pScreen;
805     RootlessWindowRec *winRec = WINREC(pWin);
806     xp_window_changes wc;
807     Bool result;
808
809     RL_DEBUG_MSG("unrealizewindow start\n");
810
811     if (winRec != NULL)
812     {
813         RootlessStopDrawing (pWin, FALSE);
814
815         wc.stack_mode = XP_UNMAPPED;
816         wc.sibling = 0;
817
818         configure_window (winRec->wid, XP_STACKING, &wc);
819
820         winRec->unrealize_time = current_time_in_seconds ();
821         winRec->is_reorder_pending = FALSE;
822
823         RootlessReenableUpdate (pWin);
824     }
825
826     SCREEN_UNWRAP (pScreen, UnrealizeWindow);
827
828     result = pScreen->UnrealizeWindow (pWin);
829
830     SCREEN_WRAP (pScreen, UnrealizeWindow);
831
832     RL_DEBUG_MSG ("unrealizewindow end\n");
833     return result;
834 }
835
836 void
837 RootlessReparentWindow (WindowPtr pWin, WindowPtr pPriorParent)
838 {
839     ScreenPtr pScreen = pWin->drawable.pScreen;
840     RootlessWindowRec *winRec = WINREC (pWin);
841
842     WindowPtr pTopWin;
843
844     if (IsRoot (pWin) || IsRoot (pWin->parent)
845         || IsTopLevel (pWin) || winRec == NULL)
846     {
847         return;
848     }
849
850     /* If the window is moving upwards towards the root has a frame,
851        we want to try to move it onto its new toplevel parent. If we
852        can't do that, we'll just have to jettison it.. */
853
854     pTopWin = TopLevelParent (pWin);
855     assert (pTopWin != pWin);
856
857     pWin->rootlessUnhittable = FALSE;
858
859     DeleteProperty (pWin, xa_native_window_id ());
860
861     if (WINREC (pTopWin) != NULL)
862     {
863         /* We're screwed. */
864         rootlessDestroyFrame (pWin, winRec);
865     }
866     else
867     {
868         xp_window_changes wc;
869         int sx, sy;
870
871         if (!pTopWin->realized && pWin->realized)
872         {
873             wc.stack_mode = XP_UNMAPPED;
874             wc.sibling = 0;
875
876             RootlessStopDrawing (pWin, FALSE);
877             configure_window (winRec->wid, XP_STACKING, &wc);
878         }
879
880         /* Switch the frame record from one to the other. */
881
882         WINREC (pWin) = NULL;
883         WINREC (pTopWin) = winRec;
884
885         rootlessInitializeFrame (pTopWin, winRec);
886         rootlessSetShape (pTopWin);
887
888         sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX;
889         sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY;
890
891         wc.x = sx + winRec->x;
892         wc.y = sy + winRec->y;
893         wc.width = winRec->width;
894         wc.height = winRec->height;
895         wc.bit_gravity = XP_GRAVITY_NONE;
896
897         RootlessStopDrawing (pWin, FALSE);
898         configure_window (winRec->wid, XP_BOUNDS, &wc);
899
900         rootlessSetNativeProperty (winRec);
901
902         if (pTopWin->realized && !pWin->realized)
903             winRec->is_reorder_pending = TRUE;
904     }
905 }
906
907 /* Reorder the window associated with the given frame so that it's
908    physically above the window below it in the X stacking order. */
909 void
910 RootlessReorderWindow (WindowPtr pWin)
911 {
912     RootlessWindowRec *winRec = WINREC (pWin);
913
914     if (pWin->realized && winRec != NULL
915         && !winRec->is_reorder_pending && !windows_hidden)
916     {
917         WindowPtr newPrevW;
918         RootlessWindowRec *newPrev;
919         xp_window_changes wc;
920         Atom atom;
921         PropertyPtr prop;
922
923         /* quartz-wm sets the _APPLE_NO_ORDER_IN property on windows
924            that are being genie-restored from the Dock. We want them to
925            be mapped but remain ordered-out until the animation
926            completes (when the Dock will order them in) */
927
928         atom = xa_apple_no_order_in ();
929         for (prop = wUserProps (pWin); prop != NULL; prop = prop->next)
930         {
931             if (prop->propertyName == atom && prop->type == atom)
932                 return;
933         }
934
935         RootlessStopDrawing (pWin, FALSE);
936
937         if (IsRoot (pWin))
938         {
939             wc.stack_mode = XP_MAPPED_BELOW;
940             wc.sibling = 0;
941         }
942         else
943         {
944             /* Find the next window above this one that has a mapped frame. */
945
946             newPrevW = pWin->prevSib;
947             while (newPrevW
948                    && (WINREC (newPrevW) == NULL || !newPrevW->realized))
949             {
950                 newPrevW = newPrevW->prevSib;
951             }
952
953             newPrev = newPrevW != NULL ? WINREC (newPrevW) : NULL;
954
955             /* Then either stack ourselves below it if it exists, or raise
956                ourselves above everything otherwise. */
957
958             if (newPrev == NULL)
959             {
960                 wc.stack_mode = XP_MAPPED_ABOVE;
961                 wc.sibling = 0;
962             }
963             else
964             {
965                 if (newPrev->is_reorder_pending)
966                 {
967                     newPrev->is_reorder_pending = FALSE;
968                     RootlessReorderWindow (newPrevW);
969                 }
970
971                 wc.stack_mode = XP_MAPPED_BELOW;
972                 wc.sibling = newPrev->wid;
973             }
974         }
975
976         configure_window (winRec->wid, XP_STACKING, &wc);
977     }
978 }
979
980 void
981 RootlessRestackWindow (WindowPtr pWin, WindowPtr pOldNextSib)
982 {
983     RegionRec saveRoot;
984     RootlessWindowRec *winRec = WINREC (pWin);
985     ScreenPtr pScreen = pWin->drawable.pScreen;
986
987     RL_DEBUG_MSG("restackwindow start\n");
988     if (winRec != NULL)
989         RL_DEBUG_MSG("restack top level \n");
990
991     HUGE_ROOT(pWin);
992     SCREEN_UNWRAP(pScreen, RestackWindow);
993
994     if (pScreen->RestackWindow != NULL)
995         pScreen->RestackWindow (pWin, pOldNextSib);
996
997     SCREEN_WRAP(pScreen, RestackWindow);
998     NORMAL_ROOT(pWin);
999
1000     if (winRec != NULL && pWin->viewable)
1001         RootlessReorderWindow (pWin);
1002
1003     RL_DEBUG_MSG("restackwindow end\n");
1004 }
1005
1006 /*
1007  * Specialized window copy procedures
1008  */
1009
1010 /* Globals needed during window resize and move. */
1011 static pointer gResizeDeathBits = NULL;
1012 static int gResizeDeathCount;
1013 static PixmapPtr gResizeDeathPix[2];
1014 static BoxRec gResizeDeathBounds[2];
1015 static CopyWindowProcPtr gResizeOldCopyWindowProc = NULL;
1016
1017 /* CopyWindow () that doesn't do anything. For MoveWindow() of
1018    top-level windows. */
1019 static void
1020 RootlessNoCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
1021 {
1022     /* Some code expects the region to be translated */
1023
1024     int dx = ptOldOrg.x - pWin->drawable.x;
1025     int dy = ptOldOrg.y - pWin->drawable.y;
1026
1027     REGION_TRANSLATE (pWin->drawable.pScreen, prgnSrc, -dx, -dy);
1028 }
1029
1030 /* CopyWindow used during ResizeWindow for gravity moves. (from fbCopyWindow)
1031    The original always draws on the root pixmap (which we don't have).
1032    Instead, draw on the parent window's pixmap.
1033    Resize version: the old location's pixels are in gResizeCopyWindowSource */
1034 static void
1035 RootlessResizeCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg,
1036                           RegionPtr prgnSrc)
1037 {
1038     ScreenPtr pScreen = pWin->drawable.pScreen;
1039     RegionRec rgnDst;
1040     int dx, dy;
1041
1042     RL_DEBUG_MSG("resizecopywindowFB start (win 0x%x)\n", pWin);
1043
1044     /* Don't unwrap pScreen->CopyWindow.
1045        The bogus rewrap with RootlessCopyWindow causes a crash if
1046        CopyWindow is called again during the same resize. */
1047
1048     if (gResizeDeathCount == 0)
1049         return;
1050
1051     RootlessStartDrawing (pWin);
1052
1053     dx = ptOldOrg.x - pWin->drawable.x;
1054     dy = ptOldOrg.y - pWin->drawable.y;
1055     REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
1056     REGION_INIT (pScreen, &rgnDst, NullBox, 0);
1057     REGION_INTERSECT (pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
1058
1059     if (gResizeDeathCount == 1)
1060     {
1061         /* Simple case, we only have a single source pixmap. */
1062
1063         fbCopyRegion (&gResizeDeathPix[0]->drawable,
1064                       &pScreen->GetWindowPixmap(pWin)->drawable, 0,
1065                       &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
1066     }
1067     else
1068     {
1069         int i;
1070         RegionRec clip, clipped;
1071
1072         /* More complex case, N source pixmaps (usually two). So we
1073            intersect the destination with each source and copy those bits. */
1074
1075         for (i = 0; i < gResizeDeathCount; i++)
1076         {
1077             REGION_INIT (pScreen, &clip, gResizeDeathBounds + 0, 1);
1078             REGION_INIT (pScreen, &clipped, NullBox, 0);
1079             REGION_INTERSECT (pScreen, &rgnDst, &clip, &clipped);
1080
1081             fbCopyRegion (&gResizeDeathPix[i]->drawable,
1082                            &pScreen->GetWindowPixmap(pWin)->drawable, 0,
1083                            &clipped, dx, dy, fbCopyWindowProc, 0, 0);
1084
1085             REGION_UNINIT (pScreen, &clipped);
1086             REGION_UNINIT (pScreen, &clip);
1087         }
1088     }
1089         
1090     /* Don't update - resize will update everything */
1091     REGION_UNINIT (pScreen, &rgnDst);
1092
1093     fbValidateDrawable (&pWin->drawable);
1094
1095     RL_DEBUG_MSG("resizecopywindowFB end\n");
1096 }
1097
1098 /* Update *new* location of window. Old location is redrawn with
1099    PaintWindowBackground/Border. Cloned from fbCopyWindow
1100    The original always draws on the root pixmap (which we don't have).
1101    Instead, draw on the parent window's pixmap. */
1102 void
1103 RootlessCopyWindow (WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
1104 {
1105     ScreenPtr pScreen = pWin->drawable.pScreen;
1106     RootlessWindowRec *winRec;
1107     WindowPtr top;
1108
1109     RegionRec rgnDst;
1110     int dx, dy;
1111     BoxPtr extents;
1112     unsigned int area;
1113
1114     RL_DEBUG_MSG("copywindowFB start (win 0x%x)\n", pWin);
1115
1116     top = TopLevelParent (pWin);
1117     if (top == NULL)
1118     {
1119         RL_DEBUG_MSG("no parent\n");
1120         return;
1121     }
1122
1123     winRec = WINREC(top);
1124     if (winRec == NULL)
1125     {
1126         RL_DEBUG_MSG("not framed\n");
1127         return;
1128     }
1129
1130     SCREEN_UNWRAP (pScreen, CopyWindow);
1131
1132     dx = ptOldOrg.x - pWin->drawable.x;
1133     dy = ptOldOrg.y - pWin->drawable.y;
1134     REGION_TRANSLATE (pScreen, prgnSrc, -dx, -dy);
1135
1136     REGION_INIT (pScreen, &rgnDst, NullBox, 0);
1137     REGION_INTERSECT (pScreen, &rgnDst, &pWin->borderClip, prgnSrc);
1138
1139     extents = REGION_EXTENTS (pScreen, &rgnDst);
1140     area = (extents->x2 - extents->x1) * (extents->y2 - extents->y1);
1141
1142     if (area > xp_scroll_area_threshold)
1143     {
1144         /* Move region to window local coords */
1145         REGION_TRANSLATE (pScreen, &rgnDst, -winRec->x, -winRec->y);
1146
1147         RootlessStopDrawing (pWin, FALSE);
1148
1149         xp_copy_window (winRec->wid, winRec->wid,
1150                         REGION_NUM_RECTS (&rgnDst),
1151                         REGION_RECTS (&rgnDst), dx, dy);
1152     }
1153     else
1154     {
1155         RootlessStartDrawing (pWin);
1156
1157         fbCopyRegion ((DrawablePtr) pWin, (DrawablePtr) pWin,
1158                       0, &rgnDst, dx, dy, fbCopyWindowProc, 0, 0);
1159
1160         /* prgnSrc has been translated to dst position */
1161         RootlessDamageRegion(pWin, prgnSrc);
1162     }
1163
1164     REGION_UNINIT (pScreen, &rgnDst);
1165     fbValidateDrawable (&pWin->drawable);
1166         
1167     SCREEN_WRAP (pScreen, CopyWindow);
1168
1169     RL_DEBUG_MSG("copywindowFB end\n");
1170 }
1171
1172 /*
1173  * Window resize procedures
1174  */
1175
1176 enum {
1177     WIDTH_SMALLER = 1,
1178     HEIGHT_SMALLER = 2,
1179 };
1180
1181 /* Compute which directions the window is resizing in. */
1182 static inline unsigned int
1183 resize_code (int oldX, int oldY, int oldW, int oldH,
1184              int newX, int newY, int newW, int newH)
1185 {
1186     unsigned int code = 0;
1187
1188     /* These comparisons were chosen to avoid setting bits when the sizes
1189        are the same. (So the fastest case automatically gets taken when
1190        dimensions are unchanging.) */
1191
1192     if (newW < oldW)
1193         code |= WIDTH_SMALLER;
1194
1195     if (newH < oldH)
1196         code |= HEIGHT_SMALLER;
1197
1198     return code;
1199 }
1200
1201 static inline unsigned int
1202 resize_weighting (int oldX1, int oldY1, int oldX2, int oldY2, int oldBW,
1203                   int newX1, int newY1, int newX2, int newY2, int newBW)
1204 {
1205     /* Choose gravity to avoid local copies. Do that by looking for
1206        a corner that doesn't move _relative to the screen_  */
1207
1208     if (newBW != oldBW)
1209         return XP_GRAVITY_NONE;
1210
1211     if (newX1 == oldX1 && newY1 == oldY1)
1212         return XP_GRAVITY_NORTH_WEST;
1213     else if (newX1 == oldX1 && newY2 == oldY2)
1214         return XP_GRAVITY_SOUTH_WEST;
1215     else if (newX2 == oldX2 && newY2 == oldY2)
1216         return XP_GRAVITY_SOUTH_EAST;
1217     else if (newX2 == oldX2 && newY1 == oldY1)
1218         return XP_GRAVITY_NORTH_EAST;
1219     else
1220         return XP_GRAVITY_NONE;
1221 }
1222
1223 /* Resize the given window to its new position and size. */
1224 static void
1225 resize_frame (ScreenPtr pScreen, WindowPtr pWin,
1226               RootlessWindowRec *winRec, int gravity)
1227 {
1228     int sx, sy;
1229     xp_window_changes wc;
1230
1231     sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX;
1232     sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY;
1233
1234     wc.x = sx + winRec->x;
1235     wc.y = sy + winRec->y;
1236     wc.width = winRec->width;
1237     wc.height = winRec->height;
1238     wc.bit_gravity = gravity;
1239
1240     /* It's unlikely that being async will save us anything here.
1241        But it can't hurt. */
1242
1243     configure_window (winRec->wid, XP_BOUNDS, &wc);
1244 }
1245
1246 /* Prepare to resize a top-level window. The old window's pixels are
1247    saved and the implementation is told to change the window size.
1248    (x,y,w,h) is outer frame of window (outside border) */
1249 static Bool
1250 StartFrameResize (WindowPtr pWin, Bool gravity,
1251                   int oldX, int oldY, int oldW, int oldH, int oldBW,
1252                   int newX, int newY, int newW, int newH, int newBW)
1253 {
1254     ScreenPtr pScreen = pWin->drawable.pScreen;
1255     RootlessWindowRec *winRec = WINREC(pWin);
1256     Bool need_window_source = FALSE, resize_after = FALSE;
1257
1258     BoxRec rect, copy_rect;
1259     int oldX2, newX2;
1260     int oldY2, newY2;
1261     unsigned int weight;
1262
1263     oldX2 = oldX + oldW, newX2 = newX + newW;
1264     oldY2 = oldY + oldH, newY2 = newY + newH;
1265
1266     /* Decide which resize weighting to use */
1267     weight = resize_weighting (oldX, oldY, oldW, oldH, oldBW,
1268                                newX, newY, newW, newH, newBW);
1269
1270     /* Compute intersection between old and new rects */
1271     rect.x1 = max(oldX, newX);
1272     rect.y1 = max(oldY, newY);
1273     rect.x2 = min(oldX2, newX2);
1274     rect.y2 = min(oldY2, newY2);
1275
1276     RL_DEBUG_MSG("RESIZE TOPLEVEL WINDOW with gravity %i ", gravity);
1277     RL_DEBUG_MSG("%d %d %d %d %d   %d %d %d %d %d\n",
1278                  oldX, oldY, oldW, oldH, oldBW,
1279                  newX, newY, newW, newH, newBW);
1280
1281     RootlessDisableUpdate (pWin);
1282     RootlessRedisplay (pWin);
1283
1284     /* If gravity is true, then we need to have a way of recovering all
1285        the original bits in the window for when X rearranges the contents
1286        based on the various gravity settings. The obvious way is to just
1287        snapshot the entire backing store before resizing it, but that
1288        it slow on large windows.
1289        
1290        So the optimization here is to use CG's resize weighting options
1291        to allow us to reason about what is left in the backing store
1292        after the resize. We can then only copy what won't be there after
1293        the resize, and do a two-stage copy operation.
1294
1295        Most of these optimizations are only applied when the top-left
1296        corner of the window is fixed, since that's the common case. They
1297        could probably be extended with some thought. */
1298
1299     gResizeDeathCount = 0;
1300
1301     if (gravity && weight == XP_GRAVITY_NORTH_WEST)
1302     {
1303         unsigned int code;
1304
1305         /* Top left corner is anchored. We never need to copy the
1306            entire window. */
1307
1308         need_window_source = TRUE;
1309
1310         code = resize_code (oldX, oldY, oldW, oldH,
1311                             newX, newY, newW, newH);
1312
1313         if (((code ^ (code >> 1)) & 1) == 0)
1314         {
1315             /* Both dimensions are either getting larger, or both
1316                are getting smaller. No need to copy anything. */
1317
1318             if (code == (WIDTH_SMALLER | HEIGHT_SMALLER))
1319             {
1320                 /* Since the window is getting smaller, we can do gravity
1321                    repair on it with it's current size, then resize it
1322                    afterwards. */
1323
1324                 resize_after = TRUE;
1325             }
1326
1327             gResizeDeathCount = 1;
1328         }
1329         else
1330         {
1331             unsigned int copy_rowbytes, Bpp;
1332
1333             /* We can get away with a partial copy. 'rect' is the
1334                intersection between old and new bounds, so copy
1335                everything to the right of or below the intersection. */
1336
1337             RootlessStartDrawing (pWin);
1338
1339             if (code == WIDTH_SMALLER)
1340             {
1341                 copy_rect.x1 = rect.x2;
1342                 copy_rect.y1 = rect.y1;
1343                 copy_rect.x2 = oldX2;
1344                 copy_rect.y2 = oldY2;
1345             }
1346             else if (code == HEIGHT_SMALLER)
1347             {
1348                 copy_rect.x1 = rect.x1;
1349                 copy_rect.y1 = rect.y2;
1350                 copy_rect.x2 = oldX2;
1351                 copy_rect.y2 = oldY2;
1352             }
1353             else
1354                 abort ();
1355
1356             Bpp = winRec->win->drawable.bitsPerPixel / 8;
1357             copy_rowbytes = (((copy_rect.x2 - copy_rect.x1) * Bpp) + 31) & ~31;
1358             gResizeDeathBits = xalloc (copy_rowbytes
1359                                        * (copy_rect.y2 - copy_rect.y1));
1360
1361             xp_copy_bytes ((copy_rect.x2 - copy_rect.x1) * Bpp,
1362                            copy_rect.y2 - copy_rect.y1, ((char *) winRec->data)
1363                            + ((copy_rect.y1 - oldY) * winRec->rowbytes)
1364                            + (copy_rect.x1 - oldX) * Bpp, winRec->rowbytes,
1365                            gResizeDeathBits, copy_rowbytes);
1366             
1367             gResizeDeathBounds[1] = copy_rect;
1368             gResizeDeathPix[1]
1369                 = GetScratchPixmapHeader(pScreen, copy_rect.x2 - copy_rect.x1,
1370                                          copy_rect.y2 - copy_rect.y1,
1371                                          winRec->win->drawable.depth,
1372                                          winRec->win->drawable.bitsPerPixel,
1373                                          winRec->rowbytes,
1374                                          (void *) gResizeDeathBits);
1375
1376             TranslatePixmapBase (gResizeDeathPix[1],
1377                                  -copy_rect.x1, -copy_rect.y1);
1378
1379             gResizeDeathCount = 2;
1380         }
1381     }
1382     else if (gravity)
1383     {
1384         /* The general case. Just copy everything. */
1385
1386         RootlessStartDrawing (pWin);
1387
1388         gResizeDeathBits = xalloc(winRec->rowbytes * winRec->height);
1389
1390         memcpy(gResizeDeathBits, winRec->data,
1391                winRec->rowbytes * winRec->height);
1392
1393         gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
1394         gResizeDeathPix[0]
1395             = GetScratchPixmapHeader(pScreen, winRec->width,
1396                                      winRec->height,
1397                                      winRec->win->drawable.depth,
1398                                      winRec->win->drawable.bitsPerPixel,
1399                                      winRec->rowbytes,
1400                                      (void *) gResizeDeathBits);
1401
1402         TranslatePixmapBase (gResizeDeathPix[0], -oldX, -oldY);
1403         gResizeDeathCount = 1;
1404     }
1405
1406     RootlessStopDrawing (pWin, FALSE);
1407
1408     winRec->x = newX;
1409     winRec->y = newY;
1410     winRec->width = newW;
1411     winRec->height = newH;
1412     winRec->borderWidth = newBW;
1413
1414     /* Unless both dimensions are getting smaller, Resize the frame
1415        before doing gravity repair */
1416
1417     if (!resize_after)
1418         resize_frame (pScreen, pWin, winRec, weight);
1419
1420     RootlessStartDrawing(pWin);
1421
1422     /* If necessary, create a source pixmap pointing at the current
1423        window bits. */
1424
1425     if (need_window_source)
1426     {
1427         gResizeDeathBounds[0] = (BoxRec) {oldX, oldY, oldX2, oldY2};
1428         gResizeDeathPix[0]
1429             = GetScratchPixmapHeader (pScreen, oldW, oldH,
1430                                       winRec->win->drawable.depth,
1431                                       winRec->win->drawable.bitsPerPixel,
1432                                       winRec->rowbytes, winRec->data);
1433
1434         TranslatePixmapBase (gResizeDeathPix[0], -oldX, -oldY);
1435     }
1436
1437     /* Use custom CopyWindow when moving gravity bits around
1438        ResizeWindow assumes the old window contents are in the same
1439        pixmap, but here they're in deathPix instead. */
1440
1441     if (gravity)
1442     {
1443         gResizeOldCopyWindowProc = pScreen->CopyWindow;
1444         pScreen->CopyWindow = RootlessResizeCopyWindow;
1445     }
1446
1447     /* If we can't rely on the window server preserving the bits we
1448        need in the position we need, copy the pixels in the
1449        intersection from src to dst. ResizeWindow assumes these pixels
1450        are already present when making gravity adjustments. pWin
1451        currently has new-sized pixmap but is in old position.
1452
1453        FIXME: border width change! (?) */
1454
1455     if (gravity && weight == XP_GRAVITY_NONE)
1456     {
1457         PixmapPtr src, dst;
1458
1459         assert (gResizeDeathCount == 1);
1460
1461         src = gResizeDeathPix[0];
1462         dst = pScreen->GetWindowPixmap(pWin);
1463
1464         RL_DEBUG_MSG("Resize copy rect %d %d %d %d\n",
1465                      rect.x1, rect.y1, rect.x2, rect.y2);
1466
1467         /* rect is the intersection of the old location and new location */
1468         if (BOX_NOT_EMPTY(rect) && src != NULL && dst != NULL)
1469         {
1470             int dx, dy;
1471
1472             /* The window drawable still has the old frame position, which
1473                means that DST doesn't actually point at the origin of our
1474                physical backing store when adjusted by the drawable.x,y
1475                position. So sneakily adjust it temporarily while copying.. */
1476
1477             dx = newX - oldX;
1478             dy = newY - oldY;
1479             TranslatePixmapBase (dst, -dx, -dy);
1480
1481             fbCopyWindowProc(&src->drawable, &dst->drawable, NULL,
1482                              &rect, 1, 0, 0, FALSE, FALSE, 0, 0);
1483
1484             TranslatePixmapBase (dst, dx, dy);
1485         }
1486     }
1487
1488     return resize_after;
1489 }
1490
1491 static void
1492 FinishFrameResize (WindowPtr pWin, Bool gravity, int oldX, int oldY,
1493                   unsigned int oldW, unsigned int oldH, unsigned int oldBW,
1494                   int newX, int newY, unsigned int newW, unsigned int newH,
1495                   unsigned int newBW, Bool resize_now)
1496 {
1497     ScreenPtr pScreen = pWin->drawable.pScreen;
1498     RootlessWindowRec *winRec = WINREC(pWin);
1499     BoxRec box;
1500     int i;
1501
1502     RootlessStopDrawing (pWin, FALSE);
1503
1504     if (resize_now)
1505     {
1506         unsigned int weight;
1507
1508         /* We didn't resize anything earlier, so do it now, now that
1509            we've finished gravitating the bits. */
1510
1511         weight = resize_weighting (oldX, oldY, oldW, oldH, oldBW,
1512                                    newX, newY, newW, newH, newBW);
1513
1514         resize_frame (pScreen, pWin, winRec, weight);
1515     }
1516
1517     /* Redraw everything. FIXME: there must be times when we don't need
1518        to do this. Perhaps when top-left weighting and no gravity? */
1519
1520     box.x1 = 0;
1521     box.y1 = 0;
1522     box.x2 = winRec->width;
1523     box.y2 = winRec->height;
1524
1525     xp_mark_window (winRec->wid, 1, &box, 0, 0);
1526
1527     for (i = 0; i < 2; i++)
1528     {
1529         if (gResizeDeathPix[i] != NULL)
1530         {
1531             FreeScratchPixmapHeader (gResizeDeathPix[i]);
1532             gResizeDeathPix[i] = NULL;
1533         }
1534     }
1535
1536     if (gResizeDeathBits != NULL)
1537     {
1538         xfree (gResizeDeathBits);
1539         gResizeDeathBits = NULL;
1540     }
1541
1542     if (gravity)
1543         pScreen->CopyWindow = gResizeOldCopyWindowProc;
1544 }
1545
1546 /* If kind==VTOther, window border is resizing (and borderWidth is
1547    already changed!!@#$)  This case works like window resize, not move. */
1548 void
1549 RootlessMoveWindow (WindowPtr pWin, int x, int y, WindowPtr pSib, VTKind kind)
1550 {
1551     RootlessWindowRec *winRec = WINREC(pWin);
1552     ScreenPtr pScreen = pWin->drawable.pScreen;
1553     CopyWindowProcPtr oldCopyWindowProc = NULL;
1554
1555     int oldX = 0, oldY = 0;
1556     unsigned int oldW = 0, oldH = 0, oldBW = 0;
1557     int newX = 0, newY = 0;
1558     unsigned int newW = 0, newH = 0, newBW = 0;
1559
1560     Bool resize_after = FALSE;
1561     RegionRec saveRoot;
1562
1563     RL_DEBUG_MSG("movewindow start \n");
1564
1565     if (winRec != NULL)
1566     {
1567         if (kind == VTMove)
1568         {
1569             oldX = winRec->x;
1570             oldY = winRec->y;
1571             RootlessRedisplay (pWin);
1572             RootlessStartDrawing (pWin);
1573         }
1574         else
1575         {
1576             RL_DEBUG_MSG("movewindow border resizing ");
1577
1578             oldBW = winRec->borderWidth;
1579             oldX = winRec->x;
1580             oldY = winRec->y;
1581             oldW = winRec->width;
1582             oldH = winRec->height;
1583
1584             newBW = wBorderWidth (pWin);
1585             newX = x;
1586             newY = y;
1587             newW = pWin->drawable.width  + 2*newBW;
1588             newH = pWin->drawable.height + 2*newBW;
1589
1590             resize_after = StartFrameResize (pWin, FALSE,
1591                                              oldX, oldY, oldW, oldH, oldBW,
1592                                              newX, newY, newW, newH, newBW);
1593         }
1594     }
1595
1596     HUGE_ROOT (pWin);
1597     SCREEN_UNWRAP (pScreen, MoveWindow);
1598
1599     oldCopyWindowProc = pScreen->CopyWindow;
1600
1601     if (winRec != NULL)
1602         pScreen->CopyWindow = RootlessNoCopyWindow;
1603
1604     pScreen->MoveWindow (pWin, x, y, pSib, kind);
1605
1606     if (winRec != NULL)
1607         pScreen->CopyWindow = oldCopyWindowProc;
1608
1609     NORMAL_ROOT (pWin);
1610     SCREEN_WRAP (pScreen, MoveWindow);
1611
1612     if (winRec != NULL)
1613     {
1614         if (kind == VTMove)
1615         {
1616             xp_window_changes wc;
1617             int sx, sy;
1618
1619             RootlessStopDrawing (pWin, FALSE);
1620
1621             winRec->x = x;
1622             winRec->y = y;
1623
1624             sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX;
1625             sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY;
1626
1627             wc.x = sx + winRec->x;
1628             wc.y = sy + winRec->y;
1629
1630             configure_window (winRec->wid, XP_ORIGIN, &wc);
1631         }
1632         else
1633         {
1634             FinishFrameResize (pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1635                                newX, newY, newW, newH, newBW, resize_after);
1636         }
1637     }
1638
1639     RL_DEBUG_MSG("movewindow end\n");
1640 }
1641
1642
1643 /* Note: (x, y, w, h) as passed to this procedure don't match the frame
1644    definition. (x,y) is corner of very outer edge, *outside* border
1645    w,h is width and height *inside* border, *ignoring* border width
1646    The rect (x, y, w, h) doesn't mean anything. (x, y, w+2*bw, h+2*bw)
1647    is total rect (x+bw, y+bw, w, h) is inner rect */
1648 void
1649 RootlessResizeWindow (WindowPtr pWin, int x, int y,
1650                       unsigned int w, unsigned int h, WindowPtr pSib)
1651 {
1652     RootlessWindowRec *winRec = WINREC(pWin);
1653     ScreenPtr pScreen = pWin->drawable.pScreen;
1654     RegionRec saveRoot;
1655
1656     int oldX = 0, oldY = 0;
1657     unsigned int oldW = 0, oldH = 0, oldBW = 0;
1658     int newX = 0, newY = 0;
1659     unsigned int newW = 0, newH = 0, newBW = 0;
1660
1661     Bool resize_after = FALSE;
1662
1663     RL_DEBUG_MSG("resizewindow start (win 0x%x)\n", pWin);
1664
1665     if (winRec != NULL)
1666     {
1667         oldBW = winRec->borderWidth;
1668         oldX = winRec->x;
1669         oldY = winRec->y;
1670         oldW = winRec->width;
1671         oldH = winRec->height;
1672
1673         newBW = oldBW;
1674         newX = x;
1675         newY = y;
1676         newW = w + 2*newBW;
1677         newH = h + 2*newBW;
1678
1679         resize_after = StartFrameResize (pWin, TRUE,
1680                                          oldX, oldY, oldW, oldH, oldBW,
1681                                          newX, newY, newW, newH, newBW);
1682     }
1683
1684     HUGE_ROOT (pWin);
1685     SCREEN_UNWRAP (pScreen, ResizeWindow);
1686
1687     if (!IsRoot (pWin))
1688     {
1689         pScreen->ResizeWindow (pWin, x, y, w, h, pSib);
1690     }
1691     else
1692     {
1693         BoxRec box;
1694
1695         /* mi won't resize the root. So do it ourselves... */
1696
1697         pWin->drawable.x = x;
1698         pWin->drawable.y = y;
1699         pWin->drawable.width = w;
1700         pWin->drawable.height = h;
1701
1702         box.x1 = x; box.y1 = y;
1703         box.x2 = x + w; box.y2 = y + h;
1704         REGION_UNINIT (pScreen, &pWin->winSize);
1705         REGION_INIT (pScreen, &pWin->winSize, &box, 1);
1706         REGION_COPY (pScreen, &pWin->borderSize, &pWin->winSize);
1707         REGION_COPY (pScreen, &pWin->clipList, &pWin->winSize);
1708         REGION_COPY (pScreen, &pWin->borderClip, &pWin->winSize);
1709
1710         miSendExposures (pWin, &pWin->borderClip,
1711                          pWin->drawable.x, pWin->drawable.y);
1712     }
1713
1714     SCREEN_WRAP (pScreen, ResizeWindow);
1715     NORMAL_ROOT (pWin);
1716
1717     if (winRec != NULL)
1718     {
1719         FinishFrameResize (pWin, TRUE, oldX, oldY, oldW, oldH, oldBW,
1720                            newX, newY, newW, newH, newBW, resize_after);
1721     }
1722
1723     RL_DEBUG_MSG("resizewindow end\n");
1724 }
1725
1726 void
1727 RootlessRepositionWindow (WindowPtr pWin)
1728 {
1729     RootlessWindowRec *winRec = WINREC (pWin);
1730     ScreenPtr pScreen = pWin->drawable.pScreen;
1731     xp_window_changes wc;
1732     int sx, sy;
1733
1734     if (IsRoot (pWin))
1735         set_screen_origin (pWin);
1736
1737     if (winRec == NULL)
1738         return;
1739
1740     RootlessStopDrawing (pWin, FALSE);
1741
1742     sx = dixScreenOrigins[pScreen->myNum].x + darwinMainScreenX;
1743     sy = dixScreenOrigins[pScreen->myNum].y + darwinMainScreenY;
1744
1745     wc.x = sx + winRec->x;
1746     wc.y = sy + winRec->y;
1747
1748     if (!rootlessHasRoot (pScreen))
1749         wc.window_level = normal_window_levels[winRec->level];
1750     else
1751         wc.window_level = rooted_window_levels[winRec->level];
1752
1753     configure_window (winRec->wid, XP_ORIGIN | XP_WINDOW_LEVEL, &wc);
1754
1755     RootlessReorderWindow (pWin);
1756 }
1757
1758 void
1759 RootlessFlushWindowColormap (WindowPtr pWin)
1760 {
1761     RootlessWindowRec *winRec = WINREC (pWin);
1762     xp_window_changes wc;
1763
1764     if (winRec == NULL)
1765         return;
1766
1767     RootlessStopDrawing (pWin, FALSE);
1768
1769     /* This is how we tell xp that the colormap may have changed. */
1770
1771     wc.colormap = rootlessColormapCallback;
1772     wc.colormap_data = pWin->drawable.pScreen;
1773
1774     configure_window (winRec->wid, XP_COLORMAP, &wc);
1775 }
1776
1777 /* Set the Pixmaps on all ParentRelative windows up the ancestor chain. */
1778 static void
1779 SetPixmapOfAncestors (WindowPtr pWin)
1780 {
1781     ScreenPtr pScreen = pWin->drawable.pScreen;
1782     WindowPtr topWin = TopLevelParent (pWin);
1783     RootlessWindowRec *topWinRec = WINREC (topWin);
1784     XID pixel;
1785
1786     while (pWin->backgroundState == ParentRelative)
1787     {
1788         if (pWin == topWin)
1789         {
1790             /* disallow ParentRelative background state on top level */
1791
1792             pixel = 0;
1793             ChangeWindowAttributes(pWin, CWBackPixel, &pixel, serverClient);
1794
1795             RL_DEBUG_MSG("Cleared ParentRelative on 0x%x.\n", pWin);
1796             break;
1797         }
1798
1799         pWin = pWin->parent;
1800         pScreen->SetWindowPixmap (pWin, topWinRec->pixmap);
1801     }
1802 }
1803
1804 /* RootlessPaintWindowBackground
1805    Paint the window background while filling in the alpha channel
1806    with all on. */
1807 void
1808 RootlessPaintWindowBackground (WindowPtr pWin, RegionPtr pRegion, int what)
1809 {
1810     ScreenPtr pScreen = pWin->drawable.pScreen;
1811
1812     SCREEN_UNWRAP (pScreen, PaintWindowBackground);
1813
1814     RL_DEBUG_MSG("paintwindowbackground start (win 0x%x, framed %i)\n",
1815                  pWin, IsFramedWindow(pWin));
1816
1817     if (IsFramedWindow (pWin))
1818     {
1819         /* Don't bother trying to paint the surface background.. */
1820         rootlessNoDRIDrawing++;
1821
1822         RootlessStartDrawing (pWin);
1823         RootlessDamageRegion (pWin, pRegion);
1824
1825         /* For ParentRelative windows, we have to make sure the window
1826            pixmap is set correctly all the way up the ancestor chain. */
1827
1828         if (pWin->backgroundState == ParentRelative)
1829             SetPixmapOfAncestors (pWin);
1830
1831         pScreen->PaintWindowBackground (pWin, pRegion, what);
1832
1833         rootlessNoDRIDrawing--;
1834     }
1835
1836     SCREEN_WRAP (pScreen, PaintWindowBackground);
1837
1838     RL_DEBUG_MSG("paintwindowbackground end\n");
1839 }
1840
1841
1842 /* RootlessPaintWindowBorder
1843    Paint the window border while filling in the alpha channel with all on. */
1844 void
1845 RootlessPaintWindowBorder (WindowPtr pWin, RegionPtr pRegion, int what)
1846 {
1847     SCREEN_UNWRAP (pWin->drawable.pScreen, PaintWindowBorder);
1848
1849     RL_DEBUG_MSG("paintwindowborder start (win 0x%x)\n", pWin);
1850
1851     if (IsFramedWindow (pWin))
1852     {
1853         RootlessStartDrawing (pWin);
1854         RootlessDamageRegion (pWin, pRegion);
1855
1856         /* For ParentRelative windows with tiled borders, we have to make
1857            sure the window pixmap is set correctly all the way up the
1858            ancestor chain. */
1859
1860         if (!pWin->borderIsPixel && pWin->backgroundState == ParentRelative)
1861             SetPixmapOfAncestors (pWin);
1862     }
1863
1864     pWin->drawable.pScreen->PaintWindowBorder (pWin, pRegion, what);
1865
1866     SCREEN_WRAP (pWin->drawable.pScreen, PaintWindowBorder);
1867
1868     RL_DEBUG_MSG("paintwindowborder end\n");
1869 }
1870
1871
1872 /* FIXME: untested!
1873    pWin inside corner stays the same; pWin->drawable.[xy] stays the same
1874    frame moves and resizes */
1875 void
1876 RootlessChangeBorderWidth (WindowPtr pWin, unsigned int width)
1877 {
1878     RegionRec saveRoot;
1879     Bool resize_after = FALSE;
1880
1881     RL_DEBUG_MSG("change border width\n");
1882
1883     if ((int) width != wBorderWidth (pWin))
1884     {
1885         RootlessWindowRec *winRec = WINREC(pWin);
1886
1887         int oldX = 0, oldY = 0, newX = 0, newY = 0;
1888         unsigned int oldW = 0, oldH = 0, oldBW = 0;
1889         unsigned int newW = 0, newH = 0, newBW = 0;
1890
1891         if (winRec != NULL)
1892         {
1893             oldBW = winRec->borderWidth;
1894             oldX = winRec->x;
1895             oldY = winRec->y;
1896             oldW = winRec->width;
1897             oldH = winRec->height;
1898
1899             newBW = width;
1900             newX = pWin->drawable.x - newBW;
1901             newY = pWin->drawable.y - newBW;
1902             newW = pWin->drawable.width  + 2*newBW;
1903             newH = pWin->drawable.height + 2*newBW;
1904
1905             resize_after = StartFrameResize (pWin, FALSE,
1906                                              oldX, oldY, oldW, oldH, oldBW,
1907                                              newX, newY, newW, newH, newBW);
1908         }
1909
1910         HUGE_ROOT (pWin);
1911         SCREEN_UNWRAP (pWin->drawable.pScreen, ChangeBorderWidth);
1912
1913         pWin->drawable.pScreen->ChangeBorderWidth (pWin, width);
1914
1915         SCREEN_WRAP (pWin->drawable.pScreen, ChangeBorderWidth);
1916         NORMAL_ROOT (pWin);
1917
1918         if (winRec != NULL)
1919         {
1920             FinishFrameResize (pWin, FALSE, oldX, oldY, oldW, oldH, oldBW,
1921                                newX, newY, newW, newH, newBW, resize_after);
1922         }
1923     }
1924
1925     RL_DEBUG_MSG("change border width end\n");
1926 }
1927
1928 /*
1929  * RootlessFillRegionTiled
1930  *  Fill using a tile while leaving the alpha channel untouched.
1931  *  Based on fbfillRegionTiled.
1932  */
1933 static void
1934 RootlessFillRegionTiled(
1935     DrawablePtr pDrawable,
1936     RegionPtr   pRegion,
1937     PixmapPtr   pTile)
1938 {
1939     FbBits      *dst;
1940     FbStride    dstStride;
1941     int         dstBpp;
1942     int         dstXoff, dstYoff;
1943     FbBits      *tile;
1944     FbStride    tileStride;
1945     int         tileBpp;
1946     int         tileXoff, tileYoff; /* XXX assumed to be zero */
1947     int         tileWidth, tileHeight;
1948     int         n = REGION_NUM_RECTS(pRegion);
1949     BoxPtr      pbox = REGION_RECTS(pRegion);
1950     int         xRot = pDrawable->x;
1951     int         yRot = pDrawable->y;
1952     FbBits      planeMask;
1953
1954 #ifdef PANORAMIX
1955     if(!noPanoramiXExtension)
1956     {
1957         int index = pDrawable->pScreen->myNum;
1958         if(&WindowTable[index]->drawable == pDrawable)
1959         {
1960             xRot -= panoramiXdataPtr[index].x;
1961             yRot -= panoramiXdataPtr[index].y;
1962         }
1963     }
1964 #endif
1965     fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
1966     fbGetDrawable (&pTile->drawable, tile, tileStride, tileBpp,
1967                    tileXoff, tileYoff);
1968     tileWidth = pTile->drawable.width;
1969     tileHeight = pTile->drawable.height;
1970     xRot += dstXoff;
1971     yRot += dstYoff;
1972     planeMask = FB_ALLONES & ~RootlessAlphaMask(dstBpp);
1973
1974     while (n--)
1975     {
1976         fbTile (dst + (pbox->y1 + dstYoff) * dstStride,
1977                 dstStride,
1978                 (pbox->x1 + dstXoff) * dstBpp,
1979                 (pbox->x2 - pbox->x1) * dstBpp,
1980                 pbox->y2 - pbox->y1,
1981                 tile,
1982                 tileStride,
1983                 tileWidth * dstBpp,
1984                 tileHeight,
1985                 GXcopy,
1986                 planeMask,
1987                 dstBpp,
1988                 xRot * dstBpp,
1989                 yRot - pbox->y1);
1990         pbox++;
1991     }
1992 }
1993
1994 /*
1995  * RootlessPaintWindow
1996  *  Paint the window while filling in the alpha channel with all on.
1997  *  We can't use fbPaintWindow because it zeros the alpha channel.
1998  */
1999 void
2000 RootlessPaintWindow(
2001     WindowPtr pWin,
2002     RegionPtr pRegion,
2003     int what)
2004 {
2005     switch (what) {
2006       case PW_BACKGROUND:
2007
2008         switch (pWin->backgroundState) {
2009             case None:
2010                 break;
2011             case ParentRelative:
2012                 do {
2013                     pWin = pWin->parent;
2014                 } while (pWin->backgroundState == ParentRelative);
2015                 (*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
2016                                                                     what);
2017                 break;
2018             case BackgroundPixmap:
2019                 RootlessFillRegionTiled (&pWin->drawable,
2020                                          pRegion,
2021                                          pWin->background.pixmap);
2022                 break;
2023             case BackgroundPixel:
2024             {
2025                 Pixel pixel = pWin->background.pixel |
2026                               RootlessAlphaMask(pWin->drawable.bitsPerPixel);
2027                 fbFillRegionSolid (&pWin->drawable, pRegion, 0,
2028                                    fbReplicatePixel (pixel,
2029                                         pWin->drawable.bitsPerPixel));
2030                 break;
2031             }
2032         }
2033         break;
2034       case PW_BORDER:
2035         if (pWin->borderIsPixel)
2036         {
2037             Pixel pixel = pWin->border.pixel |
2038                           RootlessAlphaMask(pWin->drawable.bitsPerPixel);
2039             fbFillRegionSolid (&pWin->drawable, pRegion, 0,
2040                                fbReplicatePixel (pixel,
2041                                     pWin->drawable.bitsPerPixel));
2042         }
2043         else
2044         {
2045             WindowPtr pBgWin;
2046             for (pBgWin = pWin; pBgWin->backgroundState == ParentRelative;
2047                  pBgWin = pBgWin->parent);
2048     
2049             RootlessFillRegionTiled (&pBgWin->drawable,
2050                                       pRegion,
2051                                       pWin->border.pixmap);
2052         }
2053         break;
2054     }
2055     fbValidateDrawable (&pWin->drawable);
2056 }