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