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