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