1 /*
2  * Copyright 2003-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  * Author:
30  *   Rickard E. (Rik) Faith <faith@redhat.com>
31  *   Kevin E. Martin <kem@redhat.com>
32  *
33  */
34 
35 /** \file
36  * This file provides the only interface to the X server extension support
37  * in programs/Xserver/Xext.  Those programs should only include dmxext.h
38  */
39 
40 #ifdef HAVE_DMX_CONFIG_H
41 #include <dmx-config.h>
42 #endif
43 
44 #include <stdlib.h>
45 
46 #include "dmx.h"
47 #include "dmxinit.h"
48 #include "dmxextension.h"
49 #include "dmxwindow.h"
50 #include "dmxcb.h"
51 #include "dmxcursor.h"
52 #include "dmxpixmap.h"
53 #include "dmxgc.h"
54 #include "dmxfont.h"
55 #include "dmxcmap.h"
56 #include "dmxpict.h"
57 #include "dmxinput.h"
58 #include "dmxsync.h"
59 #include "dmxscrinit.h"
60 #include "input/dmxinputinit.h"
61 
62 #include "windowstr.h"
63 #include "inputstr.h"           /* For DeviceIntRec */
64 #include <X11/extensions/dmxproto.h>    /* For DMX_BAD_* */
65 #include "cursorstr.h"
66 
67 /* The default font is declared in dix/globals.c, but is not included in
68  * _any_ header files. */
69 extern FontPtr defaultFont;
70 
71 /* Hack to get Present to build (present requires RandR) */
72 RESTYPE RRCrtcType;
73 
74 /** This routine provides information to the DMX protocol extension
75  * about a particular screen. */
76 Bool
dmxGetScreenAttributes(int physical,DMXScreenAttributesPtr attr)77 dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr)
78 {
79     DMXScreenInfo *dmxScreen;
80 
81     if (physical < 0 || physical >= dmxNumScreens)
82         return FALSE;
83 
84     dmxScreen = &dmxScreens[physical];
85     attr->displayName = dmxScreen->name;
86 #ifdef PANORAMIX
87     attr->logicalScreen = noPanoramiXExtension ? dmxScreen->index : 0;
88 #else
89     attr->logicalScreen = dmxScreen->index;
90 #endif
91 
92     attr->screenWindowWidth = dmxScreen->scrnWidth;
93     attr->screenWindowHeight = dmxScreen->scrnHeight;
94     attr->screenWindowXoffset = dmxScreen->scrnX;
95     attr->screenWindowYoffset = dmxScreen->scrnY;
96 
97     attr->rootWindowWidth = dmxScreen->rootWidth;
98     attr->rootWindowHeight = dmxScreen->rootHeight;
99     attr->rootWindowXoffset = dmxScreen->rootX;
100     attr->rootWindowYoffset = dmxScreen->rootY;
101 
102     attr->rootWindowXorigin = dmxScreen->rootXOrigin;
103     attr->rootWindowYorigin = dmxScreen->rootYOrigin;
104 
105     return TRUE;
106 }
107 
108 /** This routine provides information to the DMX protocol extension
109  * about a particular window. */
110 Bool
dmxGetWindowAttributes(WindowPtr pWindow,DMXWindowAttributesPtr attr)111 dmxGetWindowAttributes(WindowPtr pWindow, DMXWindowAttributesPtr attr)
112 {
113     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
114 
115     attr->screen = pWindow->drawable.pScreen->myNum;
116     attr->window = pWinPriv->window;
117 
118     attr->pos.x = pWindow->drawable.x;
119     attr->pos.y = pWindow->drawable.y;
120     attr->pos.width = pWindow->drawable.width;
121     attr->pos.height = pWindow->drawable.height;
122 
123     if (!pWinPriv->window || pWinPriv->offscreen) {
124         attr->vis.x = 0;
125         attr->vis.y = 0;
126         attr->vis.height = 0;
127         attr->vis.width = 0;
128         return pWinPriv->window ? TRUE : FALSE;
129     }
130 
131     /* Compute display-relative coordinates */
132     attr->vis.x = pWindow->drawable.x;
133     attr->vis.y = pWindow->drawable.y;
134     attr->vis.width = pWindow->drawable.width;
135     attr->vis.height = pWindow->drawable.height;
136 
137     if (attr->pos.x < 0) {
138         attr->vis.x -= attr->pos.x;
139         attr->vis.width = attr->pos.x + attr->pos.width - attr->vis.x;
140     }
141     if (attr->pos.x + attr->pos.width > pWindow->drawable.pScreen->width) {
142         if (attr->pos.x < 0)
143             attr->vis.width = pWindow->drawable.pScreen->width;
144         else
145             attr->vis.width = pWindow->drawable.pScreen->width - attr->pos.x;
146     }
147     if (attr->pos.y < 0) {
148         attr->vis.y -= attr->pos.y;
149         attr->vis.height = attr->pos.y + attr->pos.height - attr->vis.y;
150     }
151     if (attr->pos.y + attr->pos.height > pWindow->drawable.pScreen->height) {
152         if (attr->pos.y < 0)
153             attr->vis.height = pWindow->drawable.pScreen->height;
154         else
155             attr->vis.height = pWindow->drawable.pScreen->height - attr->pos.y;
156     }
157 
158     /* Convert to window-relative coordinates */
159     attr->vis.x -= attr->pos.x;
160     attr->vis.y -= attr->pos.y;
161 
162     return TRUE;
163 }
164 
165 void
dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr)166 dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr)
167 {
168     attr->width = dmxGlobalWidth;
169     attr->height = dmxGlobalHeight;
170     attr->shiftX = 0;           /* NOTE: The upper left hand corner of */
171     attr->shiftY = 0;           /*       the desktop is always <0,0>. */
172 }
173 
174 /** Return the total number of devices, not just #dmxNumInputs.  The
175  * number returned should be the same as that returned by
176  * XListInputDevices. */
177 int
dmxGetInputCount(void)178 dmxGetInputCount(void)
179 {
180     int i, total;
181 
182     for (total = i = 0; i < dmxNumInputs; i++)
183         total += dmxInputs[i].numDevs;
184     return total;
185 }
186 
187 /** Return information about the device with id = \a deviceId.  This
188  * information is primarily for the #ProcDMXGetInputAttributes()
189  * function, which does not have access to the appropriate data
190  * structure. */
191 int
dmxGetInputAttributes(int deviceId,DMXInputAttributesPtr attr)192 dmxGetInputAttributes(int deviceId, DMXInputAttributesPtr attr)
193 {
194     int i, j;
195     DMXInputInfo *dmxInput;
196 
197     if (deviceId < 0)
198         return -1;
199     for (i = 0; i < dmxNumInputs; i++) {
200         dmxInput = &dmxInputs[i];
201         for (j = 0; j < dmxInput->numDevs; j++) {
202             DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j];
203 
204             if (deviceId != dmxLocal->pDevice->id)
205                 continue;
206             attr->isCore = ! !dmxLocal->isCore;
207             attr->sendsCore = ! !dmxLocal->sendsCore;
208             attr->detached = ! !dmxInput->detached;
209             attr->physicalScreen = -1;
210             attr->physicalId = -1;
211             attr->name = NULL;
212             switch (dmxLocal->extType) {
213             case DMX_LOCAL_TYPE_LOCAL:
214                 attr->inputType = 0;
215                 break;
216             case DMX_LOCAL_TYPE_CONSOLE:
217                 attr->inputType = 1;
218                 attr->name = dmxInput->name;
219                 attr->physicalId = dmxLocal->deviceId;
220                 break;
221             case DMX_LOCAL_TYPE_BACKEND:
222             case DMX_LOCAL_TYPE_COMMON:
223                 attr->inputType = 2;
224                 attr->physicalScreen = dmxInput->scrnIdx;
225                 attr->name = dmxInput->name;
226                 attr->physicalId = dmxLocal->deviceId;
227                 break;
228             }
229             return 0;           /* Success */
230         }
231     }
232     return -1;                  /* Failure */
233 }
234 
235 /** Reinitialized the cursor boundaries. */
236 static void
dmxAdjustCursorBoundaries(void)237 dmxAdjustCursorBoundaries(void)
238 {
239     int i;
240 
241     dmxReInitOrigins();
242     dmxInitOverlap();
243     dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX);
244     dmxConnectionBlockCallback();
245     for (i = 0; i < dmxNumInputs; i++) {
246         DMXInputInfo *dmxInput = &dmxInputs[i];
247 
248         if (!dmxInput->detached)
249             dmxInputReInit(dmxInput);
250     }
251 
252     dmxCheckCursor();
253 
254     for (i = 0; i < dmxNumInputs; i++) {
255         DMXInputInfo *dmxInput = &dmxInputs[i];
256 
257         if (!dmxInput->detached)
258             dmxInputLateReInit(dmxInput);
259     }
260 }
261 
262 /** Add an input with the specified attributes.  If the input is added,
263  * the physical id is returned in \a deviceId. */
264 int
dmxAddInput(DMXInputAttributesPtr attr,int * id)265 dmxAddInput(DMXInputAttributesPtr attr, int *id)
266 {
267     int retcode = BadValue;
268 
269     if (attr->inputType == 1)   /* console */
270         retcode = dmxInputAttachConsole(attr->name, attr->sendsCore, id);
271     else if (attr->inputType == 2)      /* backend */
272         retcode = dmxInputAttachBackend(attr->physicalScreen,
273                                         attr->sendsCore, id);
274 
275     if (retcode == Success) {
276         /* Adjust the cursor boundaries */
277         dmxAdjustCursorBoundaries();
278 
279         /* Force completion of the changes */
280         dmxSync(NULL, TRUE);
281     }
282 
283     return retcode;
284 }
285 
286 /** Remove the input with physical id \a id. */
287 int
dmxRemoveInput(int id)288 dmxRemoveInput(int id)
289 {
290     return dmxInputDetachId(id);
291 }
292 
293 /** Return the value of #dmxNumScreens -- the total number of backend
294  * screens in use (these are logical screens and may be larger than the
295  * number of backend displays). */
296 unsigned long
dmxGetNumScreens(void)297 dmxGetNumScreens(void)
298 {
299     return dmxNumScreens;
300 }
301 
302 /** Make sure that #dmxCreateAndRealizeWindow has been called for \a
303  * pWindow. */
304 void
dmxForceWindowCreation(WindowPtr pWindow)305 dmxForceWindowCreation(WindowPtr pWindow)
306 {
307     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow);
308 
309     if (!pWinPriv->window)
310         dmxCreateAndRealizeWindow(pWindow, TRUE);
311 }
312 
313 /** Flush pending syncs for all screens. */
314 void
dmxFlushPendingSyncs(void)315 dmxFlushPendingSyncs(void)
316 {
317     dmxSync(NULL, TRUE);
318 }
319 
320 /** Update DMX's screen resources to match those of the newly moved
321  *  and/or resized "root" window. */
322 void
dmxUpdateScreenResources(ScreenPtr pScreen,int x,int y,int w,int h)323 dmxUpdateScreenResources(ScreenPtr pScreen, int x, int y, int w, int h)
324 {
325     DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
326     WindowPtr pRoot = pScreen->root;
327     WindowPtr pChild;
328     Bool anyMarked = FALSE;
329 
330     /* Handle special case where width and/or height are zero */
331     if (w == 0 || h == 0) {
332         w = 1;
333         h = 1;
334     }
335 
336     /* Change screen size */
337     pScreen->width = w;
338     pScreen->height = h;
339 
340     /* Reset the root window's drawable's size */
341     pRoot->drawable.width = w;
342     pRoot->drawable.height = h;
343 
344     /* Set the root window's new winSize and borderSize */
345     pRoot->winSize.extents.x1 = 0;
346     pRoot->winSize.extents.y1 = 0;
347     pRoot->winSize.extents.x2 = w;
348     pRoot->winSize.extents.y2 = h;
349 
350     pRoot->borderSize.extents.x1 = 0;
351     pRoot->borderSize.extents.y1 = 0;
352     pRoot->borderSize.extents.x2 = w;
353     pRoot->borderSize.extents.y2 = h;
354 
355     /* Recompute this screen's mmWidth & mmHeight */
356     pScreen->mmWidth =
357         (w * 254 + dmxScreen->beXDPI * 5) / (dmxScreen->beXDPI * 10);
358     pScreen->mmHeight =
359         (h * 254 + dmxScreen->beYDPI * 5) / (dmxScreen->beYDPI * 10);
360 
361     /* Recompute this screen's window's clip rects as follows: */
362     /*   1. Mark all of root's children's windows */
363     for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib)
364         anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild,
365                                                     (WindowPtr *) NULL);
366 
367     /*   2. Set the root window's borderClip */
368     pRoot->borderClip.extents.x1 = 0;
369     pRoot->borderClip.extents.y1 = 0;
370     pRoot->borderClip.extents.x2 = w;
371     pRoot->borderClip.extents.y2 = h;
372 
373     /*   3. Set the root window's clipList */
374     if (anyMarked) {
375         /* If any windows have been marked, set the root window's
376          * clipList to be broken since it will be recalculated in
377          * ValidateTree()
378          */
379         RegionBreak(&pRoot->clipList);
380     }
381     else {
382         /* Otherwise, we just set it directly since there are no
383          * windows visible on this screen
384          */
385         pRoot->clipList.extents.x1 = 0;
386         pRoot->clipList.extents.y1 = 0;
387         pRoot->clipList.extents.x2 = w;
388         pRoot->clipList.extents.y2 = h;
389     }
390 
391     /*   4. Revalidate all clip rects and generate expose events */
392     if (anyMarked) {
393         pScreen->ValidateTree(pRoot, NULL, VTBroken);
394         pScreen->HandleExposures(pRoot);
395         if (pScreen->PostValidateTree)
396             pScreen->PostValidateTree(pRoot, NULL, VTBroken);
397     }
398 }
399 
400 #ifdef PANORAMIX
401 #include "panoramiXsrv.h"
402 
403 /** Change the "screen" window attributes by resizing the actual window
404  *  on the back-end display (if necessary). */
405 static void
dmxConfigureScreenWindow(int idx,int x,int y,int w,int h)406 dmxConfigureScreenWindow(int idx, int x, int y, int w, int h)
407 {
408     DMXScreenInfo *dmxScreen = &dmxScreens[idx];
409     ScreenPtr pScreen = screenInfo.screens[idx];
410 
411     /* Resize "screen" window */
412     if (dmxScreen->scrnX != x ||
413         dmxScreen->scrnY != y ||
414         dmxScreen->scrnWidth != w || dmxScreen->scrnHeight != h) {
415         dmxResizeScreenWindow(pScreen, x, y, w, h);
416     }
417 
418     /* Change "screen" window values */
419     dmxScreen->scrnX = x;
420     dmxScreen->scrnY = y;
421     dmxScreen->scrnWidth = w;
422     dmxScreen->scrnHeight = h;
423 }
424 
425 /** Change the "root" window position and size by resizing the actual
426  *  window on the back-end display (if necessary) and updating all of
427  *  DMX's resources by calling #dmxUpdateScreenResources. */
428 static void
dmxConfigureRootWindow(int idx,int x,int y,int w,int h)429 dmxConfigureRootWindow(int idx, int x, int y, int w, int h)
430 {
431     DMXScreenInfo *dmxScreen = &dmxScreens[idx];
432     WindowPtr pRoot = screenInfo.screens[idx]->root;
433 
434     /* NOTE: Either this function or the ones that it calls must handle
435      * the case where w == 0 || h == 0.  Currently, the functions that
436      * this one calls handle that case. */
437 
438     /* 1. Resize "root" window */
439     if (dmxScreen->rootX != x ||
440         dmxScreen->rootY != y ||
441         dmxScreen->rootWidth != w || dmxScreen->rootHeight != h) {
442         dmxResizeRootWindow(pRoot, x, y, w, h);
443     }
444 
445     /* 2. Update all of the screen's resources associated with this root
446      *    window */
447     if (dmxScreen->rootWidth != w || dmxScreen->rootHeight != h) {
448         dmxUpdateScreenResources(screenInfo.screens[idx], x, y, w, h);
449     }
450 
451     /* Change "root" window values */
452     dmxScreen->rootX = x;
453     dmxScreen->rootY = y;
454     dmxScreen->rootWidth = w;
455     dmxScreen->rootHeight = h;
456 }
457 
458 /** Change the "root" window's origin by updating DMX's internal data
459  *  structures (dix and Xinerama) to use the new origin and adjust the
460  *  positions of windows that overlap this "root" window. */
461 static void
dmxSetRootWindowOrigin(int idx,int x,int y)462 dmxSetRootWindowOrigin(int idx, int x, int y)
463 {
464     DMXScreenInfo *dmxScreen = &dmxScreens[idx];
465     ScreenPtr pScreen = screenInfo.screens[idx];
466     WindowPtr pRoot = pScreen->root;
467     WindowPtr pChild;
468     int xoff;
469     int yoff;
470 
471     /* Change "root" window's origin */
472     dmxScreen->rootXOrigin = x;
473     dmxScreen->rootYOrigin = y;
474 
475     /* Compute offsets here in case <x,y> has been changed above */
476     xoff = x - pScreen->x;
477     yoff = y - pScreen->y;
478 
479     /* Adjust the root window's position */
480     pScreen->x = dmxScreen->rootXOrigin;
481     pScreen->y = dmxScreen->rootYOrigin;
482 
483     /* Recalculate the Xinerama regions and data structs */
484     XineramaReinitData();
485 
486     /* Adjust each of the root window's children */
487     if (!idx)
488         ReinitializeRootWindow(screenInfo.screens[0]->root, xoff, yoff);
489     pChild = pRoot->firstChild;
490     while (pChild) {
491         /* Adjust child window's position */
492         pScreen->MoveWindow(pChild,
493                             pChild->origin.x - wBorderWidth(pChild) - xoff,
494                             pChild->origin.y - wBorderWidth(pChild) - yoff,
495                             pChild->nextSib, VTMove);
496 
497         /* Note that the call to MoveWindow will eventually call
498          * dmxPositionWindow which will automatically create a
499          * window if it is now exposed on screen (for lazy window
500          * creation optimization) and it will properly set the
501          * offscreen flag.
502          */
503 
504         pChild = pChild->nextSib;
505     }
506 }
507 
508 /** Configure the attributes of each "screen" and "root" window. */
509 int
dmxConfigureScreenWindows(int nscreens,CARD32 * screens,DMXScreenAttributesPtr attribs,int * errorScreen)510 dmxConfigureScreenWindows(int nscreens,
511                           CARD32 *screens,
512                           DMXScreenAttributesPtr attribs, int *errorScreen)
513 {
514     int i;
515 
516     for (i = 0; i < nscreens; i++) {
517         DMXScreenAttributesPtr attr = &attribs[i];
518         int idx = screens[i];
519         DMXScreenInfo *dmxScreen = &dmxScreens[idx];
520 
521         if (errorScreen)
522             *errorScreen = i;
523 
524         if (!dmxScreen->beDisplay)
525             return DMX_BAD_VALUE;
526 
527         /* Check for illegal values */
528         if (idx < 0 || idx >= dmxNumScreens)
529             return BadValue;
530 
531         /* The "screen" and "root" windows must have valid sizes */
532         if (attr->screenWindowWidth <= 0 || attr->screenWindowHeight <= 0 ||
533             attr->rootWindowWidth < 0 || attr->rootWindowHeight < 0)
534             return DMX_BAD_VALUE;
535 
536         /* The "screen" window must fit entirely within the BE display */
537         if (attr->screenWindowXoffset < 0 ||
538             attr->screenWindowYoffset < 0 ||
539             attr->screenWindowXoffset
540             + attr->screenWindowWidth > (unsigned) dmxScreen->beWidth ||
541             attr->screenWindowYoffset
542             + attr->screenWindowHeight > (unsigned) dmxScreen->beHeight)
543             return DMX_BAD_VALUE;
544 
545         /* The "root" window must fit entirely within the "screen" window */
546         if (attr->rootWindowXoffset < 0 ||
547             attr->rootWindowYoffset < 0 ||
548             attr->rootWindowXoffset
549             + attr->rootWindowWidth > attr->screenWindowWidth ||
550             attr->rootWindowYoffset
551             + attr->rootWindowHeight > attr->screenWindowHeight)
552             return DMX_BAD_VALUE;
553 
554         /* The "root" window must not expose unaddressable coordinates */
555         if (attr->rootWindowXorigin < 0 ||
556             attr->rootWindowYorigin < 0 ||
557             attr->rootWindowXorigin + attr->rootWindowWidth > 32767 ||
558             attr->rootWindowYorigin + attr->rootWindowHeight > 32767)
559             return DMX_BAD_VALUE;
560 
561         /* The "root" window must fit within the global bounding box */
562         if (attr->rootWindowXorigin
563             + attr->rootWindowWidth > (unsigned) dmxGlobalWidth ||
564             attr->rootWindowYorigin
565             + attr->rootWindowHeight > (unsigned) dmxGlobalHeight)
566             return DMX_BAD_VALUE;
567 
568         /* FIXME: Handle the rest of the illegal value checking */
569     }
570 
571     /* No illegal values found */
572     if (errorScreen)
573         *errorScreen = 0;
574 
575     for (i = 0; i < nscreens; i++) {
576         DMXScreenAttributesPtr attr = &attribs[i];
577         int idx = screens[i];
578         DMXScreenInfo *dmxScreen = &dmxScreens[idx];
579 
580         dmxLog(dmxInfo, "Changing screen #%d attributes "
581                "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d "
582                "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n",
583                idx,
584                dmxScreen->scrnWidth, dmxScreen->scrnHeight,
585                dmxScreen->scrnX, dmxScreen->scrnY,
586                dmxScreen->rootWidth, dmxScreen->rootHeight,
587                dmxScreen->rootX, dmxScreen->rootY,
588                dmxScreen->rootXOrigin, dmxScreen->rootYOrigin,
589                attr->screenWindowWidth, attr->screenWindowHeight,
590                attr->screenWindowXoffset, attr->screenWindowYoffset,
591                attr->rootWindowWidth, attr->rootWindowHeight,
592                attr->rootWindowXoffset, attr->rootWindowYoffset,
593                attr->rootWindowXorigin, attr->rootWindowYorigin);
594 
595         /* Configure "screen" window */
596         dmxConfigureScreenWindow(idx,
597                                  attr->screenWindowXoffset,
598                                  attr->screenWindowYoffset,
599                                  attr->screenWindowWidth,
600                                  attr->screenWindowHeight);
601 
602         /* Configure "root" window */
603         dmxConfigureRootWindow(idx,
604                                attr->rootWindowXoffset,
605                                attr->rootWindowYoffset,
606                                attr->rootWindowWidth, attr->rootWindowHeight);
607 
608         /* Set "root" window's origin */
609         dmxSetRootWindowOrigin(idx,
610                                attr->rootWindowXorigin,
611                                attr->rootWindowYorigin);
612     }
613 
614     /* Adjust the cursor boundaries */
615     dmxAdjustCursorBoundaries();
616 
617     /* Force completion of the changes */
618     dmxSync(NULL, TRUE);
619 
620     return Success;
621 }
622 
623 /** Configure the attributes of the global desktop. */
624 int
dmxConfigureDesktop(DMXDesktopAttributesPtr attribs)625 dmxConfigureDesktop(DMXDesktopAttributesPtr attribs)
626 {
627     if (attribs->width <= 0 || attribs->width >= 32767 ||
628         attribs->height <= 0 || attribs->height >= 32767)
629         return DMX_BAD_VALUE;
630 
631     /* If the desktop is shrinking, adjust the "root" windows on each
632      * "screen" window to only show the visible desktop.  Also, handle
633      * the special case where the desktop shrinks such that the it no
634      * longer overlaps an portion of a "screen" window. */
635     if (attribs->width < dmxGlobalWidth || attribs->height < dmxGlobalHeight) {
636         int i;
637 
638         for (i = 0; i < dmxNumScreens; i++) {
639             DMXScreenInfo *dmxScreen = &dmxScreens[i];
640 
641             if (dmxScreen->rootXOrigin
642                 + dmxScreen->rootWidth > attribs->width ||
643                 dmxScreen->rootYOrigin
644                 + dmxScreen->rootHeight > attribs->height) {
645                 int w, h;
646 
647                 if ((w = attribs->width - dmxScreen->rootXOrigin) < 0)
648                     w = 0;
649                 if ((h = attribs->height - dmxScreen->rootYOrigin) < 0)
650                     h = 0;
651                 if (w > dmxScreen->scrnWidth)
652                     w = dmxScreen->scrnWidth;
653                 if (h > dmxScreen->scrnHeight)
654                     h = dmxScreen->scrnHeight;
655                 if (w > dmxScreen->rootWidth)
656                     w = dmxScreen->rootWidth;
657                 if (h > dmxScreen->rootHeight)
658                     h = dmxScreen->rootHeight;
659                 dmxConfigureRootWindow(i,
660                                        dmxScreen->rootX,
661                                        dmxScreen->rootY, w, h);
662             }
663         }
664     }
665 
666     /* Set the global width/height */
667     dmxSetWidthHeight(attribs->width, attribs->height);
668 
669     /* Handle shift[XY] changes */
670     if (attribs->shiftX || attribs->shiftY) {
671         int i;
672 
673         for (i = 0; i < dmxNumScreens; i++) {
674             ScreenPtr pScreen = screenInfo.screens[i];
675             WindowPtr pChild = pScreen->root->firstChild;
676 
677             while (pChild) {
678                 /* Adjust child window's position */
679                 pScreen->MoveWindow(pChild,
680                                     pChild->origin.x - wBorderWidth(pChild)
681                                     - attribs->shiftX,
682                                     pChild->origin.y - wBorderWidth(pChild)
683                                     - attribs->shiftY, pChild->nextSib, VTMove);
684 
685                 /* Note that the call to MoveWindow will eventually call
686                  * dmxPositionWindow which will automatically create a
687                  * window if it is now exposed on screen (for lazy
688                  * window creation optimization) and it will properly
689                  * set the offscreen flag.
690                  */
691 
692                 pChild = pChild->nextSib;
693             }
694         }
695     }
696 
697     /* Update connection block, Xinerama, etc. -- these appears to
698      * already be handled in dmxConnectionBlockCallback(), which is
699      * called from dmxAdjustCursorBoundaries() [below]. */
700 
701     /* Adjust the cursor boundaries */
702     dmxAdjustCursorBoundaries();
703 
704     /* Force completion of the changes */
705     dmxSync(NULL, TRUE);
706 
707     return Success;
708 }
709 #endif
710 
711 /** Create the scratch GCs per depth. */
712 static void
dmxBECreateScratchGCs(int scrnNum)713 dmxBECreateScratchGCs(int scrnNum)
714 {
715     ScreenPtr pScreen = screenInfo.screens[scrnNum];
716     GCPtr *ppGC = pScreen->GCperDepth;
717     int i;
718 
719     for (i = 0; i <= pScreen->numDepths; i++)
720         dmxBECreateGC(pScreen, ppGC[i]);
721 }
722 
723 #ifdef PANORAMIX
724 static Bool FoundPixImage;
725 
726 /** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs
727  *  to have its image restored.  When it is found, see if there is
728  *  another screen with the same image.  If so, copy the pixmap image
729  *  from the existing screen to the newly created pixmap. */
730 static void
dmxBERestorePixmapImage(void * value,XID id,RESTYPE type,void * p)731 dmxBERestorePixmapImage(void *value, XID id, RESTYPE type, void *p)
732 {
733     if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) {
734         PixmapPtr pDst = (PixmapPtr) p;
735         int idx = pDst->drawable.pScreen->myNum;
736         PanoramiXRes *pXinPix = (PanoramiXRes *) value;
737         PixmapPtr pPix;
738         int i;
739 
740         dixLookupResourceByType((void **) &pPix, pXinPix->info[idx].id,
741                                 RT_PIXMAP, NullClient, DixUnknownAccess);
742         if (pPix != pDst)
743             return;             /* Not a match.... Next! */
744 
745         FOR_NSCREENS(i) {
746             PixmapPtr pSrc;
747             dmxPixPrivPtr pSrcPriv = NULL;
748 
749             if (i == idx)
750                 continue;       /* Self replication is bad */
751 
752             dixLookupResourceByType((void **) &pSrc, pXinPix->info[i].id,
753                                     RT_PIXMAP, NullClient, DixUnknownAccess);
754             pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc);
755             if (pSrcPriv->pixmap) {
756                 DMXScreenInfo *dmxSrcScreen = &dmxScreens[i];
757                 DMXScreenInfo *dmxDstScreen = &dmxScreens[idx];
758                 dmxPixPrivPtr pDstPriv = DMX_GET_PIXMAP_PRIV(pDst);
759                 XImage *img;
760                 int j;
761                 XlibGC gc = NULL;
762 
763                 /* This should never happen, but just in case.... */
764                 if (pSrc->drawable.width != pDst->drawable.width ||
765                     pSrc->drawable.height != pDst->drawable.height)
766                     return;
767 
768                 /* Copy from src pixmap to dst pixmap */
769                 img = XGetImage(dmxSrcScreen->beDisplay,
770                                 pSrcPriv->pixmap,
771                                 0, 0,
772                                 pSrc->drawable.width, pSrc->drawable.height,
773                                 -1, ZPixmap);
774 
775                 for (j = 0; j < dmxDstScreen->beNumPixmapFormats; j++) {
776                     if (dmxDstScreen->bePixmapFormats[j].depth == img->depth) {
777                         unsigned long m;
778                         XGCValues v;
779 
780                         m = GCFunction | GCPlaneMask | GCClipMask;
781                         v.function = GXcopy;
782                         v.plane_mask = AllPlanes;
783                         v.clip_mask = None;
784 
785                         gc = XCreateGC(dmxDstScreen->beDisplay,
786                                        dmxDstScreen->scrnDefDrawables[j],
787                                        m, &v);
788                         break;
789                     }
790                 }
791 
792                 if (gc) {
793                     XPutImage(dmxDstScreen->beDisplay,
794                               pDstPriv->pixmap,
795                               gc, img, 0, 0, 0, 0,
796                               pDst->drawable.width, pDst->drawable.height);
797                     XFreeGC(dmxDstScreen->beDisplay, gc);
798                     FoundPixImage = True;
799                 }
800                 else {
801                     dmxLog(dmxWarning, "Could not create GC\n");
802                 }
803 
804                 XDestroyImage(img);
805                 return;
806             }
807         }
808     }
809 }
810 #endif
811 
812 /** Restore the pixmap image either from another screen or from an image
813  *  that was saved when the screen was previously detached. */
814 static void
dmxBERestorePixmap(PixmapPtr pPixmap)815 dmxBERestorePixmap(PixmapPtr pPixmap)
816 {
817 #ifdef PANORAMIX
818     int i;
819 
820     /* If Xinerama is not active, there's nothing we can do (see comment
821      * in #else below for more info). */
822     if (noPanoramiXExtension) {
823         dmxLog(dmxWarning, "Cannot restore pixmap image\n");
824         return;
825     }
826 
827     FoundPixImage = False;
828     for (i = currentMaxClients; --i >= 0;)
829         if (clients[i])
830             FindAllClientResources(clients[i], dmxBERestorePixmapImage,
831                                    (void *) pPixmap);
832 
833     /* No corresponding pixmap image was found on other screens, so we
834      * need to copy it from the saved image when the screen was detached
835      * (if available). */
836     if (!FoundPixImage) {
837         dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
838 
839         if (pPixPriv->detachedImage) {
840             ScreenPtr pScreen = pPixmap->drawable.pScreen;
841             DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
842             XlibGC gc = NULL;
843 
844             for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
845                 if (dmxScreen->bePixmapFormats[i].depth ==
846                     pPixPriv->detachedImage->depth) {
847                     unsigned long m;
848                     XGCValues v;
849 
850                     m = GCFunction | GCPlaneMask | GCClipMask;
851                     v.function = GXcopy;
852                     v.plane_mask = AllPlanes;
853                     v.clip_mask = None;
854 
855                     gc = XCreateGC(dmxScreen->beDisplay,
856                                    dmxScreen->scrnDefDrawables[i], m, &v);
857                     break;
858                 }
859             }
860 
861             if (gc) {
862                 XPutImage(dmxScreen->beDisplay,
863                           pPixPriv->pixmap,
864                           gc,
865                           pPixPriv->detachedImage,
866                           0, 0, 0, 0,
867                           pPixmap->drawable.width, pPixmap->drawable.height);
868                 XFreeGC(dmxScreen->beDisplay, gc);
869             }
870             else {
871                 dmxLog(dmxWarning, "Cannot restore pixmap image\n");
872             }
873 
874             XDestroyImage(pPixPriv->detachedImage);
875             pPixPriv->detachedImage = NULL;
876         }
877         else {
878             dmxLog(dmxWarning, "Cannot restore pixmap image\n");
879         }
880     }
881 #else
882     /* If Xinerama is not enabled, then there is no other copy of the
883      * pixmap image that we can restore.  Saving all pixmap data is not
884      * a feasible option since there is no mechanism for updating pixmap
885      * data when a screen is detached, which means that the data that
886      * was previously saved would most likely be out of date. */
887     dmxLog(dmxWarning, "Cannot restore pixmap image\n");
888     return;
889 #endif
890 }
891 
892 /** Create resources on the back-end server.  This function is called
893  *  from #dmxAttachScreen() via the dix layer's FindAllResources
894  *  function.  It walks all resources, compares them to the screen
895  *  number passed in as \a n and calls the appropriate DMX function to
896  *  create the associated resource on the back-end server. */
897 static void
dmxBECreateResources(void * value,XID id,RESTYPE type,void * n)898 dmxBECreateResources(void *value, XID id, RESTYPE type, void *n)
899 {
900     int scrnNum = (uintptr_t) n;
901     ScreenPtr pScreen = screenInfo.screens[scrnNum];
902 
903     if ((type & TypeMask) == (RT_WINDOW & TypeMask)) {
904         /* Window resources are created below in dmxBECreateWindowTree */
905     }
906     else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) {
907         PixmapPtr pPix = value;
908 
909         if (pPix->drawable.pScreen->myNum == scrnNum) {
910             dmxBECreatePixmap(pPix);
911             dmxBERestorePixmap(pPix);
912         }
913     }
914     else if ((type & TypeMask) == (RT_GC & TypeMask)) {
915         GCPtr pGC = value;
916 
917         if (pGC->pScreen->myNum == scrnNum) {
918             /* Create the GC on the back-end server */
919             dmxBECreateGC(pScreen, pGC);
920             /* Create any pixmaps associated with this GC */
921             if (!pGC->tileIsPixel) {
922                 dmxBECreatePixmap(pGC->tile.pixmap);
923                 dmxBERestorePixmap(pGC->tile.pixmap);
924             }
925             if (pGC->stipple != pScreen->defaultStipple) {
926                 dmxBECreatePixmap(pGC->stipple);
927                 dmxBERestorePixmap(pGC->stipple);
928             }
929             if (pGC->font != defaultFont) {
930                 (void) dmxBELoadFont(pScreen, pGC->font);
931             }
932             /* Update the GC on the back-end server */
933             dmxChangeGC(pGC, -1L);
934         }
935     }
936     else if ((type & TypeMask) == (RT_FONT & TypeMask)) {
937         (void) dmxBELoadFont(pScreen, (FontPtr) value);
938     }
939     else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) {
940         dmxBECreateCursor(pScreen, (CursorPtr) value);
941     }
942     else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) {
943         ColormapPtr pCmap = value;
944 
945         if (pCmap->pScreen->myNum == scrnNum)
946             (void) dmxBECreateColormap((ColormapPtr) value);
947 #if 0
948         /* TODO: Recreate Picture and GlyphSet resources */
949     }
950     else if ((type & TypeMask) == (PictureType & TypeMask)) {
951         /* Picture resources are created when windows are created */
952     }
953     else if ((type & TypeMask) == (GlyphSetType & TypeMask)) {
954         dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr) value);
955 #endif
956     }
957     else {
958         /* Other resource types??? */
959     }
960 }
961 
962 /** Create window hierarchy on back-end server.  The window tree is
963  *  created in a special order (bottom most subwindow first) so that the
964  *  #dmxCreateNonRootWindow() function does not need to recursively call
965  *  itself to create each window's parents.  This is required so that we
966  *  have the opportunity to create each window's border and background
967  *  pixmaps (where appropriate) before the window is created. */
968 static void
dmxBECreateWindowTree(int idx)969 dmxBECreateWindowTree(int idx)
970 {
971     DMXScreenInfo *dmxScreen = &dmxScreens[idx];
972     WindowPtr pRoot = screenInfo.screens[idx]->root;
973     dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot);
974     WindowPtr pWin;
975 
976     /* Create the pixmaps associated with the root window */
977     if (!pRoot->borderIsPixel) {
978         dmxBECreatePixmap(pRoot->border.pixmap);
979         dmxBERestorePixmap(pRoot->border.pixmap);
980     }
981     if (pRoot->backgroundState == BackgroundPixmap) {
982         dmxBECreatePixmap(pRoot->background.pixmap);
983         dmxBERestorePixmap(pRoot->background.pixmap);
984     }
985 
986     /* Create root window first */
987     dmxScreen->rootWin = pWinPriv->window = dmxCreateRootWindow(pRoot);
988     XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin);
989 
990     pWin = pRoot->lastChild;
991     while (pWin) {
992         pWinPriv = DMX_GET_WINDOW_PRIV(pWin);
993 
994         /* Create the pixmaps regardless of whether or not the
995          * window is created or not due to lazy window creation.
996          */
997         if (!pWin->borderIsPixel) {
998             dmxBECreatePixmap(pWin->border.pixmap);
999             dmxBERestorePixmap(pWin->border.pixmap);
1000         }
1001         if (pWin->backgroundState == BackgroundPixmap) {
1002             dmxBECreatePixmap(pWin->background.pixmap);
1003             dmxBERestorePixmap(pWin->background.pixmap);
1004         }
1005 
1006         /* Reset the window attributes */
1007         dmxGetDefaultWindowAttributes(pWin, &pWinPriv->cmap, &pWinPriv->visual);
1008 
1009         /* Create the window */
1010         if (pWinPriv->mapped && !pWinPriv->offscreen)
1011             dmxCreateAndRealizeWindow(pWin, TRUE);
1012 
1013         /* Next, create the bottom-most child */
1014         if (pWin->lastChild) {
1015             pWin = pWin->lastChild;
1016             continue;
1017         }
1018 
1019         /* If the window has no children, move on to the next higher window */
1020         while (!pWin->prevSib && (pWin != pRoot))
1021             pWin = pWin->parent;
1022 
1023         if (pWin->prevSib) {
1024             pWin = pWin->prevSib;
1025             continue;
1026         }
1027 
1028         /* When we reach the root window, we are finished */
1029         if (pWin == pRoot)
1030             break;
1031     }
1032 }
1033 
1034 /* Refresh screen by generating exposure events for all windows */
1035 static void
dmxForceExposures(int idx)1036 dmxForceExposures(int idx)
1037 {
1038     ScreenPtr pScreen = screenInfo.screens[idx];
1039     WindowPtr pRoot = pScreen->root;
1040     Bool anyMarked = FALSE;
1041     WindowPtr pChild;
1042 
1043     for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib)
1044         anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild,
1045                                                     (WindowPtr *) NULL);
1046     if (anyMarked) {
1047         /* If any windows have been marked, set the root window's
1048          * clipList to be broken since it will be recalculated in
1049          * ValidateTree()
1050          */
1051         RegionBreak(&pRoot->clipList);
1052         pScreen->ValidateTree(pRoot, NULL, VTBroken);
1053         pScreen->HandleExposures(pRoot);
1054         if (pScreen->PostValidateTree)
1055             pScreen->PostValidateTree(pRoot, NULL, VTBroken);
1056     }
1057 }
1058 
1059 /** Compare the new and old screens to see if they are compatible. */
1060 static Bool
dmxCompareScreens(DMXScreenInfo * new,DMXScreenInfo * old)1061 dmxCompareScreens(DMXScreenInfo * new, DMXScreenInfo * old)
1062 {
1063     int i;
1064 
1065     if (new->beWidth != old->beWidth)
1066         return FALSE;
1067     if (new->beHeight != old->beHeight)
1068         return FALSE;
1069     if (new->beDepth != old->beDepth)
1070         return FALSE;
1071     if (new->beBPP != old->beBPP)
1072         return FALSE;
1073 
1074     if (new->beNumDepths != old->beNumDepths)
1075         return FALSE;
1076     for (i = 0; i < old->beNumDepths; i++)
1077         if (new->beDepths[i] != old->beDepths[i])
1078             return FALSE;
1079 
1080     if (new->beNumPixmapFormats != old->beNumPixmapFormats)
1081         return FALSE;
1082     for (i = 0; i < old->beNumPixmapFormats; i++) {
1083         if (new->bePixmapFormats[i].depth != old->bePixmapFormats[i].depth)
1084             return FALSE;
1085         if (new->bePixmapFormats[i].bits_per_pixel !=
1086             old->bePixmapFormats[i].bits_per_pixel)
1087             return FALSE;
1088         if (new->bePixmapFormats[i].scanline_pad !=
1089             old->bePixmapFormats[i].scanline_pad)
1090             return FALSE;
1091     }
1092 
1093     if (new->beNumVisuals != old->beNumVisuals)
1094         return FALSE;
1095     for (i = 0; i < old->beNumVisuals; i++) {
1096         if (new->beVisuals[i].visualid != old->beVisuals[i].visualid)
1097             return FALSE;
1098         if (new->beVisuals[i].screen != old->beVisuals[i].screen)
1099             return FALSE;
1100         if (new->beVisuals[i].depth != old->beVisuals[i].depth)
1101             return FALSE;
1102         if (new->beVisuals[i].class != old->beVisuals[i].class)
1103             return FALSE;
1104         if (new->beVisuals[i].red_mask != old->beVisuals[i].red_mask)
1105             return FALSE;
1106         if (new->beVisuals[i].green_mask != old->beVisuals[i].green_mask)
1107             return FALSE;
1108         if (new->beVisuals[i].blue_mask != old->beVisuals[i].blue_mask)
1109             return FALSE;
1110         if (new->beVisuals[i].colormap_size != old->beVisuals[i].colormap_size)
1111             return FALSE;
1112         if (new->beVisuals[i].bits_per_rgb != old->beVisuals[i].bits_per_rgb)
1113             return FALSE;
1114     }
1115 
1116     if (new->beDefVisualIndex != old->beDefVisualIndex)
1117         return FALSE;
1118 
1119     return TRUE;
1120 }
1121 
1122 /** Restore Render's picture */
1123 static void
dmxBERestoreRenderPict(void * value,XID id,void * n)1124 dmxBERestoreRenderPict(void *value, XID id, void *n)
1125 {
1126     PicturePtr pPicture = value;        /* The picture */
1127     DrawablePtr pDraw = pPicture->pDrawable;    /* The picture's drawable */
1128     int scrnNum = (uintptr_t) n;
1129 
1130     if (pDraw->pScreen->myNum != scrnNum) {
1131         /* Picture not on the screen we are restoring */
1132         return;
1133     }
1134 
1135     if (pDraw->type == DRAWABLE_PIXMAP) {
1136         PixmapPtr pPixmap = (PixmapPtr) pDraw;
1137 
1138         /* Create and restore the pixmap drawable */
1139         dmxBECreatePixmap(pPixmap);
1140         dmxBERestorePixmap(pPixmap);
1141     }
1142 
1143     dmxBECreatePicture(pPicture);
1144 }
1145 
1146 /** Restore Render's glyphs */
1147 static void
dmxBERestoreRenderGlyph(void * value,XID id,void * n)1148 dmxBERestoreRenderGlyph(void *value, XID id, void *n)
1149 {
1150     GlyphSetPtr glyphSet = value;
1151     int scrnNum = (uintptr_t) n;
1152     dmxGlyphPrivPtr glyphPriv = DMX_GET_GLYPH_PRIV(glyphSet);
1153     DMXScreenInfo *dmxScreen = &dmxScreens[scrnNum];
1154     GlyphRefPtr table;
1155     char *images;
1156     Glyph *gids;
1157     XGlyphInfo *glyphs;
1158     char *pos;
1159     int beret;
1160     int len_images = 0;
1161     int i;
1162     int ctr;
1163 
1164     if (glyphPriv->glyphSets[scrnNum]) {
1165         /* Only restore glyphs on the screen we are attaching */
1166         return;
1167     }
1168 
1169     /* First we must create the glyph set on the backend. */
1170     if ((beret = dmxBECreateGlyphSet(scrnNum, glyphSet)) != Success) {
1171         dmxLog(dmxWarning,
1172                "\tdmxBERestoreRenderGlyph failed to create glyphset!\n");
1173         return;
1174     }
1175 
1176     /* Now for the complex part, restore the glyph data */
1177     table = glyphSet->hash.table;
1178 
1179     /* We need to know how much memory to allocate for this part */
1180     for (i = 0; i < glyphSet->hash.hashSet->size; i++) {
1181         GlyphRefPtr gr = &table[i];
1182         GlyphPtr gl = gr->glyph;
1183 
1184         if (!gl || gl == DeletedGlyph)
1185             continue;
1186         len_images += gl->size - sizeof(gl->info);
1187     }
1188 
1189     /* Now allocate the memory we need */
1190     images = calloc(len_images, sizeof(char));
1191     gids = xallocarray(glyphSet->hash.tableEntries, sizeof(Glyph));
1192     glyphs = xallocarray(glyphSet->hash.tableEntries, sizeof(XGlyphInfo));
1193 
1194     pos = images;
1195     ctr = 0;
1196 
1197     /* Fill the allocated memory with the proper data */
1198     for (i = 0; i < glyphSet->hash.hashSet->size; i++) {
1199         GlyphRefPtr gr = &table[i];
1200         GlyphPtr gl = gr->glyph;
1201 
1202         if (!gl || gl == DeletedGlyph)
1203             continue;
1204 
1205         /* First lets put the data into gids */
1206         gids[ctr] = gr->signature;
1207 
1208         /* Next do the glyphs data structures */
1209         glyphs[ctr].width = gl->info.width;
1210         glyphs[ctr].height = gl->info.height;
1211         glyphs[ctr].x = gl->info.x;
1212         glyphs[ctr].y = gl->info.y;
1213         glyphs[ctr].xOff = gl->info.xOff;
1214         glyphs[ctr].yOff = gl->info.yOff;
1215 
1216         /* Copy the images from the DIX's data into the buffer */
1217         memcpy(pos, gl + 1, gl->size - sizeof(gl->info));
1218         pos += gl->size - sizeof(gl->info);
1219         ctr++;
1220     }
1221 
1222     /* Now restore the glyph data */
1223     XRenderAddGlyphs(dmxScreen->beDisplay, glyphPriv->glyphSets[scrnNum],
1224                      gids, glyphs, glyphSet->hash.tableEntries, images,
1225                      len_images);
1226 
1227     /* Clean up */
1228     free(images);
1229     free(gids);
1230     free(glyphs);
1231 }
1232 
1233 /** Reattach previously detached back-end screen. */
1234 int
dmxAttachScreen(int idx,DMXScreenAttributesPtr attr)1235 dmxAttachScreen(int idx, DMXScreenAttributesPtr attr)
1236 {
1237     ScreenPtr pScreen;
1238     DMXScreenInfo *dmxScreen;
1239     CARD32 scrnNum = idx;
1240     DMXScreenInfo oldDMXScreen;
1241     int i;
1242 
1243     /* Return failure if dynamic addition/removal of screens is disabled */
1244     if (!dmxAddRemoveScreens) {
1245         dmxLog(dmxWarning,
1246                "Attempting to add a screen, but the AddRemoveScreen\n");
1247         dmxLog(dmxWarning,
1248                "extension has not been enabled.  To enable this extension\n");
1249         dmxLog(dmxWarning,
1250                "add the \"-addremovescreens\" option either to the command\n");
1251         dmxLog(dmxWarning, "line or in the configuration file.\n");
1252         return 1;
1253     }
1254 
1255     /* Cannot add a screen that does not exist */
1256     if (idx < 0 || idx >= dmxNumScreens)
1257         return 1;
1258     pScreen = screenInfo.screens[idx];
1259     dmxScreen = &dmxScreens[idx];
1260 
1261     /* Cannot attach to a screen that is already opened */
1262     if (dmxScreen->beDisplay) {
1263         dmxLog(dmxWarning,
1264                "Attempting to add screen #%d but a screen already exists\n",
1265                idx);
1266         return 1;
1267     }
1268 
1269     dmxLogOutput(dmxScreen, "Attaching screen #%d\n", idx);
1270 
1271     /* Save old info */
1272     oldDMXScreen = *dmxScreen;
1273 
1274     /* Copy the name to the new screen */
1275     dmxScreen->name = strdup(attr->displayName);
1276 
1277     /* Open display and get all of the screen info */
1278     if (!dmxOpenDisplay(dmxScreen)) {
1279         dmxLog(dmxWarning,
1280                "dmxOpenDisplay: Unable to open display %s\n", dmxScreen->name);
1281 
1282         /* Restore the old screen */
1283         *dmxScreen = oldDMXScreen;
1284         return 1;
1285     }
1286 
1287     dmxSetErrorHandler(dmxScreen);
1288     dmxCheckForWM(dmxScreen);
1289     dmxGetScreenAttribs(dmxScreen);
1290 
1291     if (!dmxGetVisualInfo(dmxScreen)) {
1292         dmxLog(dmxWarning, "dmxGetVisualInfo: No matching visuals found\n");
1293         XFree(dmxScreen->beVisuals);
1294         XCloseDisplay(dmxScreen->beDisplay);
1295 
1296         /* Restore the old screen */
1297         *dmxScreen = oldDMXScreen;
1298         return 1;
1299     }
1300 
1301     dmxGetColormaps(dmxScreen);
1302     dmxGetPixmapFormats(dmxScreen);
1303 
1304     /* Verify that the screen to be added has the same info as the
1305      * previously added screen. */
1306     if (!dmxCompareScreens(dmxScreen, &oldDMXScreen)) {
1307         dmxLog(dmxWarning,
1308                "New screen data (%s) does not match previously\n",
1309                dmxScreen->name);
1310         dmxLog(dmxWarning, "attached screen data (%s)\n", oldDMXScreen.name);
1311         dmxLog(dmxWarning,
1312                "All data must match in order to attach to screen #%d\n", idx);
1313         XFree(dmxScreen->beVisuals);
1314         XFree(dmxScreen->beDepths);
1315         XFree(dmxScreen->bePixmapFormats);
1316         XCloseDisplay(dmxScreen->beDisplay);
1317 
1318         /* Restore the old screen */
1319         *dmxScreen = oldDMXScreen;
1320         return 1;
1321     }
1322 
1323     /* Initialize the BE screen resources */
1324     dmxBEScreenInit(screenInfo.screens[idx]);
1325 
1326     /* TODO: Handle GLX visual initialization.  GLXProxy needs to be
1327      * updated to handle dynamic addition/removal of screens. */
1328 
1329     /* Create default stipple */
1330     dmxBECreatePixmap(pScreen->defaultStipple);
1331     dmxBERestorePixmap(pScreen->defaultStipple);
1332 
1333     /* Create the scratch GCs */
1334     dmxBECreateScratchGCs(idx);
1335 
1336     /* Create the default font */
1337     (void) dmxBELoadFont(pScreen, defaultFont);
1338 
1339     /* Create all resources that don't depend on windows */
1340     for (i = currentMaxClients; --i >= 0;)
1341         if (clients[i])
1342             FindAllClientResources(clients[i], dmxBECreateResources,
1343                                    (void *) (uintptr_t) idx);
1344 
1345     /* Create window hierarchy (top down) */
1346     dmxBECreateWindowTree(idx);
1347 
1348     /* Restore the picture state for RENDER */
1349     for (i = currentMaxClients; --i >= 0;)
1350         if (clients[i])
1351             FindClientResourcesByType(clients[i], PictureType,
1352                                       dmxBERestoreRenderPict,
1353                                       (void *) (uintptr_t) idx);
1354 
1355     /* Restore the glyph state for RENDER */
1356     for (i = currentMaxClients; --i >= 0;)
1357         if (clients[i])
1358             FindClientResourcesByType(clients[i], GlyphSetType,
1359                                       dmxBERestoreRenderGlyph,
1360                                       (void *) (uintptr_t) idx);
1361 
1362     /* Refresh screen by generating exposure events for all windows */
1363     dmxForceExposures(idx);
1364 
1365     dmxSync(&dmxScreens[idx], TRUE);
1366 
1367     /* We used these to compare the old and new screens.  They are no
1368      * longer needed since we have a newly attached screen, so we can
1369      * now free the old screen's resources. */
1370     XFree(oldDMXScreen.beVisuals);
1371     XFree(oldDMXScreen.beDepths);
1372     XFree(oldDMXScreen.bePixmapFormats);
1373     /* TODO: should oldDMXScreen.name be freed?? */
1374 
1375 #ifdef PANORAMIX
1376     if (!noPanoramiXExtension)
1377         return dmxConfigureScreenWindows(1, &scrnNum, attr, NULL);
1378     else
1379 #endif
1380         return 0;               /* Success */
1381 }
1382 
1383 /*
1384  * Resources that may have state on the BE server and need to be freed:
1385  *
1386  * RT_NONE
1387  * RT_WINDOW
1388  * RT_PIXMAP
1389  * RT_GC
1390  * RT_FONT
1391  * RT_CURSOR
1392  * RT_COLORMAP
1393  * RT_CMAPENTRY
1394  * RT_OTHERCLIENT
1395  * RT_PASSIVEGRAB
1396  * XRT_WINDOW
1397  * XRT_PIXMAP
1398  * XRT_GC
1399  * XRT_COLORMAP
1400  * XRT_PICTURE
1401  * PictureType
1402  * PictFormatType
1403  * GlyphSetType
1404  * ClientType
1405  * EventType
1406  * RT_INPUTCLIENT
1407  * XETrapType
1408  * RTCounter
1409  * RTAwait
1410  * RTAlarmClient
1411  * RT_XKBCLIENT
1412  * RTContext
1413  * TagResType
1414  * StalledResType
1415  * SecurityAuthorizationResType
1416  * RTEventClient
1417  * __glXContextRes
1418  * __glXClientRes
1419  * __glXPixmapRes
1420  * __glXWindowRes
1421  * __glXPbufferRes
1422  */
1423 
1424 #ifdef PANORAMIX
1425 /** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs
1426  *  to have its image saved. */
1427 static void
dmxBEFindPixmapImage(void * value,XID id,RESTYPE type,void * p)1428 dmxBEFindPixmapImage(void *value, XID id, RESTYPE type, void *p)
1429 {
1430     if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) {
1431         PixmapPtr pDst = (PixmapPtr) p;
1432         int idx = pDst->drawable.pScreen->myNum;
1433         PanoramiXRes *pXinPix = (PanoramiXRes *) value;
1434         PixmapPtr pPix;
1435         int i;
1436 
1437         dixLookupResourceByType((void **) &pPix, pXinPix->info[idx].id,
1438                                 RT_PIXMAP, NullClient, DixUnknownAccess);
1439         if (pPix != pDst)
1440             return;             /* Not a match.... Next! */
1441 
1442         FOR_NSCREENS(i) {
1443             PixmapPtr pSrc;
1444             dmxPixPrivPtr pSrcPriv = NULL;
1445 
1446             if (i == idx)
1447                 continue;       /* Self replication is bad */
1448 
1449             dixLookupResourceByType((void **) &pSrc, pXinPix->info[i].id,
1450                                     RT_PIXMAP, NullClient, DixUnknownAccess);
1451             pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc);
1452             if (pSrcPriv->pixmap) {
1453                 FoundPixImage = True;
1454                 return;
1455             }
1456         }
1457     }
1458 }
1459 #endif
1460 
1461 /** Save the pixmap image only when there is not another screen with
1462  *  that pixmap from which the image can be read when the screen is
1463  *  reattached.  To do this, we first try to find a pixmap on another
1464  *  screen corresponding to the one we are trying to save.  If we find
1465  *  one, then we do not need to save the image data since during
1466  *  reattachment, the image data can be read from that other pixmap.
1467  *  However, if we do not find one, then we need to save the image data.
1468  *  The common case for these are for the default stipple and root
1469  *  tile. */
1470 static void
dmxBESavePixmap(PixmapPtr pPixmap)1471 dmxBESavePixmap(PixmapPtr pPixmap)
1472 {
1473 #ifdef PANORAMIX
1474     int i;
1475 
1476     /* If Xinerama is not active, there's nothing we can do (see comment
1477      * in #else below for more info). */
1478     if (noPanoramiXExtension)
1479         return;
1480 
1481     FoundPixImage = False;
1482     for (i = currentMaxClients; --i >= 0;)
1483         if (clients[i])
1484             FindAllClientResources(clients[i], dmxBEFindPixmapImage,
1485                                    (void *) pPixmap);
1486 
1487     /* Save the image only if there is no other screens that have a
1488      * pixmap that corresponds to the one we are trying to save. */
1489     if (!FoundPixImage) {
1490         dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap);
1491 
1492         if (!pPixPriv->detachedImage) {
1493             ScreenPtr pScreen = pPixmap->drawable.pScreen;
1494             DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum];
1495 
1496             pPixPriv->detachedImage = XGetImage(dmxScreen->beDisplay,
1497                                                 pPixPriv->pixmap,
1498                                                 0, 0,
1499                                                 pPixmap->drawable.width,
1500                                                 pPixmap->drawable.height,
1501                                                 -1, ZPixmap);
1502             if (!pPixPriv->detachedImage)
1503                 dmxLog(dmxWarning, "Cannot save pixmap image\n");
1504         }
1505     }
1506 #else
1507     /* NOTE: The only time there is a pixmap on another screen that
1508      * corresponds to the one we are trying to save is when Xinerama is
1509      * active.  Otherwise, the pixmap image data is only stored on a
1510      * single screen, which means that once it is detached, that data is
1511      * lost.  We could save the data here, but then that would require
1512      * us to implement the ability for Xdmx to keep the pixmap up to
1513      * date while the screen is detached, which is beyond the scope of
1514      * the current project. */
1515     return;
1516 #endif
1517 }
1518 
1519 /** Destroy resources on the back-end server.  This function is called
1520  *  from #dmxDetachScreen() via the dix layer's FindAllResources
1521  *  function.  It walks all resources, compares them to the screen
1522  *  number passed in as \a n and calls the appropriate DMX function to
1523  *  free the associated resource on the back-end server. */
1524 static void
dmxBEDestroyResources(void * value,XID id,RESTYPE type,void * n)1525 dmxBEDestroyResources(void *value, XID id, RESTYPE type, void *n)
1526 {
1527     int scrnNum = (uintptr_t) n;
1528     ScreenPtr pScreen = screenInfo.screens[scrnNum];
1529 
1530     if ((type & TypeMask) == (RT_WINDOW & TypeMask)) {
1531         /* Window resources are destroyed below in dmxBEDestroyWindowTree */
1532     }
1533     else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) {
1534         PixmapPtr pPix = value;
1535 
1536         if (pPix->drawable.pScreen->myNum == scrnNum) {
1537             dmxBESavePixmap(pPix);
1538             dmxBEFreePixmap(pPix);
1539         }
1540     }
1541     else if ((type & TypeMask) == (RT_GC & TypeMask)) {
1542         GCPtr pGC = value;
1543 
1544         if (pGC->pScreen->myNum == scrnNum)
1545             dmxBEFreeGC(pGC);
1546     }
1547     else if ((type & TypeMask) == (RT_FONT & TypeMask)) {
1548         dmxBEFreeFont(pScreen, (FontPtr) value);
1549     }
1550     else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) {
1551         dmxBEFreeCursor(pScreen, (CursorPtr) value);
1552     }
1553     else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) {
1554         ColormapPtr pCmap = value;
1555 
1556         if (pCmap->pScreen->myNum == scrnNum)
1557             dmxBEFreeColormap((ColormapPtr) value);
1558     }
1559     else if ((type & TypeMask) == (PictureType & TypeMask)) {
1560         PicturePtr pPict = value;
1561 
1562         if (pPict->pDrawable->pScreen->myNum == scrnNum) {
1563             /* Free the pixmaps on the backend if needed */
1564             if (pPict->pDrawable->type == DRAWABLE_PIXMAP) {
1565                 PixmapPtr pPixmap = (PixmapPtr) (pPict->pDrawable);
1566 
1567                 dmxBESavePixmap(pPixmap);
1568                 dmxBEFreePixmap(pPixmap);
1569             }
1570             dmxBEFreePicture((PicturePtr) value);
1571         }
1572     }
1573     else if ((type & TypeMask) == (GlyphSetType & TypeMask)) {
1574         dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr) value);
1575     }
1576     else {
1577         /* Other resource types??? */
1578     }
1579 }
1580 
1581 /** Destroy the scratch GCs that are created per depth. */
1582 static void
dmxBEDestroyScratchGCs(int scrnNum)1583 dmxBEDestroyScratchGCs(int scrnNum)
1584 {
1585     ScreenPtr pScreen = screenInfo.screens[scrnNum];
1586     GCPtr *ppGC = pScreen->GCperDepth;
1587     int i;
1588 
1589     for (i = 0; i <= pScreen->numDepths; i++)
1590         dmxBEFreeGC(ppGC[i]);
1591 }
1592 
1593 /** Destroy window hierarchy on back-end server.  To ensure that all
1594  *  XDestroyWindow() calls succeed, they must be performed in a bottom
1595  *  up order so that windows are not destroyed before their children.
1596  *  XDestroyWindow(), which is called from #dmxBEDestroyWindow(), will
1597  *  destroy a window as well as all of its children. */
1598 static void
dmxBEDestroyWindowTree(int idx)1599 dmxBEDestroyWindowTree(int idx)
1600 {
1601     WindowPtr pWin = screenInfo.screens[idx]->root;
1602     WindowPtr pChild = pWin;
1603 
1604     while (1) {
1605         if (pChild->firstChild) {
1606             pChild = pChild->firstChild;
1607             continue;
1608         }
1609 
1610         /* Destroy the window */
1611         dmxBEDestroyWindow(pChild);
1612 
1613         /* Make sure we destroy the window's border and background
1614          * pixmaps if they exist */
1615         if (!pChild->borderIsPixel) {
1616             dmxBESavePixmap(pChild->border.pixmap);
1617             dmxBEFreePixmap(pChild->border.pixmap);
1618         }
1619         if (pChild->backgroundState == BackgroundPixmap) {
1620             dmxBESavePixmap(pChild->background.pixmap);
1621             dmxBEFreePixmap(pChild->background.pixmap);
1622         }
1623 
1624         while (!pChild->nextSib && (pChild != pWin)) {
1625             pChild = pChild->parent;
1626             dmxBEDestroyWindow(pChild);
1627             if (!pChild->borderIsPixel) {
1628                 dmxBESavePixmap(pChild->border.pixmap);
1629                 dmxBEFreePixmap(pChild->border.pixmap);
1630             }
1631             if (pChild->backgroundState == BackgroundPixmap) {
1632                 dmxBESavePixmap(pChild->background.pixmap);
1633                 dmxBEFreePixmap(pChild->background.pixmap);
1634             }
1635         }
1636 
1637         if (pChild == pWin)
1638             break;
1639 
1640         pChild = pChild->nextSib;
1641     }
1642 }
1643 
1644 /** Detach back-end screen. */
1645 int
dmxDetachScreen(int idx)1646 dmxDetachScreen(int idx)
1647 {
1648     DMXScreenInfo *dmxScreen = &dmxScreens[idx];
1649     int i;
1650 
1651     /* Return failure if dynamic addition/removal of screens is disabled */
1652     if (!dmxAddRemoveScreens) {
1653         dmxLog(dmxWarning,
1654                "Attempting to remove a screen, but the AddRemoveScreen\n");
1655         dmxLog(dmxWarning,
1656                "extension has not been enabled.  To enable this extension\n");
1657         dmxLog(dmxWarning,
1658                "add the \"-addremovescreens\" option either to the command\n");
1659         dmxLog(dmxWarning, "line or in the configuration file.\n");
1660         return 1;
1661     }
1662 
1663     /* Cannot remove a screen that does not exist */
1664     if (idx < 0 || idx >= dmxNumScreens)
1665         return 1;
1666 
1667     /* Cannot detach from a screen that is not opened */
1668     if (!dmxScreen->beDisplay) {
1669         dmxLog(dmxWarning,
1670                "Attempting to remove screen #%d but it has not been opened\n",
1671                idx);
1672         return 1;
1673     }
1674 
1675     dmxLogOutput(dmxScreen, "Detaching screen #%d\n", idx);
1676 
1677     /* Detach input */
1678     dmxInputDetachAll(dmxScreen);
1679 
1680     /* Save all relevant state (TODO) */
1681 
1682     /* Free all non-window resources related to this screen */
1683     for (i = currentMaxClients; --i >= 0;)
1684         if (clients[i])
1685             FindAllClientResources(clients[i], dmxBEDestroyResources,
1686                                    (void *) (uintptr_t) idx);
1687 
1688     /* Free scratch GCs */
1689     dmxBEDestroyScratchGCs(idx);
1690 
1691     /* Free window resources related to this screen */
1692     dmxBEDestroyWindowTree(idx);
1693 
1694     /* Free default stipple */
1695     dmxBESavePixmap(screenInfo.screens[idx]->defaultStipple);
1696     dmxBEFreePixmap(screenInfo.screens[idx]->defaultStipple);
1697 
1698     /* Free the remaining screen resources and close the screen */
1699     dmxBECloseScreen(screenInfo.screens[idx]);
1700 
1701     /* Adjust the cursor boundaries (paints detached console window) */
1702     dmxAdjustCursorBoundaries();
1703 
1704     return 0;                   /* Success */
1705 }
1706