2 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
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:
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.
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
30 * Rickard E. (Rik) Faith <faith@redhat.com>
31 * Kevin E. Martin <kem@redhat.com>
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
40 #ifdef HAVE_DMX_CONFIG_H
41 #include <dmx-config.h>
48 #include "dmxextension.h"
49 #include "dmxwindow.h"
51 #include "dmxcursor.h"
52 #include "dmxpixmap.h"
59 #include "dmxscrinit.h"
60 #include "input/dmxinputinit.h"
62 #include "windowstr.h"
63 #include "inputstr.h" /* For DeviceIntRec */
64 #include <X11/extensions/dmxproto.h> /* For DMX_BAD_* */
65 #include "cursorstr.h"
67 /* The default font is declared in dix/globals.c, but is not included in
68 * _any_ header files. */
69 extern FontPtr defaultFont
;
71 /* Hack to get Present to build (present requires RandR) */
74 /** This routine provides information to the DMX protocol extension
75 * about a particular screen. */
77 dmxGetScreenAttributes(int physical
, DMXScreenAttributesPtr attr
)
79 DMXScreenInfo
*dmxScreen
;
81 if (physical
< 0 || physical
>= dmxNumScreens
)
84 dmxScreen
= &dmxScreens
[physical
];
85 attr
->displayName
= dmxScreen
->name
;
87 attr
->logicalScreen
= noPanoramiXExtension
? dmxScreen
->index
: 0;
89 attr
->logicalScreen
= dmxScreen
->index
;
92 attr
->screenWindowWidth
= dmxScreen
->scrnWidth
;
93 attr
->screenWindowHeight
= dmxScreen
->scrnHeight
;
94 attr
->screenWindowXoffset
= dmxScreen
->scrnX
;
95 attr
->screenWindowYoffset
= dmxScreen
->scrnY
;
97 attr
->rootWindowWidth
= dmxScreen
->rootWidth
;
98 attr
->rootWindowHeight
= dmxScreen
->rootHeight
;
99 attr
->rootWindowXoffset
= dmxScreen
->rootX
;
100 attr
->rootWindowYoffset
= dmxScreen
->rootY
;
102 attr
->rootWindowXorigin
= dmxScreen
->rootXOrigin
;
103 attr
->rootWindowYorigin
= dmxScreen
->rootYOrigin
;
108 /** This routine provides information to the DMX protocol extension
109 * about a particular window. */
111 dmxGetWindowAttributes(WindowPtr pWindow
, DMXWindowAttributesPtr attr
)
113 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWindow
);
115 attr
->screen
= pWindow
->drawable
.pScreen
->myNum
;
116 attr
->window
= pWinPriv
->window
;
118 attr
->pos
.x
= pWindow
->drawable
.x
;
119 attr
->pos
.y
= pWindow
->drawable
.y
;
120 attr
->pos
.width
= pWindow
->drawable
.width
;
121 attr
->pos
.height
= pWindow
->drawable
.height
;
123 if (!pWinPriv
->window
|| pWinPriv
->offscreen
) {
126 attr
->vis
.height
= 0;
128 return pWinPriv
->window
? TRUE
: FALSE
;
131 /* Compute display-relative coordinates */
132 attr
->vis
.x
= pWindow
->drawable
.x
;
133 attr
->vis
.y
= pWindow
->drawable
.y
;
134 attr
->vis
.width
= pWindow
->drawable
.width
;
135 attr
->vis
.height
= pWindow
->drawable
.height
;
137 if (attr
->pos
.x
< 0) {
138 attr
->vis
.x
-= attr
->pos
.x
;
139 attr
->vis
.width
= attr
->pos
.x
+ attr
->pos
.width
- attr
->vis
.x
;
141 if (attr
->pos
.x
+ attr
->pos
.width
> pWindow
->drawable
.pScreen
->width
) {
143 attr
->vis
.width
= pWindow
->drawable
.pScreen
->width
;
145 attr
->vis
.width
= pWindow
->drawable
.pScreen
->width
- attr
->pos
.x
;
147 if (attr
->pos
.y
< 0) {
148 attr
->vis
.y
-= attr
->pos
.y
;
149 attr
->vis
.height
= attr
->pos
.y
+ attr
->pos
.height
- attr
->vis
.y
;
151 if (attr
->pos
.y
+ attr
->pos
.height
> pWindow
->drawable
.pScreen
->height
) {
153 attr
->vis
.height
= pWindow
->drawable
.pScreen
->height
;
155 attr
->vis
.height
= pWindow
->drawable
.pScreen
->height
- attr
->pos
.y
;
158 /* Convert to window-relative coordinates */
159 attr
->vis
.x
-= attr
->pos
.x
;
160 attr
->vis
.y
-= attr
->pos
.y
;
166 dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr
)
168 attr
->width
= dmxGlobalWidth
;
169 attr
->height
= dmxGlobalHeight
;
170 attr
->shiftX
= 0; /* NOTE: The upper left hand corner of */
171 attr
->shiftY
= 0; /* the desktop is always <0,0>. */
174 /** Return the total number of devices, not just #dmxNumInputs. The
175 * number returned should be the same as that returned by
176 * XListInputDevices. */
178 dmxGetInputCount(void)
182 for (total
= i
= 0; i
< dmxNumInputs
; i
++)
183 total
+= dmxInputs
[i
].numDevs
;
187 /** Return information about the device with id = \a deviceId. This
188 * information is primarily for the #ProcDMXGetInputAttributes()
189 * function, which does not have access to the appropriate data
192 dmxGetInputAttributes(int deviceId
, DMXInputAttributesPtr attr
)
195 DMXInputInfo
*dmxInput
;
199 for (i
= 0; i
< dmxNumInputs
; i
++) {
200 dmxInput
= &dmxInputs
[i
];
201 for (j
= 0; j
< dmxInput
->numDevs
; j
++) {
202 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[j
];
204 if (deviceId
!= dmxLocal
->pDevice
->id
)
206 attr
->isCore
= ! !dmxLocal
->isCore
;
207 attr
->sendsCore
= ! !dmxLocal
->sendsCore
;
208 attr
->detached
= ! !dmxInput
->detached
;
209 attr
->physicalScreen
= -1;
210 attr
->physicalId
= -1;
212 switch (dmxLocal
->extType
) {
213 case DMX_LOCAL_TYPE_LOCAL
:
216 case DMX_LOCAL_TYPE_CONSOLE
:
218 attr
->name
= dmxInput
->name
;
219 attr
->physicalId
= dmxLocal
->deviceId
;
221 case DMX_LOCAL_TYPE_BACKEND
:
222 case DMX_LOCAL_TYPE_COMMON
:
224 attr
->physicalScreen
= dmxInput
->scrnIdx
;
225 attr
->name
= dmxInput
->name
;
226 attr
->physicalId
= dmxLocal
->deviceId
;
229 return 0; /* Success */
232 return -1; /* Failure */
235 /** Reinitialized the cursor boundaries. */
237 dmxAdjustCursorBoundaries(void)
243 dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX
);
244 dmxConnectionBlockCallback();
245 for (i
= 0; i
< dmxNumInputs
; i
++) {
246 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
248 if (!dmxInput
->detached
)
249 dmxInputReInit(dmxInput
);
254 for (i
= 0; i
< dmxNumInputs
; i
++) {
255 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
257 if (!dmxInput
->detached
)
258 dmxInputLateReInit(dmxInput
);
262 /** Add an input with the specified attributes. If the input is added,
263 * the physical id is returned in \a deviceId. */
265 dmxAddInput(DMXInputAttributesPtr attr
, int *id
)
267 int retcode
= BadValue
;
269 if (attr
->inputType
== 1) /* console */
270 retcode
= dmxInputAttachConsole(attr
->name
, attr
->sendsCore
, id
);
271 else if (attr
->inputType
== 2) /* backend */
272 retcode
= dmxInputAttachBackend(attr
->physicalScreen
,
273 attr
->sendsCore
, id
);
275 if (retcode
== Success
) {
276 /* Adjust the cursor boundaries */
277 dmxAdjustCursorBoundaries();
279 /* Force completion of the changes */
286 /** Remove the input with physical id \a id. */
288 dmxRemoveInput(int id
)
290 return dmxInputDetachId(id
);
293 /** Return the value of #dmxNumScreens -- the total number of backend
294 * screens in use (these are logical screens and may be larger than the
295 * number of backend displays). */
297 dmxGetNumScreens(void)
299 return dmxNumScreens
;
302 /** Make sure that #dmxCreateAndRealizeWindow has been called for \a
305 dmxForceWindowCreation(WindowPtr pWindow
)
307 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWindow
);
309 if (!pWinPriv
->window
)
310 dmxCreateAndRealizeWindow(pWindow
, TRUE
);
313 /** Flush pending syncs for all screens. */
315 dmxFlushPendingSyncs(void)
320 /** Update DMX's screen resources to match those of the newly moved
321 * and/or resized "root" window. */
323 dmxUpdateScreenResources(ScreenPtr pScreen
, int x
, int y
, int w
, int h
)
325 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
326 WindowPtr pRoot
= pScreen
->root
;
328 Bool anyMarked
= FALSE
;
330 /* Handle special case where width and/or height are zero */
331 if (w
== 0 || h
== 0) {
336 /* Change screen size */
340 /* Reset the root window's drawable's size */
341 pRoot
->drawable
.width
= w
;
342 pRoot
->drawable
.height
= h
;
344 /* Set the root window's new winSize and borderSize */
345 pRoot
->winSize
.extents
.x1
= 0;
346 pRoot
->winSize
.extents
.y1
= 0;
347 pRoot
->winSize
.extents
.x2
= w
;
348 pRoot
->winSize
.extents
.y2
= h
;
350 pRoot
->borderSize
.extents
.x1
= 0;
351 pRoot
->borderSize
.extents
.y1
= 0;
352 pRoot
->borderSize
.extents
.x2
= w
;
353 pRoot
->borderSize
.extents
.y2
= h
;
355 /* Recompute this screen's mmWidth & mmHeight */
357 (w
* 254 + dmxScreen
->beXDPI
* 5) / (dmxScreen
->beXDPI
* 10);
359 (h
* 254 + dmxScreen
->beYDPI
* 5) / (dmxScreen
->beYDPI
* 10);
361 /* Recompute this screen's window's clip rects as follows: */
362 /* 1. Mark all of root's children's windows */
363 for (pChild
= pRoot
->firstChild
; pChild
; pChild
= pChild
->nextSib
)
364 anyMarked
|= pScreen
->MarkOverlappedWindows(pChild
, pChild
,
367 /* 2. Set the root window's borderClip */
368 pRoot
->borderClip
.extents
.x1
= 0;
369 pRoot
->borderClip
.extents
.y1
= 0;
370 pRoot
->borderClip
.extents
.x2
= w
;
371 pRoot
->borderClip
.extents
.y2
= h
;
373 /* 3. Set the root window's clipList */
375 /* If any windows have been marked, set the root window's
376 * clipList to be broken since it will be recalculated in
379 RegionBreak(&pRoot
->clipList
);
382 /* Otherwise, we just set it directly since there are no
383 * windows visible on this screen
385 pRoot
->clipList
.extents
.x1
= 0;
386 pRoot
->clipList
.extents
.y1
= 0;
387 pRoot
->clipList
.extents
.x2
= w
;
388 pRoot
->clipList
.extents
.y2
= h
;
391 /* 4. Revalidate all clip rects and generate expose events */
393 pScreen
->ValidateTree(pRoot
, NULL
, VTBroken
);
394 pScreen
->HandleExposures(pRoot
);
395 if (pScreen
->PostValidateTree
)
396 pScreen
->PostValidateTree(pRoot
, NULL
, VTBroken
);
401 #include "panoramiXsrv.h"
403 /** Change the "screen" window attributes by resizing the actual window
404 * on the back-end display (if necessary). */
406 dmxConfigureScreenWindow(int idx
, int x
, int y
, int w
, int h
)
408 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
409 ScreenPtr pScreen
= screenInfo
.screens
[idx
];
411 /* Resize "screen" window */
412 if (dmxScreen
->scrnX
!= x
||
413 dmxScreen
->scrnY
!= y
||
414 dmxScreen
->scrnWidth
!= w
|| dmxScreen
->scrnHeight
!= h
) {
415 dmxResizeScreenWindow(pScreen
, x
, y
, w
, h
);
418 /* Change "screen" window values */
419 dmxScreen
->scrnX
= x
;
420 dmxScreen
->scrnY
= y
;
421 dmxScreen
->scrnWidth
= w
;
422 dmxScreen
->scrnHeight
= h
;
425 /** Change the "root" window position and size by resizing the actual
426 * window on the back-end display (if necessary) and updating all of
427 * DMX's resources by calling #dmxUpdateScreenResources. */
429 dmxConfigureRootWindow(int idx
, int x
, int y
, int w
, int h
)
431 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
432 WindowPtr pRoot
= screenInfo
.screens
[idx
]->root
;
434 /* NOTE: Either this function or the ones that it calls must handle
435 * the case where w == 0 || h == 0. Currently, the functions that
436 * this one calls handle that case. */
438 /* 1. Resize "root" window */
439 if (dmxScreen
->rootX
!= x
||
440 dmxScreen
->rootY
!= y
||
441 dmxScreen
->rootWidth
!= w
|| dmxScreen
->rootHeight
!= h
) {
442 dmxResizeRootWindow(pRoot
, x
, y
, w
, h
);
445 /* 2. Update all of the screen's resources associated with this root
447 if (dmxScreen
->rootWidth
!= w
|| dmxScreen
->rootHeight
!= h
) {
448 dmxUpdateScreenResources(screenInfo
.screens
[idx
], x
, y
, w
, h
);
451 /* Change "root" window values */
452 dmxScreen
->rootX
= x
;
453 dmxScreen
->rootY
= y
;
454 dmxScreen
->rootWidth
= w
;
455 dmxScreen
->rootHeight
= h
;
458 /** Change the "root" window's origin by updating DMX's internal data
459 * structures (dix and Xinerama) to use the new origin and adjust the
460 * positions of windows that overlap this "root" window. */
462 dmxSetRootWindowOrigin(int idx
, int x
, int y
)
464 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
465 ScreenPtr pScreen
= screenInfo
.screens
[idx
];
466 WindowPtr pRoot
= pScreen
->root
;
471 /* Change "root" window's origin */
472 dmxScreen
->rootXOrigin
= x
;
473 dmxScreen
->rootYOrigin
= y
;
475 /* Compute offsets here in case <x,y> has been changed above */
476 xoff
= x
- pScreen
->x
;
477 yoff
= y
- pScreen
->y
;
479 /* Adjust the root window's position */
480 pScreen
->x
= dmxScreen
->rootXOrigin
;
481 pScreen
->y
= dmxScreen
->rootYOrigin
;
483 /* Recalculate the Xinerama regions and data structs */
484 XineramaReinitData();
486 /* Adjust each of the root window's children */
488 ReinitializeRootWindow(screenInfo
.screens
[0]->root
, xoff
, yoff
);
489 pChild
= pRoot
->firstChild
;
491 /* Adjust child window's position */
492 pScreen
->MoveWindow(pChild
,
493 pChild
->origin
.x
- wBorderWidth(pChild
) - xoff
,
494 pChild
->origin
.y
- wBorderWidth(pChild
) - yoff
,
495 pChild
->nextSib
, VTMove
);
497 /* Note that the call to MoveWindow will eventually call
498 * dmxPositionWindow which will automatically create a
499 * window if it is now exposed on screen (for lazy window
500 * creation optimization) and it will properly set the
504 pChild
= pChild
->nextSib
;
508 /** Configure the attributes of each "screen" and "root" window. */
510 dmxConfigureScreenWindows(int nscreens
,
512 DMXScreenAttributesPtr attribs
, int *errorScreen
)
516 for (i
= 0; i
< nscreens
; i
++) {
517 DMXScreenAttributesPtr attr
= &attribs
[i
];
518 int idx
= screens
[i
];
519 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
524 if (!dmxScreen
->beDisplay
)
525 return DMX_BAD_VALUE
;
527 /* Check for illegal values */
528 if (idx
< 0 || idx
>= dmxNumScreens
)
531 /* The "screen" and "root" windows must have valid sizes */
532 if (attr
->screenWindowWidth
<= 0 || attr
->screenWindowHeight
<= 0 ||
533 attr
->rootWindowWidth
< 0 || attr
->rootWindowHeight
< 0)
534 return DMX_BAD_VALUE
;
536 /* The "screen" window must fit entirely within the BE display */
537 if (attr
->screenWindowXoffset
< 0 ||
538 attr
->screenWindowYoffset
< 0 ||
539 attr
->screenWindowXoffset
540 + attr
->screenWindowWidth
> (unsigned) dmxScreen
->beWidth
||
541 attr
->screenWindowYoffset
542 + attr
->screenWindowHeight
> (unsigned) dmxScreen
->beHeight
)
543 return DMX_BAD_VALUE
;
545 /* The "root" window must fit entirely within the "screen" window */
546 if (attr
->rootWindowXoffset
< 0 ||
547 attr
->rootWindowYoffset
< 0 ||
548 attr
->rootWindowXoffset
549 + attr
->rootWindowWidth
> attr
->screenWindowWidth
||
550 attr
->rootWindowYoffset
551 + attr
->rootWindowHeight
> attr
->screenWindowHeight
)
552 return DMX_BAD_VALUE
;
554 /* The "root" window must not expose unaddressable coordinates */
555 if (attr
->rootWindowXorigin
< 0 ||
556 attr
->rootWindowYorigin
< 0 ||
557 attr
->rootWindowXorigin
+ attr
->rootWindowWidth
> 32767 ||
558 attr
->rootWindowYorigin
+ attr
->rootWindowHeight
> 32767)
559 return DMX_BAD_VALUE
;
561 /* The "root" window must fit within the global bounding box */
562 if (attr
->rootWindowXorigin
563 + attr
->rootWindowWidth
> (unsigned) dmxGlobalWidth
||
564 attr
->rootWindowYorigin
565 + attr
->rootWindowHeight
> (unsigned) dmxGlobalHeight
)
566 return DMX_BAD_VALUE
;
568 /* FIXME: Handle the rest of the illegal value checking */
571 /* No illegal values found */
575 for (i
= 0; i
< nscreens
; i
++) {
576 DMXScreenAttributesPtr attr
= &attribs
[i
];
577 int idx
= screens
[i
];
578 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
580 dmxLog(dmxInfo
, "Changing screen #%d attributes "
581 "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d "
582 "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n",
584 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
585 dmxScreen
->scrnX
, dmxScreen
->scrnY
,
586 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
587 dmxScreen
->rootX
, dmxScreen
->rootY
,
588 dmxScreen
->rootXOrigin
, dmxScreen
->rootYOrigin
,
589 attr
->screenWindowWidth
, attr
->screenWindowHeight
,
590 attr
->screenWindowXoffset
, attr
->screenWindowYoffset
,
591 attr
->rootWindowWidth
, attr
->rootWindowHeight
,
592 attr
->rootWindowXoffset
, attr
->rootWindowYoffset
,
593 attr
->rootWindowXorigin
, attr
->rootWindowYorigin
);
595 /* Configure "screen" window */
596 dmxConfigureScreenWindow(idx
,
597 attr
->screenWindowXoffset
,
598 attr
->screenWindowYoffset
,
599 attr
->screenWindowWidth
,
600 attr
->screenWindowHeight
);
602 /* Configure "root" window */
603 dmxConfigureRootWindow(idx
,
604 attr
->rootWindowXoffset
,
605 attr
->rootWindowYoffset
,
606 attr
->rootWindowWidth
, attr
->rootWindowHeight
);
608 /* Set "root" window's origin */
609 dmxSetRootWindowOrigin(idx
,
610 attr
->rootWindowXorigin
,
611 attr
->rootWindowYorigin
);
614 /* Adjust the cursor boundaries */
615 dmxAdjustCursorBoundaries();
617 /* Force completion of the changes */
623 /** Configure the attributes of the global desktop. */
625 dmxConfigureDesktop(DMXDesktopAttributesPtr attribs
)
627 if (attribs
->width
<= 0 || attribs
->width
>= 32767 ||
628 attribs
->height
<= 0 || attribs
->height
>= 32767)
629 return DMX_BAD_VALUE
;
631 /* If the desktop is shrinking, adjust the "root" windows on each
632 * "screen" window to only show the visible desktop. Also, handle
633 * the special case where the desktop shrinks such that the it no
634 * longer overlaps an portion of a "screen" window. */
635 if (attribs
->width
< dmxGlobalWidth
|| attribs
->height
< dmxGlobalHeight
) {
638 for (i
= 0; i
< dmxNumScreens
; i
++) {
639 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
641 if (dmxScreen
->rootXOrigin
642 + dmxScreen
->rootWidth
> attribs
->width
||
643 dmxScreen
->rootYOrigin
644 + dmxScreen
->rootHeight
> attribs
->height
) {
647 if ((w
= attribs
->width
- dmxScreen
->rootXOrigin
) < 0)
649 if ((h
= attribs
->height
- dmxScreen
->rootYOrigin
) < 0)
651 if (w
> dmxScreen
->scrnWidth
)
652 w
= dmxScreen
->scrnWidth
;
653 if (h
> dmxScreen
->scrnHeight
)
654 h
= dmxScreen
->scrnHeight
;
655 if (w
> dmxScreen
->rootWidth
)
656 w
= dmxScreen
->rootWidth
;
657 if (h
> dmxScreen
->rootHeight
)
658 h
= dmxScreen
->rootHeight
;
659 dmxConfigureRootWindow(i
,
661 dmxScreen
->rootY
, w
, h
);
666 /* Set the global width/height */
667 dmxSetWidthHeight(attribs
->width
, attribs
->height
);
669 /* Handle shift[XY] changes */
670 if (attribs
->shiftX
|| attribs
->shiftY
) {
673 for (i
= 0; i
< dmxNumScreens
; i
++) {
674 ScreenPtr pScreen
= screenInfo
.screens
[i
];
675 WindowPtr pChild
= pScreen
->root
->firstChild
;
678 /* Adjust child window's position */
679 pScreen
->MoveWindow(pChild
,
680 pChild
->origin
.x
- wBorderWidth(pChild
)
682 pChild
->origin
.y
- wBorderWidth(pChild
)
683 - attribs
->shiftY
, pChild
->nextSib
, VTMove
);
685 /* Note that the call to MoveWindow will eventually call
686 * dmxPositionWindow which will automatically create a
687 * window if it is now exposed on screen (for lazy
688 * window creation optimization) and it will properly
689 * set the offscreen flag.
692 pChild
= pChild
->nextSib
;
697 /* Update connection block, Xinerama, etc. -- these appears to
698 * already be handled in dmxConnectionBlockCallback(), which is
699 * called from dmxAdjustCursorBoundaries() [below]. */
701 /* Adjust the cursor boundaries */
702 dmxAdjustCursorBoundaries();
704 /* Force completion of the changes */
711 /** Create the scratch GCs per depth. */
713 dmxBECreateScratchGCs(int scrnNum
)
715 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
716 GCPtr
*ppGC
= pScreen
->GCperDepth
;
719 for (i
= 0; i
<= pScreen
->numDepths
; i
++)
720 dmxBECreateGC(pScreen
, ppGC
[i
]);
724 static Bool FoundPixImage
;
726 /** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs
727 * to have its image restored. When it is found, see if there is
728 * another screen with the same image. If so, copy the pixmap image
729 * from the existing screen to the newly created pixmap. */
731 dmxBERestorePixmapImage(pointer value
, XID id
, RESTYPE type
, pointer p
)
733 if ((type
& TypeMask
) == (XRT_PIXMAP
& TypeMask
)) {
734 PixmapPtr pDst
= (PixmapPtr
) p
;
735 int idx
= pDst
->drawable
.pScreen
->myNum
;
736 PanoramiXRes
*pXinPix
= (PanoramiXRes
*) value
;
740 dixLookupResourceByType((pointer
*) &pPix
, pXinPix
->info
[idx
].id
,
741 RT_PIXMAP
, NullClient
, DixUnknownAccess
);
743 return; /* Not a match.... Next! */
747 dmxPixPrivPtr pSrcPriv
= NULL
;
750 continue; /* Self replication is bad */
752 dixLookupResourceByType((pointer
*) &pSrc
, pXinPix
->info
[i
].id
,
753 RT_PIXMAP
, NullClient
, DixUnknownAccess
);
754 pSrcPriv
= DMX_GET_PIXMAP_PRIV(pSrc
);
755 if (pSrcPriv
->pixmap
) {
756 DMXScreenInfo
*dmxSrcScreen
= &dmxScreens
[i
];
757 DMXScreenInfo
*dmxDstScreen
= &dmxScreens
[idx
];
758 dmxPixPrivPtr pDstPriv
= DMX_GET_PIXMAP_PRIV(pDst
);
763 /* This should never happen, but just in case.... */
764 if (pSrc
->drawable
.width
!= pDst
->drawable
.width
||
765 pSrc
->drawable
.height
!= pDst
->drawable
.height
)
768 /* Copy from src pixmap to dst pixmap */
769 img
= XGetImage(dmxSrcScreen
->beDisplay
,
772 pSrc
->drawable
.width
, pSrc
->drawable
.height
,
775 for (j
= 0; j
< dmxDstScreen
->beNumPixmapFormats
; j
++) {
776 if (dmxDstScreen
->bePixmapFormats
[j
].depth
== img
->depth
) {
780 m
= GCFunction
| GCPlaneMask
| GCClipMask
;
782 v
.plane_mask
= AllPlanes
;
785 gc
= XCreateGC(dmxDstScreen
->beDisplay
,
786 dmxDstScreen
->scrnDefDrawables
[j
],
793 XPutImage(dmxDstScreen
->beDisplay
,
796 pDst
->drawable
.width
, pDst
->drawable
.height
);
797 XFreeGC(dmxDstScreen
->beDisplay
, gc
);
798 FoundPixImage
= True
;
801 dmxLog(dmxWarning
, "Could not create GC\n");
812 /** Restore the pixmap image either from another screen or from an image
813 * that was saved when the screen was previously detached. */
815 dmxBERestorePixmap(PixmapPtr pPixmap
)
820 /* If Xinerama is not active, there's nothing we can do (see comment
821 * in #else below for more info). */
822 if (noPanoramiXExtension
) {
823 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
827 FoundPixImage
= False
;
828 for (i
= currentMaxClients
; --i
>= 0;)
830 FindAllClientResources(clients
[i
], dmxBERestorePixmapImage
,
833 /* No corresponding pixmap image was found on other screens, so we
834 * need to copy it from the saved image when the screen was detached
836 if (!FoundPixImage
) {
837 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pPixmap
);
839 if (pPixPriv
->detachedImage
) {
840 ScreenPtr pScreen
= pPixmap
->drawable
.pScreen
;
841 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
844 for (i
= 0; i
< dmxScreen
->beNumPixmapFormats
; i
++) {
845 if (dmxScreen
->bePixmapFormats
[i
].depth
==
846 pPixPriv
->detachedImage
->depth
) {
850 m
= GCFunction
| GCPlaneMask
| GCClipMask
;
852 v
.plane_mask
= AllPlanes
;
855 gc
= XCreateGC(dmxScreen
->beDisplay
,
856 dmxScreen
->scrnDefDrawables
[i
], m
, &v
);
862 XPutImage(dmxScreen
->beDisplay
,
865 pPixPriv
->detachedImage
,
867 pPixmap
->drawable
.width
, pPixmap
->drawable
.height
);
868 XFreeGC(dmxScreen
->beDisplay
, gc
);
871 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
874 XDestroyImage(pPixPriv
->detachedImage
);
875 pPixPriv
->detachedImage
= NULL
;
878 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
882 /* If Xinerama is not enabled, then there is no other copy of the
883 * pixmap image that we can restore. Saving all pixmap data is not
884 * a feasible option since there is no mechanism for updating pixmap
885 * data when a screen is detached, which means that the data that
886 * was previously saved would most likely be out of date. */
887 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
892 /** Create resources on the back-end server. This function is called
893 * from #dmxAttachScreen() via the dix layer's FindAllResources
894 * function. It walks all resources, compares them to the screen
895 * number passed in as \a n and calls the appropriate DMX function to
896 * create the associated resource on the back-end server. */
898 dmxBECreateResources(pointer value
, XID id
, RESTYPE type
, pointer n
)
900 int scrnNum
= (uintptr_t) n
;
901 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
903 if ((type
& TypeMask
) == (RT_WINDOW
& TypeMask
)) {
904 /* Window resources are created below in dmxBECreateWindowTree */
906 else if ((type
& TypeMask
) == (RT_PIXMAP
& TypeMask
)) {
907 PixmapPtr pPix
= value
;
909 if (pPix
->drawable
.pScreen
->myNum
== scrnNum
) {
910 dmxBECreatePixmap(pPix
);
911 dmxBERestorePixmap(pPix
);
914 else if ((type
& TypeMask
) == (RT_GC
& TypeMask
)) {
917 if (pGC
->pScreen
->myNum
== scrnNum
) {
918 /* Create the GC on the back-end server */
919 dmxBECreateGC(pScreen
, pGC
);
920 /* Create any pixmaps associated with this GC */
921 if (!pGC
->tileIsPixel
) {
922 dmxBECreatePixmap(pGC
->tile
.pixmap
);
923 dmxBERestorePixmap(pGC
->tile
.pixmap
);
925 if (pGC
->stipple
!= pScreen
->PixmapPerDepth
[0]) {
926 dmxBECreatePixmap(pGC
->stipple
);
927 dmxBERestorePixmap(pGC
->stipple
);
929 if (pGC
->font
!= defaultFont
) {
930 (void) dmxBELoadFont(pScreen
, pGC
->font
);
932 /* Update the GC on the back-end server */
933 dmxChangeGC(pGC
, -1L);
936 else if ((type
& TypeMask
) == (RT_FONT
& TypeMask
)) {
937 (void) dmxBELoadFont(pScreen
, (FontPtr
) value
);
939 else if ((type
& TypeMask
) == (RT_CURSOR
& TypeMask
)) {
940 dmxBECreateCursor(pScreen
, (CursorPtr
) value
);
942 else if ((type
& TypeMask
) == (RT_COLORMAP
& TypeMask
)) {
943 ColormapPtr pCmap
= value
;
945 if (pCmap
->pScreen
->myNum
== scrnNum
)
946 (void) dmxBECreateColormap((ColormapPtr
) value
);
948 /* TODO: Recreate Picture and GlyphSet resources */
950 else if ((type
& TypeMask
) == (PictureType
& TypeMask
)) {
951 /* Picture resources are created when windows are created */
953 else if ((type
& TypeMask
) == (GlyphSetType
& TypeMask
)) {
954 dmxBEFreeGlyphSet(pScreen
, (GlyphSetPtr
) value
);
958 /* Other resource types??? */
962 /** Create window hierachy on back-end server. The window tree is
963 * created in a special order (bottom most subwindow first) so that the
964 * #dmxCreateNonRootWindow() function does not need to recursively call
965 * itself to create each window's parents. This is required so that we
966 * have the opportunity to create each window's border and background
967 * pixmaps (where appropriate) before the window is created. */
969 dmxBECreateWindowTree(int idx
)
971 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
972 WindowPtr pRoot
= screenInfo
.screens
[idx
]->root
;
973 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pRoot
);
976 /* Create the pixmaps associated with the root window */
977 if (!pRoot
->borderIsPixel
) {
978 dmxBECreatePixmap(pRoot
->border
.pixmap
);
979 dmxBERestorePixmap(pRoot
->border
.pixmap
);
981 if (pRoot
->backgroundState
== BackgroundPixmap
) {
982 dmxBECreatePixmap(pRoot
->background
.pixmap
);
983 dmxBERestorePixmap(pRoot
->background
.pixmap
);
986 /* Create root window first */
987 dmxScreen
->rootWin
= pWinPriv
->window
= dmxCreateRootWindow(pRoot
);
988 XMapWindow(dmxScreen
->beDisplay
, dmxScreen
->rootWin
);
990 pWin
= pRoot
->lastChild
;
992 pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
994 /* Create the pixmaps regardless of whether or not the
995 * window is created or not due to lazy window creation.
997 if (!pWin
->borderIsPixel
) {
998 dmxBECreatePixmap(pWin
->border
.pixmap
);
999 dmxBERestorePixmap(pWin
->border
.pixmap
);
1001 if (pWin
->backgroundState
== BackgroundPixmap
) {
1002 dmxBECreatePixmap(pWin
->background
.pixmap
);
1003 dmxBERestorePixmap(pWin
->background
.pixmap
);
1006 /* Reset the window attributes */
1007 dmxGetDefaultWindowAttributes(pWin
, &pWinPriv
->cmap
, &pWinPriv
->visual
);
1009 /* Create the window */
1010 if (pWinPriv
->mapped
&& !pWinPriv
->offscreen
)
1011 dmxCreateAndRealizeWindow(pWin
, TRUE
);
1013 /* Next, create the bottom-most child */
1014 if (pWin
->lastChild
) {
1015 pWin
= pWin
->lastChild
;
1019 /* If the window has no children, move on to the next higher window */
1020 while (!pWin
->prevSib
&& (pWin
!= pRoot
))
1021 pWin
= pWin
->parent
;
1023 if (pWin
->prevSib
) {
1024 pWin
= pWin
->prevSib
;
1028 /* When we reach the root window, we are finished */
1034 /* Refresh screen by generating exposure events for all windows */
1036 dmxForceExposures(int idx
)
1038 ScreenPtr pScreen
= screenInfo
.screens
[idx
];
1039 WindowPtr pRoot
= pScreen
->root
;
1040 Bool anyMarked
= FALSE
;
1043 for (pChild
= pRoot
->firstChild
; pChild
; pChild
= pChild
->nextSib
)
1044 anyMarked
|= pScreen
->MarkOverlappedWindows(pChild
, pChild
,
1045 (WindowPtr
*) NULL
);
1047 /* If any windows have been marked, set the root window's
1048 * clipList to be broken since it will be recalculated in
1051 RegionBreak(&pRoot
->clipList
);
1052 pScreen
->ValidateTree(pRoot
, NULL
, VTBroken
);
1053 pScreen
->HandleExposures(pRoot
);
1054 if (pScreen
->PostValidateTree
)
1055 pScreen
->PostValidateTree(pRoot
, NULL
, VTBroken
);
1059 /** Compare the new and old screens to see if they are compatible. */
1061 dmxCompareScreens(DMXScreenInfo
* new, DMXScreenInfo
* old
)
1065 if (new->beWidth
!= old
->beWidth
)
1067 if (new->beHeight
!= old
->beHeight
)
1069 if (new->beDepth
!= old
->beDepth
)
1071 if (new->beBPP
!= old
->beBPP
)
1074 if (new->beNumDepths
!= old
->beNumDepths
)
1076 for (i
= 0; i
< old
->beNumDepths
; i
++)
1077 if (new->beDepths
[i
] != old
->beDepths
[i
])
1080 if (new->beNumPixmapFormats
!= old
->beNumPixmapFormats
)
1082 for (i
= 0; i
< old
->beNumPixmapFormats
; i
++) {
1083 if (new->bePixmapFormats
[i
].depth
!= old
->bePixmapFormats
[i
].depth
)
1085 if (new->bePixmapFormats
[i
].bits_per_pixel
!=
1086 old
->bePixmapFormats
[i
].bits_per_pixel
)
1088 if (new->bePixmapFormats
[i
].scanline_pad
!=
1089 old
->bePixmapFormats
[i
].scanline_pad
)
1093 if (new->beNumVisuals
!= old
->beNumVisuals
)
1095 for (i
= 0; i
< old
->beNumVisuals
; i
++) {
1096 if (new->beVisuals
[i
].visualid
!= old
->beVisuals
[i
].visualid
)
1098 if (new->beVisuals
[i
].screen
!= old
->beVisuals
[i
].screen
)
1100 if (new->beVisuals
[i
].depth
!= old
->beVisuals
[i
].depth
)
1102 if (new->beVisuals
[i
].class != old
->beVisuals
[i
].class)
1104 if (new->beVisuals
[i
].red_mask
!= old
->beVisuals
[i
].red_mask
)
1106 if (new->beVisuals
[i
].green_mask
!= old
->beVisuals
[i
].green_mask
)
1108 if (new->beVisuals
[i
].blue_mask
!= old
->beVisuals
[i
].blue_mask
)
1110 if (new->beVisuals
[i
].colormap_size
!= old
->beVisuals
[i
].colormap_size
)
1112 if (new->beVisuals
[i
].bits_per_rgb
!= old
->beVisuals
[i
].bits_per_rgb
)
1116 if (new->beDefVisualIndex
!= old
->beDefVisualIndex
)
1122 /** Restore Render's picture */
1124 dmxBERestoreRenderPict(pointer value
, XID id
, pointer n
)
1126 PicturePtr pPicture
= value
; /* The picture */
1127 DrawablePtr pDraw
= pPicture
->pDrawable
; /* The picture's drawable */
1128 int scrnNum
= (uintptr_t) n
;
1130 if (pDraw
->pScreen
->myNum
!= scrnNum
) {
1131 /* Picture not on the screen we are restoring */
1135 if (pDraw
->type
== DRAWABLE_PIXMAP
) {
1136 PixmapPtr pPixmap
= (PixmapPtr
) pDraw
;
1138 /* Create and restore the pixmap drawable */
1139 dmxBECreatePixmap(pPixmap
);
1140 dmxBERestorePixmap(pPixmap
);
1143 dmxBECreatePicture(pPicture
);
1146 /** Restore Render's glyphs */
1148 dmxBERestoreRenderGlyph(pointer value
, XID id
, pointer n
)
1150 GlyphSetPtr glyphSet
= value
;
1151 int scrnNum
= (uintptr_t) n
;
1152 dmxGlyphPrivPtr glyphPriv
= DMX_GET_GLYPH_PRIV(glyphSet
);
1153 DMXScreenInfo
*dmxScreen
= &dmxScreens
[scrnNum
];
1164 if (glyphPriv
->glyphSets
[scrnNum
]) {
1165 /* Only restore glyphs on the screen we are attaching */
1169 /* First we must create the glyph set on the backend. */
1170 if ((beret
= dmxBECreateGlyphSet(scrnNum
, glyphSet
)) != Success
) {
1172 "\tdmxBERestoreRenderGlyph failed to create glyphset!\n");
1176 /* Now for the complex part, restore the glyph data */
1177 table
= glyphSet
->hash
.table
;
1179 /* We need to know how much memory to allocate for this part */
1180 for (i
= 0; i
< glyphSet
->hash
.hashSet
->size
; i
++) {
1181 GlyphRefPtr gr
= &table
[i
];
1182 GlyphPtr gl
= gr
->glyph
;
1184 if (!gl
|| gl
== DeletedGlyph
)
1186 len_images
+= gl
->size
- sizeof(gl
->info
);
1189 /* Now allocate the memory we need */
1190 images
= calloc(len_images
, sizeof(char));
1191 gids
= malloc(glyphSet
->hash
.tableEntries
* sizeof(Glyph
));
1192 glyphs
= malloc(glyphSet
->hash
.tableEntries
* sizeof(XGlyphInfo
));
1197 /* Fill the allocated memory with the proper data */
1198 for (i
= 0; i
< glyphSet
->hash
.hashSet
->size
; i
++) {
1199 GlyphRefPtr gr
= &table
[i
];
1200 GlyphPtr gl
= gr
->glyph
;
1202 if (!gl
|| gl
== DeletedGlyph
)
1205 /* First lets put the data into gids */
1206 gids
[ctr
] = gr
->signature
;
1208 /* Next do the glyphs data structures */
1209 glyphs
[ctr
].width
= gl
->info
.width
;
1210 glyphs
[ctr
].height
= gl
->info
.height
;
1211 glyphs
[ctr
].x
= gl
->info
.x
;
1212 glyphs
[ctr
].y
= gl
->info
.y
;
1213 glyphs
[ctr
].xOff
= gl
->info
.xOff
;
1214 glyphs
[ctr
].yOff
= gl
->info
.yOff
;
1216 /* Copy the images from the DIX's data into the buffer */
1217 memcpy(pos
, gl
+ 1, gl
->size
- sizeof(gl
->info
));
1218 pos
+= gl
->size
- sizeof(gl
->info
);
1222 /* Now restore the glyph data */
1223 XRenderAddGlyphs(dmxScreen
->beDisplay
, glyphPriv
->glyphSets
[scrnNum
],
1224 gids
, glyphs
, glyphSet
->hash
.tableEntries
, images
,
1233 /** Reattach previously detached back-end screen. */
1235 dmxAttachScreen(int idx
, DMXScreenAttributesPtr attr
)
1238 DMXScreenInfo
*dmxScreen
;
1239 CARD32 scrnNum
= idx
;
1240 DMXScreenInfo oldDMXScreen
;
1243 /* Return failure if dynamic addition/removal of screens is disabled */
1244 if (!dmxAddRemoveScreens
) {
1246 "Attempting to add a screen, but the AddRemoveScreen\n");
1248 "extension has not been enabled. To enable this extension\n");
1250 "add the \"-addremovescreens\" option either to the command\n");
1251 dmxLog(dmxWarning
, "line or in the configuration file.\n");
1255 /* Cannot add a screen that does not exist */
1256 if (idx
< 0 || idx
>= dmxNumScreens
)
1258 pScreen
= screenInfo
.screens
[idx
];
1259 dmxScreen
= &dmxScreens
[idx
];
1261 /* Cannot attach to a screen that is already opened */
1262 if (dmxScreen
->beDisplay
) {
1264 "Attempting to add screen #%d but a screen already exists\n",
1269 dmxLogOutput(dmxScreen
, "Attaching screen #%d\n", idx
);
1272 oldDMXScreen
= *dmxScreen
;
1274 /* Copy the name to the new screen */
1275 dmxScreen
->name
= strdup(attr
->displayName
);
1277 /* Open display and get all of the screen info */
1278 if (!dmxOpenDisplay(dmxScreen
)) {
1280 "dmxOpenDisplay: Unable to open display %s\n", dmxScreen
->name
);
1282 /* Restore the old screen */
1283 *dmxScreen
= oldDMXScreen
;
1287 dmxSetErrorHandler(dmxScreen
);
1288 dmxCheckForWM(dmxScreen
);
1289 dmxGetScreenAttribs(dmxScreen
);
1291 if (!dmxGetVisualInfo(dmxScreen
)) {
1292 dmxLog(dmxWarning
, "dmxGetVisualInfo: No matching visuals found\n");
1293 XFree(dmxScreen
->beVisuals
);
1294 XCloseDisplay(dmxScreen
->beDisplay
);
1296 /* Restore the old screen */
1297 *dmxScreen
= oldDMXScreen
;
1301 dmxGetColormaps(dmxScreen
);
1302 dmxGetPixmapFormats(dmxScreen
);
1304 /* Verify that the screen to be added has the same info as the
1305 * previously added screen. */
1306 if (!dmxCompareScreens(dmxScreen
, &oldDMXScreen
)) {
1308 "New screen data (%s) does not match previously\n",
1310 dmxLog(dmxWarning
, "attached screen data (%s)\n", oldDMXScreen
.name
);
1312 "All data must match in order to attach to screen #%d\n", idx
);
1313 XFree(dmxScreen
->beVisuals
);
1314 XFree(dmxScreen
->beDepths
);
1315 XFree(dmxScreen
->bePixmapFormats
);
1316 XCloseDisplay(dmxScreen
->beDisplay
);
1318 /* Restore the old screen */
1319 *dmxScreen
= oldDMXScreen
;
1323 /* Initialize the BE screen resources */
1324 dmxBEScreenInit(screenInfo
.screens
[idx
]);
1326 /* TODO: Handle GLX visual initialization. GLXProxy needs to be
1327 * updated to handle dynamic addition/removal of screens. */
1329 /* Create default stipple */
1330 dmxBECreatePixmap(pScreen
->PixmapPerDepth
[0]);
1331 dmxBERestorePixmap(pScreen
->PixmapPerDepth
[0]);
1333 /* Create the scratch GCs */
1334 dmxBECreateScratchGCs(idx
);
1336 /* Create the default font */
1337 (void) dmxBELoadFont(pScreen
, defaultFont
);
1339 /* Create all resources that don't depend on windows */
1340 for (i
= currentMaxClients
; --i
>= 0;)
1342 FindAllClientResources(clients
[i
], dmxBECreateResources
,
1343 (pointer
) (uintptr_t) idx
);
1345 /* Create window hierarchy (top down) */
1346 dmxBECreateWindowTree(idx
);
1348 /* Restore the picture state for RENDER */
1349 for (i
= currentMaxClients
; --i
>= 0;)
1351 FindClientResourcesByType(clients
[i
], PictureType
,
1352 dmxBERestoreRenderPict
,
1353 (pointer
) (uintptr_t) idx
);
1355 /* Restore the glyph state for RENDER */
1356 for (i
= currentMaxClients
; --i
>= 0;)
1358 FindClientResourcesByType(clients
[i
], GlyphSetType
,
1359 dmxBERestoreRenderGlyph
,
1360 (pointer
) (uintptr_t) idx
);
1362 /* Refresh screen by generating exposure events for all windows */
1363 dmxForceExposures(idx
);
1365 dmxSync(&dmxScreens
[idx
], TRUE
);
1367 /* We used these to compare the old and new screens. They are no
1368 * longer needed since we have a newly attached screen, so we can
1369 * now free the old screen's resources. */
1370 XFree(oldDMXScreen
.beVisuals
);
1371 XFree(oldDMXScreen
.beDepths
);
1372 XFree(oldDMXScreen
.bePixmapFormats
);
1373 /* TODO: should oldDMXScreen.name be freed?? */
1376 if (!noPanoramiXExtension
)
1377 return dmxConfigureScreenWindows(1, &scrnNum
, attr
, NULL
);
1380 return 0; /* Success */
1384 * Resources that may have state on the BE server and need to be freed:
1415 * SecurityAuthorizationResType
1425 /** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs
1426 * to have its image saved. */
1428 dmxBEFindPixmapImage(pointer value
, XID id
, RESTYPE type
, pointer p
)
1430 if ((type
& TypeMask
) == (XRT_PIXMAP
& TypeMask
)) {
1431 PixmapPtr pDst
= (PixmapPtr
) p
;
1432 int idx
= pDst
->drawable
.pScreen
->myNum
;
1433 PanoramiXRes
*pXinPix
= (PanoramiXRes
*) value
;
1437 dixLookupResourceByType((pointer
*) &pPix
, pXinPix
->info
[idx
].id
,
1438 RT_PIXMAP
, NullClient
, DixUnknownAccess
);
1440 return; /* Not a match.... Next! */
1444 dmxPixPrivPtr pSrcPriv
= NULL
;
1447 continue; /* Self replication is bad */
1449 dixLookupResourceByType((pointer
*) &pSrc
, pXinPix
->info
[i
].id
,
1450 RT_PIXMAP
, NullClient
, DixUnknownAccess
);
1451 pSrcPriv
= DMX_GET_PIXMAP_PRIV(pSrc
);
1452 if (pSrcPriv
->pixmap
) {
1453 FoundPixImage
= True
;
1461 /** Save the pixmap image only when there is not another screen with
1462 * that pixmap from which the image can be read when the screen is
1463 * reattached. To do this, we first try to find a pixmap on another
1464 * screen corresponding to the one we are trying to save. If we find
1465 * one, then we do not need to save the image data since during
1466 * reattachment, the image data can be read from that other pixmap.
1467 * However, if we do not find one, then we need to save the image data.
1468 * The common case for these are for the default stipple and root
1471 dmxBESavePixmap(PixmapPtr pPixmap
)
1476 /* If Xinerama is not active, there's nothing we can do (see comment
1477 * in #else below for more info). */
1478 if (noPanoramiXExtension
)
1481 FoundPixImage
= False
;
1482 for (i
= currentMaxClients
; --i
>= 0;)
1484 FindAllClientResources(clients
[i
], dmxBEFindPixmapImage
,
1487 /* Save the image only if there is no other screens that have a
1488 * pixmap that corresponds to the one we are trying to save. */
1489 if (!FoundPixImage
) {
1490 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pPixmap
);
1492 if (!pPixPriv
->detachedImage
) {
1493 ScreenPtr pScreen
= pPixmap
->drawable
.pScreen
;
1494 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
1496 pPixPriv
->detachedImage
= XGetImage(dmxScreen
->beDisplay
,
1499 pPixmap
->drawable
.width
,
1500 pPixmap
->drawable
.height
,
1502 if (!pPixPriv
->detachedImage
)
1503 dmxLog(dmxWarning
, "Cannot save pixmap image\n");
1507 /* NOTE: The only time there is a pixmap on another screen that
1508 * corresponds to the one we are trying to save is when Xinerama is
1509 * active. Otherwise, the pixmap image data is only stored on a
1510 * single screen, which means that once it is detached, that data is
1511 * lost. We could save the data here, but then that would require
1512 * us to implement the ability for Xdmx to keep the pixmap up to
1513 * date while the screen is detached, which is beyond the scope of
1514 * the current project. */
1519 /** Destroy resources on the back-end server. This function is called
1520 * from #dmxDetachScreen() via the dix layer's FindAllResources
1521 * function. It walks all resources, compares them to the screen
1522 * number passed in as \a n and calls the appropriate DMX function to
1523 * free the associated resource on the back-end server. */
1525 dmxBEDestroyResources(pointer value
, XID id
, RESTYPE type
, pointer n
)
1527 int scrnNum
= (uintptr_t) n
;
1528 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
1530 if ((type
& TypeMask
) == (RT_WINDOW
& TypeMask
)) {
1531 /* Window resources are destroyed below in dmxBEDestroyWindowTree */
1533 else if ((type
& TypeMask
) == (RT_PIXMAP
& TypeMask
)) {
1534 PixmapPtr pPix
= value
;
1536 if (pPix
->drawable
.pScreen
->myNum
== scrnNum
) {
1537 dmxBESavePixmap(pPix
);
1538 dmxBEFreePixmap(pPix
);
1541 else if ((type
& TypeMask
) == (RT_GC
& TypeMask
)) {
1544 if (pGC
->pScreen
->myNum
== scrnNum
)
1547 else if ((type
& TypeMask
) == (RT_FONT
& TypeMask
)) {
1548 dmxBEFreeFont(pScreen
, (FontPtr
) value
);
1550 else if ((type
& TypeMask
) == (RT_CURSOR
& TypeMask
)) {
1551 dmxBEFreeCursor(pScreen
, (CursorPtr
) value
);
1553 else if ((type
& TypeMask
) == (RT_COLORMAP
& TypeMask
)) {
1554 ColormapPtr pCmap
= value
;
1556 if (pCmap
->pScreen
->myNum
== scrnNum
)
1557 dmxBEFreeColormap((ColormapPtr
) value
);
1559 else if ((type
& TypeMask
) == (PictureType
& TypeMask
)) {
1560 PicturePtr pPict
= value
;
1562 if (pPict
->pDrawable
->pScreen
->myNum
== scrnNum
) {
1563 /* Free the pixmaps on the backend if needed */
1564 if (pPict
->pDrawable
->type
== DRAWABLE_PIXMAP
) {
1565 PixmapPtr pPixmap
= (PixmapPtr
) (pPict
->pDrawable
);
1567 dmxBESavePixmap(pPixmap
);
1568 dmxBEFreePixmap(pPixmap
);
1570 dmxBEFreePicture((PicturePtr
) value
);
1573 else if ((type
& TypeMask
) == (GlyphSetType
& TypeMask
)) {
1574 dmxBEFreeGlyphSet(pScreen
, (GlyphSetPtr
) value
);
1577 /* Other resource types??? */
1581 /** Destroy the scratch GCs that are created per depth. */
1583 dmxBEDestroyScratchGCs(int scrnNum
)
1585 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
1586 GCPtr
*ppGC
= pScreen
->GCperDepth
;
1589 for (i
= 0; i
<= pScreen
->numDepths
; i
++)
1590 dmxBEFreeGC(ppGC
[i
]);
1593 /** Destroy window hierachy on back-end server. To ensure that all
1594 * XDestroyWindow() calls succeed, they must be performed in a bottom
1595 * up order so that windows are not destroyed before their children.
1596 * XDestroyWindow(), which is called from #dmxBEDestroyWindow(), will
1597 * destroy a window as well as all of it's children. */
1599 dmxBEDestroyWindowTree(int idx
)
1601 WindowPtr pWin
= screenInfo
.screens
[idx
]->root
;
1602 WindowPtr pChild
= pWin
;
1605 if (pChild
->firstChild
) {
1606 pChild
= pChild
->firstChild
;
1610 /* Destroy the window */
1611 dmxBEDestroyWindow(pChild
);
1613 /* Make sure we destroy the window's border and background
1614 * pixmaps if they exist */
1615 if (!pChild
->borderIsPixel
) {
1616 dmxBESavePixmap(pChild
->border
.pixmap
);
1617 dmxBEFreePixmap(pChild
->border
.pixmap
);
1619 if (pChild
->backgroundState
== BackgroundPixmap
) {
1620 dmxBESavePixmap(pChild
->background
.pixmap
);
1621 dmxBEFreePixmap(pChild
->background
.pixmap
);
1624 while (!pChild
->nextSib
&& (pChild
!= pWin
)) {
1625 pChild
= pChild
->parent
;
1626 dmxBEDestroyWindow(pChild
);
1627 if (!pChild
->borderIsPixel
) {
1628 dmxBESavePixmap(pChild
->border
.pixmap
);
1629 dmxBEFreePixmap(pChild
->border
.pixmap
);
1631 if (pChild
->backgroundState
== BackgroundPixmap
) {
1632 dmxBESavePixmap(pChild
->background
.pixmap
);
1633 dmxBEFreePixmap(pChild
->background
.pixmap
);
1640 pChild
= pChild
->nextSib
;
1644 /** Detach back-end screen. */
1646 dmxDetachScreen(int idx
)
1648 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
1651 /* Return failure if dynamic addition/removal of screens is disabled */
1652 if (!dmxAddRemoveScreens
) {
1654 "Attempting to remove a screen, but the AddRemoveScreen\n");
1656 "extension has not been enabled. To enable this extension\n");
1658 "add the \"-addremovescreens\" option either to the command\n");
1659 dmxLog(dmxWarning
, "line or in the configuration file.\n");
1663 /* Cannot remove a screen that does not exist */
1664 if (idx
< 0 || idx
>= dmxNumScreens
)
1667 /* Cannot detach from a screen that is not opened */
1668 if (!dmxScreen
->beDisplay
) {
1670 "Attempting to remove screen #%d but it has not been opened\n",
1675 dmxLogOutput(dmxScreen
, "Detaching screen #%d\n", idx
);
1678 dmxInputDetachAll(dmxScreen
);
1680 /* Save all relevant state (TODO) */
1682 /* Free all non-window resources related to this screen */
1683 for (i
= currentMaxClients
; --i
>= 0;)
1685 FindAllClientResources(clients
[i
], dmxBEDestroyResources
,
1686 (pointer
) (uintptr_t) idx
);
1688 /* Free scratch GCs */
1689 dmxBEDestroyScratchGCs(idx
);
1691 /* Free window resources related to this screen */
1692 dmxBEDestroyWindowTree(idx
);
1694 /* Free default stipple */
1695 dmxBESavePixmap(screenInfo
.screens
[idx
]->PixmapPerDepth
[0]);
1696 dmxBEFreePixmap(screenInfo
.screens
[idx
]->PixmapPerDepth
[0]);
1698 /* Free the remaining screen resources and close the screen */
1699 dmxBECloseScreen(screenInfo
.screens
[idx
]);
1701 /* Adjust the cursor boundaries (paints detached console window) */
1702 dmxAdjustCursorBoundaries();
1704 return 0; /* Success */