1 /*
2  * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   Kevin E. Martin <kem@redhat.com>
31  *
32  */
33 
34 /** \file
35  * This file provides support for window-related functions. */
36 
37 #ifdef HAVE_DMX_CONFIG_H
38 #include <dmx-config.h>
39 #endif
40 
41 #include "dmx.h"
42 #include "dmxsync.h"
43 #include "dmxwindow.h"
44 #include "dmxpixmap.h"
45 #include "dmxcmap.h"
46 #include "dmxvisual.h"
47 #include "dmxinput.h"
48 #include "dmxextension.h"
49 #include "dmxpict.h"
50 
51 #include "windowstr.h"
52 
53 static void dmxDoRestackWindow(WindowPtr pWindow);
54 static void dmxDoChangeWindowAttributes(WindowPtr pWindow,
55                                         unsigned long *mask,
56                                         XSetWindowAttributes * attribs);
57 
58 static void dmxDoSetShape(WindowPtr pWindow);
59 
60 /** Initialize the private area for the window functions. */
61 Bool
dmxInitWindow(ScreenPtr pScreen)62 dmxInitWindow(ScreenPtr pScreen)
63 {
64     if (!dixRegisterPrivateKey
65         (&dmxWinPrivateKeyRec, PRIVATE_WINDOW, sizeof(dmxWinPrivRec)))
66         return FALSE;
67 
68     return TRUE;
69 }
70 
71 Window
dmxCreateRootWindow(WindowPtr pWindow)72 dmxCreateRootWindow(WindowPtr pWindow)
73 {
74     ScreenPtr pScreen = pWindow->drawable.pScreen;
75     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
76     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
77     Window parent;
78     Visual *visual;
79     unsigned long mask;
80     XSetWindowAttributes attribs;
81     ColormapPtr pCmap;
82     dmxColormapPrivPtr pCmapPriv;
83 
84     /* Create root window */
85 
86     parent = dmxScreen->scrnWin;        /* This is our "Screen" window */
87     visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual;
88 
89     dixLookupResourceByType((void **) &pCmap, wColormap(pWindow),
90                             RT_COLORMAP, NullClient, DixUnknownAccess);
91     pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap);
92 
93     mask = CWEventMask | CWBackingStore | CWColormap | CWBorderPixel;
94     attribs.event_mask = ExposureMask;
95     attribs.backing_store = NotUseful;
96     attribs.colormap = pCmapPriv->cmap;
97     attribs.border_pixel = 0;
98 
99     /* Incorporate new attributes, if needed */
100     if (pWinPriv->attribMask) {
101         dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs);
102         mask |= pWinPriv->attribMask;
103     }
104 
105     return XCreateWindow(dmxScreen->beDisplay,
106                          parent,
107                          pWindow->origin.x - wBorderWidth(pWindow),
108                          pWindow->origin.y - wBorderWidth(pWindow),
109                          pWindow->drawable.width,
110                          pWindow->drawable.height,
111                          pWindow->borderWidth,
112                          pWindow->drawable.depth,
113                          pWindow->drawable.class, visual, mask, &attribs);
114 }
115 
116 /** Change the location and size of the "screen" window.  Called from
117  *  dmxextension.c dmxConfigureScreenWindow(). */
118 void
dmxResizeScreenWindow(ScreenPtr pScreen,int x,int y,int w,int h)119 dmxResizeScreenWindow(ScreenPtr pScreen, int x, int y, int w, int h)
120 {
121     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
122     unsigned int m;
123     XWindowChanges c;
124 
125     if (!dmxScreen->beDisplay)
126         return;
127 
128     /* Handle resizing on back-end server */
129     m = CWX | CWY | CWWidth | CWHeight;
130     c.x = x;
131     c.y = y;
132     c.width = w;
133     c.height = h;
134 
135     XConfigureWindow(dmxScreen->beDisplay, dmxScreen->scrnWin, m, &c);
136     dmxSync(dmxScreen, False);
137 }
138 
139 /** Change the location and size of the "root" window.  Called from
140  *  #dmxCreateWindow. */
141 void
dmxResizeRootWindow(WindowPtr pRoot,int x,int y,int w,int h)142 dmxResizeRootWindow(WindowPtr pRoot, int x, int y, int w, int h)
143 {
144     DMXScreenInfo *dmxScreen = &dmxScreens[pRoot->drawable.pScreen->myNum];
145     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot);
146     unsigned int m;
147     XWindowChanges c;
148 
149     /* Handle resizing on back-end server */
150     if (dmxScreen->beDisplay) {
151         m = CWX | CWY | CWWidth | CWHeight;
152         c.x = x;
153         c.y = y;
154         c.width = (w > 0) ? w : 1;
155         c.height = (h > 0) ? h : 1;
156 
157         XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
158     }
159 
160     if (w == 0 || h == 0) {
161         if (pWinPriv->mapped) {
162             if (dmxScreen->beDisplay)
163                 XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window);
164             pWinPriv->mapped = FALSE;
165         }
166     }
167     else if (!pWinPriv->mapped) {
168         if (dmxScreen->beDisplay)
169             XMapWindow(dmxScreen->beDisplay, pWinPriv->window);
170         pWinPriv->mapped = TRUE;
171     }
172 
173     if (dmxScreen->beDisplay)
174         dmxSync(dmxScreen, False);
175 }
176 
177 void
dmxGetDefaultWindowAttributes(WindowPtr pWindow,Colormap * cmap,Visual ** visual)178 dmxGetDefaultWindowAttributes(WindowPtr pWindow,
179                               Colormap * cmap, Visual ** visual)
180 {
181     ScreenPtr pScreen = pWindow->drawable.pScreen;
182 
183     if (pWindow->drawable.class != InputOnly &&
184         pWindow->optional &&
185         pWindow->optional->visual != wVisual(pWindow->parent)) {
186 
187         /* Find the matching visual */
188         *visual = dmxLookupVisualFromID(pScreen, wVisual(pWindow));
189 
190         /* Handle optional colormaps */
191         if (pWindow->optional->colormap) {
192             ColormapPtr pCmap;
193             dmxColormapPrivPtr pCmapPriv;
194 
195             dixLookupResourceByType((void **) &pCmap, wColormap(pWindow),
196                                     RT_COLORMAP, NullClient, DixUnknownAccess);
197             pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap);
198             *cmap = pCmapPriv->cmap;
199         }
200         else {
201             *cmap = dmxColormapFromDefaultVisual(pScreen, *visual);
202         }
203     }
204     else {
205         *visual = CopyFromParent;
206         *cmap = (Colormap) 0;
207     }
208 }
209 
210 static Window
dmxCreateNonRootWindow(WindowPtr pWindow)211 dmxCreateNonRootWindow(WindowPtr pWindow)
212 {
213     ScreenPtr pScreen = pWindow->drawable.pScreen;
214     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
215     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
216     Window parent;
217     unsigned long mask = 0L;
218     XSetWindowAttributes attribs;
219     dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent);
220 
221     /* Create window on back-end server */
222 
223     parent = pParentPriv->window;
224 
225     /* The parent won't exist if this call to CreateNonRootWindow came
226        from ReparentWindow and the grandparent window has not yet been
227        created */
228     if (!parent) {
229         dmxCreateAndRealizeWindow(pWindow->parent, FALSE);
230         parent = pParentPriv->window;
231     }
232 
233     /* Incorporate new attributes, if needed */
234     if (pWinPriv->attribMask) {
235         dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs);
236         mask |= pWinPriv->attribMask;
237     }
238 
239     /* Add in default attributes */
240     if (pWindow->drawable.class != InputOnly) {
241         mask |= CWBackingStore;
242         attribs.backing_store = NotUseful;
243 
244         if (!(mask & CWColormap) && pWinPriv->cmap) {
245             mask |= CWColormap;
246             attribs.colormap = pWinPriv->cmap;
247             if (!(mask & CWBorderPixel)) {
248                 mask |= CWBorderPixel;
249                 attribs.border_pixel = 0;
250             }
251         }
252     }
253 
254     /* Handle case where subwindows are being mapped, but created out of
255        order -- if current window has a previous sibling, then it cannot
256        be created on top of the stack, so we must restack the windows */
257     pWinPriv->restacked = (pWindow->prevSib != NullWindow);
258 
259     return XCreateWindow(dmxScreen->beDisplay,
260                          parent,
261                          pWindow->origin.x - wBorderWidth(pWindow),
262                          pWindow->origin.y - wBorderWidth(pWindow),
263                          pWindow->drawable.width,
264                          pWindow->drawable.height,
265                          pWindow->borderWidth,
266                          pWindow->drawable.depth,
267                          pWindow->drawable.class,
268                          pWinPriv->visual, mask, &attribs);
269 }
270 
271 /** This function handles lazy window creation and realization.  Window
272  *  creation is handled by #dmxCreateNonRootWindow().  It also handles
273  *  any stacking changes that have occured since the window was
274  *  originally created by calling #dmxDoRestackWindow().  If the window
275  *  is shaped, the shape is set on the back-end server by calling
276  *  #dmxDoSetShape(), and if the window has pictures (from RENDER)
277  *  associated with it, those pictures are created on the back-end
278  *  server by calling #dmxCreatePictureList().  If \a doSync is TRUE,
279  *  then #dmxSync() is called. */
280 void
dmxCreateAndRealizeWindow(WindowPtr pWindow,Bool doSync)281 dmxCreateAndRealizeWindow(WindowPtr pWindow, Bool doSync)
282 {
283     ScreenPtr pScreen = pWindow->drawable.pScreen;
284     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
285     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
286 
287     if (!dmxScreen->beDisplay)
288         return;
289 
290     pWinPriv->window = dmxCreateNonRootWindow(pWindow);
291     if (pWinPriv->restacked)
292         dmxDoRestackWindow(pWindow);
293     if (pWinPriv->isShaped)
294         dmxDoSetShape(pWindow);
295     if (pWinPriv->hasPict)
296         dmxCreatePictureList(pWindow);
297     if (pWinPriv->mapped)
298         XMapWindow(dmxScreen->beDisplay, pWinPriv->window);
299     if (doSync)
300         dmxSync(dmxScreen, False);
301 }
302 
303 /** Create \a pWindow on the back-end server.  If the lazy window
304  *  creation optimization is enabled, then the actual creation and
305  *  realization of the window is handled by
306  *  #dmxCreateAndRealizeWindow(). */
307 Bool
dmxCreateWindow(WindowPtr pWindow)308 dmxCreateWindow(WindowPtr pWindow)
309 {
310     ScreenPtr pScreen = pWindow->drawable.pScreen;
311     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
312     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
313     Bool ret = TRUE;
314 
315     DMX_UNWRAP(CreateWindow, dmxScreen, pScreen);
316 #if 0
317     if (pScreen->CreateWindow)
318         ret = pScreen->CreateWindow(pWindow);
319 #endif
320 
321     /* Set up the defaults */
322     pWinPriv->window = (Window) 0;
323     pWinPriv->offscreen = TRUE;
324     pWinPriv->mapped = FALSE;
325     pWinPriv->restacked = FALSE;
326     pWinPriv->attribMask = 0;
327     pWinPriv->isShaped = FALSE;
328     pWinPriv->hasPict = FALSE;
329 #ifdef GLXEXT
330     pWinPriv->swapGroup = NULL;
331     pWinPriv->barrier = 0;
332 #endif
333 
334     if (dmxScreen->beDisplay) {
335         /* Only create the root window at this stage -- non-root windows are
336            created when they are mapped and are on-screen */
337         if (!pWindow->parent) {
338             dmxScreen->rootWin = pWinPriv->window
339                 = dmxCreateRootWindow(pWindow);
340             if (dmxScreen->scrnX != dmxScreen->rootX
341                 || dmxScreen->scrnY != dmxScreen->rootY
342                 || dmxScreen->scrnWidth != dmxScreen->rootWidth
343                 || dmxScreen->scrnHeight != dmxScreen->rootHeight) {
344                 dmxResizeRootWindow(pWindow,
345                                     dmxScreen->rootX,
346                                     dmxScreen->rootY,
347                                     dmxScreen->rootWidth,
348                                     dmxScreen->rootHeight);
349                 dmxUpdateScreenResources(screenInfo.screens[dmxScreen->index],
350                                          dmxScreen->rootX,
351                                          dmxScreen->rootY,
352                                          dmxScreen->rootWidth,
353                                          dmxScreen->rootHeight);
354                 pWindow->origin.x = dmxScreen->rootX;
355                 pWindow->origin.y = dmxScreen->rootY;
356             }
357         }
358         else {
359             dmxGetDefaultWindowAttributes(pWindow,
360                                           &pWinPriv->cmap, &pWinPriv->visual);
361 
362             if (dmxLazyWindowCreation) {
363                 /* Save parent's visual for use later */
364                 if (pWinPriv->visual == CopyFromParent)
365                     pWinPriv->visual =
366                         dmxLookupVisualFromID(pScreen,
367                                               wVisual(pWindow->parent));
368             }
369             else {
370                 pWinPriv->window = dmxCreateNonRootWindow(pWindow);
371             }
372         }
373 
374         dmxSync(dmxScreen, False);
375     }
376 
377     DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen);
378 
379     return ret;
380 }
381 
382 /** Destroy \a pWindow on the back-end server. */
383 Bool
dmxBEDestroyWindow(WindowPtr pWindow)384 dmxBEDestroyWindow(WindowPtr pWindow)
385 {
386     ScreenPtr pScreen = pWindow->drawable.pScreen;
387     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
388     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
389 
390     if (pWinPriv->window) {
391         XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window);
392         pWinPriv->window = (Window) 0;
393         return TRUE;
394     }
395 
396     return FALSE;
397 }
398 
399 /** Destroy \a pWindow on the back-end server.  If any RENDER pictures
400     were created, destroy them as well. */
401 Bool
dmxDestroyWindow(WindowPtr pWindow)402 dmxDestroyWindow(WindowPtr pWindow)
403 {
404     ScreenPtr pScreen = pWindow->drawable.pScreen;
405     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
406     Bool ret = TRUE;
407     Bool needSync = FALSE;
408 
409 #ifdef GLXEXT
410     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
411 #endif
412 
413     DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen);
414 
415     /* Destroy any picture list associated with this window */
416     needSync |= dmxDestroyPictureList(pWindow);
417 
418     /* Destroy window on back-end server */
419     needSync |= dmxBEDestroyWindow(pWindow);
420     if (needSync)
421         dmxSync(dmxScreen, FALSE);
422 
423 #ifdef GLXEXT
424     if (pWinPriv->swapGroup && pWinPriv->windowDestroyed)
425         pWinPriv->windowDestroyed(pWindow);
426 #endif
427 
428     if (pScreen->DestroyWindow)
429         ret = pScreen->DestroyWindow(pWindow);
430 
431     DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen);
432 
433     return ret;
434 }
435 
436 /** Change the position of \a pWindow to be \a x, \a y. */
437 Bool
dmxPositionWindow(WindowPtr pWindow,int x,int y)438 dmxPositionWindow(WindowPtr pWindow, int x, int y)
439 {
440     ScreenPtr pScreen = pWindow->drawable.pScreen;
441     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
442     Bool ret = TRUE;
443     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
444     unsigned int m;
445     XWindowChanges c;
446 
447     DMX_UNWRAP(PositionWindow, dmxScreen, pScreen);
448 #if 0
449     if (pScreen->PositionWindow)
450         ret = pScreen->PositionWindow(pWindow, x, y);
451 #endif
452 
453     /* Determine if the window is completely off the visible portion of
454        the screen */
455     pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow);
456 
457     /* If the window is now on-screen and it is mapped and it has not
458        been created yet, create it and map it */
459     if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) {
460         dmxCreateAndRealizeWindow(pWindow, TRUE);
461     }
462     else if (pWinPriv->window) {
463         /* Position window on back-end server */
464         m = CWX | CWY | CWWidth | CWHeight;
465         c.x = pWindow->origin.x - wBorderWidth(pWindow);
466         c.y = pWindow->origin.y - wBorderWidth(pWindow);
467         c.width = pWindow->drawable.width;
468         c.height = pWindow->drawable.height;
469         if (pWindow->drawable.class != InputOnly) {
470             m |= CWBorderWidth;
471             c.border_width = pWindow->borderWidth;
472         }
473 
474         XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
475         dmxSync(dmxScreen, False);
476     }
477 
478     DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen);
479 
480     return ret;
481 }
482 
483 static void
dmxDoChangeWindowAttributes(WindowPtr pWindow,unsigned long * mask,XSetWindowAttributes * attribs)484 dmxDoChangeWindowAttributes(WindowPtr pWindow,
485                             unsigned long *mask, XSetWindowAttributes * attribs)
486 {
487     dmxPixPrivPtr pPixPriv;
488 
489     if (*mask & CWBackPixmap) {
490         switch (pWindow->backgroundState) {
491         case None:
492             attribs->background_pixmap = None;
493             break;
494 
495         case ParentRelative:
496             attribs->background_pixmap = ParentRelative;
497             break;
498 
499         case BackgroundPixmap:
500             pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->background.pixmap);
501             attribs->background_pixmap = pPixPriv->pixmap;
502             break;
503 
504         case BackgroundPixel:
505             *mask &= ~CWBackPixmap;
506             break;
507         }
508     }
509 
510     if (*mask & CWBackPixel) {
511         if (pWindow->backgroundState == BackgroundPixel)
512             attribs->background_pixel = pWindow->background.pixel;
513         else
514             *mask &= ~CWBackPixel;
515     }
516 
517     if (*mask & CWBorderPixmap) {
518         if (pWindow->borderIsPixel)
519             *mask &= ~CWBorderPixmap;
520         else {
521             pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->border.pixmap);
522             attribs->border_pixmap = pPixPriv->pixmap;
523         }
524     }
525 
526     if (*mask & CWBorderPixel) {
527         if (pWindow->borderIsPixel)
528             attribs->border_pixel = pWindow->border.pixel;
529         else
530             *mask &= ~CWBorderPixel;
531     }
532 
533     if (*mask & CWBitGravity)
534         attribs->bit_gravity = pWindow->bitGravity;
535 
536     if (*mask & CWWinGravity)
537         *mask &= ~CWWinGravity; /* Handled by dix */
538 
539     if (*mask & CWBackingStore)
540         *mask &= ~CWBackingStore;       /* Backing store not supported */
541 
542     if (*mask & CWBackingPlanes)
543         *mask &= ~CWBackingPlanes;      /* Backing store not supported */
544 
545     if (*mask & CWBackingPixel)
546         *mask &= ~CWBackingPixel;       /* Backing store not supported */
547 
548     if (*mask & CWOverrideRedirect)
549         attribs->override_redirect = pWindow->overrideRedirect;
550 
551     if (*mask & CWSaveUnder)
552         *mask &= ~CWSaveUnder;  /* Save unders not supported */
553 
554     if (*mask & CWEventMask)
555         *mask &= ~CWEventMask;  /* Events are handled by dix */
556 
557     if (*mask & CWDontPropagate)
558         *mask &= ~CWDontPropagate;      /* Events are handled by dix */
559 
560     if (*mask & CWColormap) {
561         ColormapPtr pCmap;
562         dmxColormapPrivPtr pCmapPriv;
563 
564         dixLookupResourceByType((void **) &pCmap, wColormap(pWindow),
565                                 RT_COLORMAP, NullClient, DixUnknownAccess);
566         pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap);
567         attribs->colormap = pCmapPriv->cmap;
568     }
569 
570     if (*mask & CWCursor)
571         *mask &= ~CWCursor;     /* Handled by the cursor code */
572 }
573 
574 /** Change the window attributes of \a pWindow. */
575 Bool
dmxChangeWindowAttributes(WindowPtr pWindow,unsigned long mask)576 dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask)
577 {
578     ScreenPtr pScreen = pWindow->drawable.pScreen;
579     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
580     Bool ret = TRUE;
581     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
582     XSetWindowAttributes attribs;
583 
584     DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen);
585 #if 0
586     if (pScreen->ChangeWindowAttributes)
587         ret = pScreen->ChangeWindowAttributes(pWindow, mask);
588 #endif
589 
590     /* Change window attribs on back-end server */
591     dmxDoChangeWindowAttributes(pWindow, &mask, &attribs);
592 
593     /* Save mask for lazy window creation optimization */
594     pWinPriv->attribMask |= mask;
595 
596     if (mask && pWinPriv->window) {
597         XChangeWindowAttributes(dmxScreen->beDisplay, pWinPriv->window,
598                                 mask, &attribs);
599         dmxSync(dmxScreen, False);
600     }
601 
602     DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen,
603              pScreen);
604 
605     return ret;
606 }
607 
608 /** Realize \a pWindow on the back-end server.  If the lazy window
609  *  creation optimization is enabled, the window is only realized when
610  *  it at least partially overlaps the screen. */
611 Bool
dmxRealizeWindow(WindowPtr pWindow)612 dmxRealizeWindow(WindowPtr pWindow)
613 {
614     ScreenPtr pScreen = pWindow->drawable.pScreen;
615     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
616     Bool ret = TRUE;
617     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
618 
619     DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen);
620 #if 0
621     if (pScreen->RealizeWindow)
622         ret = pScreen->RealizeWindow(pWindow);
623 #endif
624 
625     /* Determine if the window is completely off the visible portion of
626        the screen */
627     pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow);
628 
629     /* If the window hasn't been created and it's not offscreen, then
630        create it */
631     if (!pWinPriv->window && !pWinPriv->offscreen) {
632         dmxCreateAndRealizeWindow(pWindow, FALSE);
633     }
634 
635     if (pWinPriv->window) {
636         /* Realize window on back-end server */
637         XMapWindow(dmxScreen->beDisplay, pWinPriv->window);
638         dmxSync(dmxScreen, False);
639     }
640 
641     /* Let the other functions know that the window is now mapped */
642     pWinPriv->mapped = TRUE;
643 
644     DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen);
645 
646     dmxUpdateWindowInfo(DMX_UPDATE_REALIZE, pWindow);
647     return ret;
648 }
649 
650 /** Unrealize \a pWindow on the back-end server. */
651 Bool
dmxUnrealizeWindow(WindowPtr pWindow)652 dmxUnrealizeWindow(WindowPtr pWindow)
653 {
654     ScreenPtr pScreen = pWindow->drawable.pScreen;
655     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
656     Bool ret = TRUE;
657     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
658 
659     DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen);
660 #if 0
661     if (pScreen->UnrealizeWindow)
662         ret = pScreen->UnrealizeWindow(pWindow);
663 #endif
664 
665     if (pWinPriv->window) {
666         /* Unrealize window on back-end server */
667         XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window);
668         dmxSync(dmxScreen, False);
669     }
670 
671     /* When unrealized (i.e., unmapped), the window is always considered
672        off of the visible portion of the screen */
673     pWinPriv->offscreen = TRUE;
674     pWinPriv->mapped = FALSE;
675 
676 #ifdef GLXEXT
677     if (pWinPriv->swapGroup && pWinPriv->windowUnmapped)
678         pWinPriv->windowUnmapped(pWindow);
679 #endif
680 
681     DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen);
682 
683     dmxUpdateWindowInfo(DMX_UPDATE_UNREALIZE, pWindow);
684     return ret;
685 }
686 
687 static void
dmxDoRestackWindow(WindowPtr pWindow)688 dmxDoRestackWindow(WindowPtr pWindow)
689 {
690     ScreenPtr pScreen = pWindow->drawable.pScreen;
691     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
692     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
693     WindowPtr pNextSib = pWindow->nextSib;
694     unsigned int m;
695     XWindowChanges c;
696 
697     if (pNextSib == NullWindow) {
698         /* Window is at the bottom of the stack */
699         m = CWStackMode;
700         c.sibling = (Window) 0;
701         c.stack_mode = Below;
702         XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
703     }
704     else {
705         /* Window is not at the bottom of the stack */
706         dmxWinPrivPtr pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib);
707 
708         /* Handle case where siblings have not yet been created due to
709            lazy window creation optimization by first finding the next
710            sibling in the sibling list that has been created (if any)
711            and then putting the current window just above that sibling,
712            and if no next siblings have been created yet, then put it at
713            the bottom of the stack (since it might have a previous
714            sibling that should be above it). */
715         while (!pNextSibPriv->window) {
716             pNextSib = pNextSib->nextSib;
717             if (pNextSib == NullWindow) {
718                 /* Window is at the bottom of the stack */
719                 m = CWStackMode;
720                 c.sibling = (Window) 0;
721                 c.stack_mode = Below;
722                 XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
723                 return;
724             }
725             pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib);
726         }
727 
728         m = CWStackMode | CWSibling;
729         c.sibling = pNextSibPriv->window;
730         c.stack_mode = Above;
731         XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
732     }
733 }
734 
735 /** Handle window restacking.  The actual restacking occurs in
736  *  #dmxDoRestackWindow(). */
737 void
dmxRestackWindow(WindowPtr pWindow,WindowPtr pOldNextSib)738 dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib)
739 {
740     ScreenPtr pScreen = pWindow->drawable.pScreen;
741     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
742     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
743 
744     DMX_UNWRAP(RestackWindow, dmxScreen, pScreen);
745 #if 0
746     if (pScreen->RestackWindow)
747         pScreen->RestackWindow(pWindow, pOldNextSib);
748 #endif
749 
750     if (pOldNextSib != pWindow->nextSib) {
751         /* Track restacking for lazy window creation optimization */
752         pWinPriv->restacked = TRUE;
753 
754         /* Restack window on back-end server */
755         if (pWinPriv->window) {
756             dmxDoRestackWindow(pWindow);
757             dmxSync(dmxScreen, False);
758         }
759     }
760 
761     DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen);
762     dmxUpdateWindowInfo(DMX_UPDATE_RESTACK, pWindow);
763 }
764 
765 static Bool
dmxWindowExposurePredicate(Display * dpy,XEvent * ev,XPointer ptr)766 dmxWindowExposurePredicate(Display * dpy, XEvent * ev, XPointer ptr)
767 {
768     return (ev->type == Expose && ev->xexpose.window == *(Window *) ptr);
769 }
770 
771 /** Handle exposures on \a pWindow.  Since window exposures are handled
772  *  in DMX, the events that are generated by the back-end server are
773  *  redundant, so we eat them here. */
774 void
dmxWindowExposures(WindowPtr pWindow,RegionPtr prgn)775 dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn)
776 {
777     ScreenPtr pScreen = pWindow->drawable.pScreen;
778     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
779     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
780     XEvent ev;
781 
782     DMX_UNWRAP(WindowExposures, dmxScreen, pScreen);
783 
784     dmxSync(dmxScreen, False);
785 
786     if (pWinPriv->window) {
787         while (XCheckIfEvent(dmxScreen->beDisplay, &ev,
788                              dmxWindowExposurePredicate,
789                              (XPointer) &pWinPriv->window)) {
790             /* Handle expose events -- this should not be necessary
791                since the base window in which the root window was
792                created is guaranteed to be on top (override_redirect),
793                so we should just swallow these events.  If for some
794                reason the window is not on top, then we'd need to
795                collect these events and send them to the client later
796                (e.g., during the block handler as Xnest does). */
797         }
798     }
799 
800 #if 1
801     if (pScreen->WindowExposures)
802         pScreen->WindowExposures(pWindow, prgn);
803 #endif
804     DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen);
805 }
806 
807 /** Move \a pWindow on the back-end server.  Determine whether or not it
808  *  is on or offscreen, and realize it if it is newly on screen and the
809  *  lazy window creation optimization is enabled. */
810 void
dmxCopyWindow(WindowPtr pWindow,DDXPointRec ptOldOrg,RegionPtr prgnSrc)811 dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
812 {
813     ScreenPtr pScreen = pWindow->drawable.pScreen;
814     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
815     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
816     unsigned int m;
817     XWindowChanges c;
818 
819     DMX_UNWRAP(CopyWindow, dmxScreen, pScreen);
820 #if 0
821     if (pScreen->CopyWindow)
822         pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc);
823 #endif
824 
825     /* Determine if the window is completely off the visible portion of
826        the screen */
827     pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow);
828 
829     /* If the window is now on-screen and it is mapped and it has not
830        been created yet, create it and map it */
831     if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) {
832         dmxCreateAndRealizeWindow(pWindow, TRUE);
833     }
834     else if (pWinPriv->window) {
835         /* Move window on back-end server */
836         m = CWX | CWY | CWWidth | CWHeight;
837         c.x = pWindow->origin.x - wBorderWidth(pWindow);
838         c.y = pWindow->origin.y - wBorderWidth(pWindow);
839         c.width = pWindow->drawable.width;
840         c.height = pWindow->drawable.height;
841 
842         XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
843         dmxSync(dmxScreen, False);
844     }
845 
846     DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen);
847     dmxUpdateWindowInfo(DMX_UPDATE_COPY, pWindow);
848 }
849 
850 /** Resize \a pWindow on the back-end server.  Determine whether or not
851  *  it is on or offscreen, and realize it if it is newly on screen and
852  *  the lazy window creation optimization is enabled. */
853 void
dmxResizeWindow(WindowPtr pWindow,int x,int y,unsigned int w,unsigned int h,WindowPtr pSib)854 dmxResizeWindow(WindowPtr pWindow, int x, int y,
855                 unsigned int w, unsigned int h, WindowPtr pSib)
856 {
857     ScreenPtr pScreen = pWindow->drawable.pScreen;
858     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
859     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
860     unsigned int m;
861     XWindowChanges c;
862 
863     DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen);
864 #if 1
865     if (pScreen->ResizeWindow)
866         pScreen->ResizeWindow(pWindow, x, y, w, h, pSib);
867 #endif
868 
869     /* Determine if the window is completely off the visible portion of
870        the screen */
871     pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow);
872 
873     /* If the window is now on-screen and it is mapped and it has not
874        been created yet, create it and map it */
875     if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) {
876         dmxCreateAndRealizeWindow(pWindow, TRUE);
877     }
878     else if (pWinPriv->window) {
879         /* Handle resizing on back-end server */
880         m = CWX | CWY | CWWidth | CWHeight;
881         c.x = pWindow->origin.x - wBorderWidth(pWindow);
882         c.y = pWindow->origin.y - wBorderWidth(pWindow);
883         c.width = pWindow->drawable.width;
884         c.height = pWindow->drawable.height;
885 
886         XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
887         dmxSync(dmxScreen, False);
888     }
889 
890     DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen);
891     dmxUpdateWindowInfo(DMX_UPDATE_RESIZE, pWindow);
892 }
893 
894 /** Reparent \a pWindow on the back-end server. */
895 void
dmxReparentWindow(WindowPtr pWindow,WindowPtr pPriorParent)896 dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent)
897 {
898     ScreenPtr pScreen = pWindow->drawable.pScreen;
899     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
900     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
901     dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent);
902 
903     DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen);
904 #if 0
905     if (pScreen->ReparentWindow)
906         pScreen->ReparentWindow(pWindow, pPriorParent);
907 #endif
908 
909     if (pWinPriv->window) {
910         if (!pParentPriv->window) {
911             dmxCreateAndRealizeWindow(pWindow->parent, FALSE);
912         }
913 
914         /* Handle reparenting on back-end server */
915         XReparentWindow(dmxScreen->beDisplay, pWinPriv->window,
916                         pParentPriv->window,
917                         pWindow->origin.x - wBorderWidth(pWindow),
918                         pWindow->origin.x - wBorderWidth(pWindow));
919         dmxSync(dmxScreen, False);
920     }
921 
922     DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen);
923     dmxUpdateWindowInfo(DMX_UPDATE_REPARENT, pWindow);
924 }
925 
926 /** Change border width for \a pWindow to \a width pixels. */
927 void
dmxChangeBorderWidth(WindowPtr pWindow,unsigned int width)928 dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width)
929 {
930     ScreenPtr pScreen = pWindow->drawable.pScreen;
931     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
932     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
933     unsigned int m;
934     XWindowChanges c;
935 
936     DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen);
937 #if 1
938     if (pScreen->ChangeBorderWidth)
939         pScreen->ChangeBorderWidth(pWindow, width);
940 #endif
941 
942     /* NOTE: Do we need to check for on/off screen here? */
943 
944     if (pWinPriv->window) {
945         /* Handle border width change on back-end server */
946         m = CWBorderWidth;
947         c.border_width = width;
948 
949         XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c);
950         dmxSync(dmxScreen, False);
951     }
952 
953     DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen);
954 }
955 
956 static void
dmxDoSetShape(WindowPtr pWindow)957 dmxDoSetShape(WindowPtr pWindow)
958 {
959     ScreenPtr pScreen = pWindow->drawable.pScreen;
960     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
961     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
962     int nBox;
963     BoxPtr pBox;
964     int nRect;
965     XRectangle *pRect;
966     XRectangle *pRectFirst;
967 
968     /* First, set the bounding shape */
969     if (wBoundingShape(pWindow)) {
970         pBox = RegionRects(wBoundingShape(pWindow));
971         nRect = nBox = RegionNumRects(wBoundingShape(pWindow));
972         pRectFirst = pRect = xallocarray(nRect, sizeof(*pRect));
973         while (nBox--) {
974             pRect->x = pBox->x1;
975             pRect->y = pBox->y1;
976             pRect->width = pBox->x2 - pBox->x1;
977             pRect->height = pBox->y2 - pBox->y1;
978             pBox++;
979             pRect++;
980         }
981         XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window,
982                                 ShapeBounding, 0, 0,
983                                 pRectFirst, nRect, ShapeSet, YXBanded);
984         free(pRectFirst);
985     }
986     else {
987         XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window,
988                           ShapeBounding, 0, 0, None, ShapeSet);
989     }
990 
991     /* Next, set the clip shape */
992     if (wClipShape(pWindow)) {
993         pBox = RegionRects(wClipShape(pWindow));
994         nRect = nBox = RegionNumRects(wClipShape(pWindow));
995         pRectFirst = pRect = xallocarray(nRect, sizeof(*pRect));
996         while (nBox--) {
997             pRect->x = pBox->x1;
998             pRect->y = pBox->y1;
999             pRect->width = pBox->x2 - pBox->x1;
1000             pRect->height = pBox->y2 - pBox->y1;
1001             pBox++;
1002             pRect++;
1003         }
1004         XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window,
1005                                 ShapeClip, 0, 0,
1006                                 pRectFirst, nRect, ShapeSet, YXBanded);
1007         free(pRectFirst);
1008     }
1009     else {
1010         XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window,
1011                           ShapeClip, 0, 0, None, ShapeSet);
1012     }
1013 
1014     if (XShapeInputSelected(dmxScreen->beDisplay, pWinPriv->window)) {
1015         ErrorF("Input selected for window %x on Screen %d\n",
1016                (unsigned int) pWinPriv->window, pScreen->myNum);
1017     }
1018 }
1019 
1020 /** Set shape of \a pWindow on the back-end server. */
1021 void
dmxSetShape(WindowPtr pWindow,int kind)1022 dmxSetShape(WindowPtr pWindow, int kind)
1023 {
1024     ScreenPtr pScreen = pWindow->drawable.pScreen;
1025     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
1026     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
1027 
1028     DMX_UNWRAP(SetShape, dmxScreen, pScreen);
1029 #if 1
1030     if (pScreen->SetShape)
1031         pScreen->SetShape(pWindow, kind);
1032 #endif
1033 
1034     if (pWinPriv->window) {
1035         /* Handle setting the current shape on the back-end server */
1036         dmxDoSetShape(pWindow);
1037         dmxSync(dmxScreen, False);
1038     }
1039     else {
1040         pWinPriv->isShaped = TRUE;
1041     }
1042 
1043     DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen);
1044 }
1045