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>
46 #include "dmxextension.h"
47 #include "dmxwindow.h"
49 #include "dmxcursor.h"
50 #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 /** This routine provides information to the DMX protocol extension
72 * about a particular screen. */
73 Bool
dmxGetScreenAttributes(int physical
, DMXScreenAttributesPtr attr
)
75 DMXScreenInfo
*dmxScreen
;
77 if (physical
< 0 || physical
>= dmxNumScreens
) return FALSE
;
79 dmxScreen
= &dmxScreens
[physical
];
80 attr
->displayName
= dmxScreen
->name
;
82 attr
->logicalScreen
= noPanoramiXExtension
? dmxScreen
->index
: 0;
84 attr
->logicalScreen
= dmxScreen
->index
;
87 attr
->screenWindowWidth
= dmxScreen
->scrnWidth
;
88 attr
->screenWindowHeight
= dmxScreen
->scrnHeight
;
89 attr
->screenWindowXoffset
= dmxScreen
->scrnX
;
90 attr
->screenWindowYoffset
= dmxScreen
->scrnY
;
92 attr
->rootWindowWidth
= dmxScreen
->rootWidth
;
93 attr
->rootWindowHeight
= dmxScreen
->rootHeight
;
94 attr
->rootWindowXoffset
= dmxScreen
->rootX
;
95 attr
->rootWindowYoffset
= dmxScreen
->rootY
;
97 attr
->rootWindowXorigin
= dmxScreen
->rootXOrigin
;
98 attr
->rootWindowYorigin
= dmxScreen
->rootYOrigin
;
103 /** This routine provides information to the DMX protocol extension
104 * about a particular window. */
105 Bool
dmxGetWindowAttributes(WindowPtr pWindow
, DMXWindowAttributesPtr attr
)
107 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWindow
);
109 attr
->screen
= pWindow
->drawable
.pScreen
->myNum
;
110 attr
->window
= pWinPriv
->window
;
112 attr
->pos
.x
= pWindow
->drawable
.x
;
113 attr
->pos
.y
= pWindow
->drawable
.y
;
114 attr
->pos
.width
= pWindow
->drawable
.width
;
115 attr
->pos
.height
= pWindow
->drawable
.height
;
117 if (!pWinPriv
->window
|| pWinPriv
->offscreen
) {
120 attr
->vis
.height
= 0;
122 return pWinPriv
->window
? TRUE
: FALSE
;
125 /* Compute display-relative coordinates */
126 attr
->vis
.x
= pWindow
->drawable
.x
;
127 attr
->vis
.y
= pWindow
->drawable
.y
;
128 attr
->vis
.width
= pWindow
->drawable
.width
;
129 attr
->vis
.height
= pWindow
->drawable
.height
;
131 if (attr
->pos
.x
< 0) {
132 attr
->vis
.x
-= attr
->pos
.x
;
133 attr
->vis
.width
= attr
->pos
.x
+ attr
->pos
.width
- attr
->vis
.x
;
135 if (attr
->pos
.x
+ attr
->pos
.width
> pWindow
->drawable
.pScreen
->width
) {
137 attr
->vis
.width
= pWindow
->drawable
.pScreen
->width
;
139 attr
->vis
.width
= pWindow
->drawable
.pScreen
->width
- attr
->pos
.x
;
141 if (attr
->pos
.y
< 0) {
142 attr
->vis
.y
-= attr
->pos
.y
;
143 attr
->vis
.height
= attr
->pos
.y
+ attr
->pos
.height
- attr
->vis
.y
;
145 if (attr
->pos
.y
+ attr
->pos
.height
> pWindow
->drawable
.pScreen
->height
) {
147 attr
->vis
.height
= pWindow
->drawable
.pScreen
->height
;
149 attr
->vis
.height
= pWindow
->drawable
.pScreen
->height
- attr
->pos
.y
;
152 /* Convert to window-relative coordinates */
153 attr
->vis
.x
-= attr
->pos
.x
;
154 attr
->vis
.y
-= attr
->pos
.y
;
159 void dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr
)
161 attr
->width
= dmxGlobalWidth
;
162 attr
->height
= dmxGlobalHeight
;
163 attr
->shiftX
= 0; /* NOTE: The upper left hand corner of */
164 attr
->shiftY
= 0; /* the desktop is always <0,0>. */
167 /** Return the total number of devices, not just #dmxNumInputs. The
168 * number returned should be the same as that returned by
169 * XListInputDevices. */
170 int dmxGetInputCount(void)
174 for (total
= i
= 0; i
< dmxNumInputs
; i
++) total
+= dmxInputs
[i
].numDevs
;
178 /** Return information about the device with id = \a deviceId. This
179 * information is primarily for the #ProcDMXGetInputAttributes()
180 * function, which does not have access to the appropriate data
182 int dmxGetInputAttributes(int deviceId
, DMXInputAttributesPtr attr
)
185 DMXInputInfo
*dmxInput
;
187 if (deviceId
< 0) return -1;
188 for (i
= 0; i
< dmxNumInputs
; i
++) {
189 dmxInput
= &dmxInputs
[i
];
190 for (j
= 0; j
< dmxInput
->numDevs
; j
++) {
191 DMXLocalInputInfoPtr dmxLocal
= dmxInput
->devs
[j
];
192 if (deviceId
!= dmxLocal
->pDevice
->id
) continue;
193 attr
->isCore
= !!dmxLocal
->isCore
;
194 attr
->sendsCore
= !!dmxLocal
->sendsCore
;
195 attr
->detached
= !!dmxInput
->detached
;
196 attr
->physicalScreen
= -1;
197 attr
->physicalId
= -1;
199 switch (dmxLocal
->extType
) {
200 case DMX_LOCAL_TYPE_LOCAL
:
203 case DMX_LOCAL_TYPE_CONSOLE
:
205 attr
->name
= dmxInput
->name
;
206 attr
->physicalId
= dmxLocal
->deviceId
;
208 case DMX_LOCAL_TYPE_BACKEND
:
209 case DMX_LOCAL_TYPE_COMMON
:
211 attr
->physicalScreen
= dmxInput
->scrnIdx
;
212 attr
->name
= dmxInput
->name
;
213 attr
->physicalId
= dmxLocal
->deviceId
;
216 return 0; /* Success */
219 return -1; /* Failure */
222 /** Reinitialized the cursor boundaries. */
223 static void dmxAdjustCursorBoundaries(void)
229 dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX
);
230 dmxConnectionBlockCallback();
231 for (i
= 0; i
< dmxNumInputs
; i
++) {
232 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
233 if (!dmxInput
->detached
) dmxInputReInit(dmxInput
);
238 for (i
= 0; i
< dmxNumInputs
; i
++) {
239 DMXInputInfo
*dmxInput
= &dmxInputs
[i
];
240 if (!dmxInput
->detached
) dmxInputLateReInit(dmxInput
);
244 /** Add an input with the specified attributes. If the input is added,
245 * the physical id is returned in \a deviceId. */
246 int dmxAddInput(DMXInputAttributesPtr attr
, int *id
)
248 int retcode
= BadValue
;
250 if (attr
->inputType
== 1) /* console */
251 retcode
= dmxInputAttachConsole(attr
->name
, attr
->sendsCore
, id
);
252 else if (attr
->inputType
== 2) /* backend */
253 retcode
= dmxInputAttachBackend(attr
->physicalScreen
,
256 if (retcode
== Success
) {
257 /* Adjust the cursor boundaries */
258 dmxAdjustCursorBoundaries();
260 /* Force completion of the changes */
267 /** Remove the input with physical id \a id. */
268 int dmxRemoveInput(int id
)
270 return dmxInputDetachId(id
);
273 /** Return the value of #dmxNumScreens -- the total number of backend
274 * screens in use (these are logical screens and may be larger than the
275 * number of backend displays). */
276 unsigned long dmxGetNumScreens(void)
278 return dmxNumScreens
;
281 /** Make sure that #dmxCreateAndRealizeWindow has been called for \a
283 void dmxForceWindowCreation(WindowPtr pWindow
)
285 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pWindow
);
286 if (!pWinPriv
->window
) dmxCreateAndRealizeWindow(pWindow
, TRUE
);
289 /** Flush pending syncs for all screens. */
290 void dmxFlushPendingSyncs(void)
295 /** Update DMX's screen resources to match those of the newly moved
296 * and/or resized "root" window. */
297 void dmxUpdateScreenResources(ScreenPtr pScreen
, int x
, int y
, int w
, int h
)
299 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
300 WindowPtr pRoot
= WindowTable
[pScreen
->myNum
];
302 Bool anyMarked
= FALSE
;
304 /* Handle special case where width and/or height are zero */
305 if (w
== 0 || h
== 0) {
310 /* Change screen size */
314 /* Reset the root window's drawable's size */
315 pRoot
->drawable
.width
= w
;
316 pRoot
->drawable
.height
= h
;
318 /* Set the root window's new winSize and borderSize */
319 pRoot
->winSize
.extents
.x1
= 0;
320 pRoot
->winSize
.extents
.y1
= 0;
321 pRoot
->winSize
.extents
.x2
= w
;
322 pRoot
->winSize
.extents
.y2
= h
;
324 pRoot
->borderSize
.extents
.x1
= 0;
325 pRoot
->borderSize
.extents
.y1
= 0;
326 pRoot
->borderSize
.extents
.x2
= w
;
327 pRoot
->borderSize
.extents
.y2
= h
;
329 /* Recompute this screen's mmWidth & mmHeight */
331 (w
* 254 + dmxScreen
->beXDPI
* 5) / (dmxScreen
->beXDPI
* 10);
333 (h
* 254 + dmxScreen
->beYDPI
* 5) / (dmxScreen
->beYDPI
* 10);
335 /* Recompute this screen's window's clip rects as follows: */
336 /* 1. Mark all of root's children's windows */
337 for (pChild
= pRoot
->firstChild
; pChild
; pChild
= pChild
->nextSib
)
338 anyMarked
|= pScreen
->MarkOverlappedWindows(pChild
, pChild
,
341 /* 2. Set the root window's borderClip */
342 pRoot
->borderClip
.extents
.x1
= 0;
343 pRoot
->borderClip
.extents
.y1
= 0;
344 pRoot
->borderClip
.extents
.x2
= w
;
345 pRoot
->borderClip
.extents
.y2
= h
;
347 /* 3. Set the root window's clipList */
349 /* If any windows have been marked, set the root window's
350 * clipList to be broken since it will be recalculated in
353 REGION_BREAK(pScreen
, &pRoot
->clipList
);
355 /* Otherwise, we just set it directly since there are no
356 * windows visible on this screen
358 pRoot
->clipList
.extents
.x1
= 0;
359 pRoot
->clipList
.extents
.y1
= 0;
360 pRoot
->clipList
.extents
.x2
= w
;
361 pRoot
->clipList
.extents
.y2
= h
;
364 /* 4. Revalidate all clip rects and generate expose events */
366 pScreen
->ValidateTree(pRoot
, NULL
, VTBroken
);
367 pScreen
->HandleExposures(pRoot
);
368 if (pScreen
->PostValidateTree
)
369 pScreen
->PostValidateTree(pRoot
, NULL
, VTBroken
);
374 #include "panoramiXsrv.h"
376 /** Change the "screen" window attributes by resizing the actual window
377 * on the back-end display (if necessary). */
378 static void dmxConfigureScreenWindow(int idx
,
379 int x
, int y
, int w
, int h
)
381 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
382 ScreenPtr pScreen
= screenInfo
.screens
[idx
];
384 /* Resize "screen" window */
385 if (dmxScreen
->scrnX
!= x
||
386 dmxScreen
->scrnY
!= y
||
387 dmxScreen
->scrnWidth
!= w
||
388 dmxScreen
->scrnHeight
!= h
) {
389 dmxResizeScreenWindow(pScreen
, x
, y
, w
, h
);
392 /* Change "screen" window values */
393 dmxScreen
->scrnX
= x
;
394 dmxScreen
->scrnY
= y
;
395 dmxScreen
->scrnWidth
= w
;
396 dmxScreen
->scrnHeight
= h
;
399 /** Change the "root" window position and size by resizing the actual
400 * window on the back-end display (if necessary) and updating all of
401 * DMX's resources by calling #dmxUpdateScreenResources. */
402 static void dmxConfigureRootWindow(int idx
, int x
, int y
, int w
, int h
)
404 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
405 WindowPtr pRoot
= WindowTable
[idx
];
407 /* NOTE: Either this function or the ones that it calls must handle
408 * the case where w == 0 || h == 0. Currently, the functions that
409 * this one calls handle that case. */
411 /* 1. Resize "root" window */
412 if (dmxScreen
->rootX
!= x
||
413 dmxScreen
->rootY
!= y
||
414 dmxScreen
->rootWidth
!= w
||
415 dmxScreen
->rootHeight
!= h
) {
416 dmxResizeRootWindow(pRoot
, x
, y
, w
, h
);
419 /* 2. Update all of the screen's resources associated with this root
421 if (dmxScreen
->rootWidth
!= w
||
422 dmxScreen
->rootHeight
!= h
) {
423 dmxUpdateScreenResources(screenInfo
.screens
[idx
], x
, y
, w
, h
);
426 /* Change "root" window values */
427 dmxScreen
->rootX
= x
;
428 dmxScreen
->rootY
= y
;
429 dmxScreen
->rootWidth
= w
;
430 dmxScreen
->rootHeight
= h
;
433 /** Change the "root" window's origin by updating DMX's internal data
434 * structures (dix and Xinerama) to use the new origin and adjust the
435 * positions of windows that overlap this "root" window. */
436 static void dmxSetRootWindowOrigin(int idx
, int x
, int y
)
438 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
439 ScreenPtr pScreen
= screenInfo
.screens
[idx
];
440 WindowPtr pRoot
= WindowTable
[idx
];
445 /* Change "root" window's origin */
446 dmxScreen
->rootXOrigin
= x
;
447 dmxScreen
->rootYOrigin
= y
;
449 /* Compute offsets here in case <x,y> has been changed above */
450 xoff
= x
- dixScreenOrigins
[idx
].x
;
451 yoff
= y
- dixScreenOrigins
[idx
].y
;
453 /* Adjust the root window's position in dixScreenOrigins */
454 dixScreenOrigins
[idx
].x
= dmxScreen
->rootXOrigin
;
455 dixScreenOrigins
[idx
].y
= dmxScreen
->rootYOrigin
;
457 /* Recalculate the Xinerama regions and data structs */
458 XineramaReinitData(pScreen
);
460 /* Adjust each of the root window's children */
461 if (!idx
) ReinitializeRootWindow(WindowTable
[0], xoff
, yoff
);
462 pChild
= pRoot
->firstChild
;
464 /* Adjust child window's position */
465 pScreen
->MoveWindow(pChild
,
466 pChild
->origin
.x
- wBorderWidth(pChild
) - xoff
,
467 pChild
->origin
.y
- wBorderWidth(pChild
) - yoff
,
471 /* Note that the call to MoveWindow will eventually call
472 * dmxPositionWindow which will automatically create a
473 * window if it is now exposed on screen (for lazy window
474 * creation optimization) and it will properly set the
478 pChild
= pChild
->nextSib
;
482 /** Configure the attributes of each "screen" and "root" window. */
483 int dmxConfigureScreenWindows(int nscreens
,
485 DMXScreenAttributesPtr attribs
,
490 for (i
= 0; i
< nscreens
; i
++) {
491 DMXScreenAttributesPtr attr
= &attribs
[i
];
492 int idx
= screens
[i
];
493 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
495 if (errorScreen
) *errorScreen
= i
;
497 if (!dmxScreen
->beDisplay
) return DMX_BAD_VALUE
;
499 /* Check for illegal values */
500 if (idx
< 0 || idx
>= dmxNumScreens
) return BadValue
;
502 /* The "screen" and "root" windows must have valid sizes */
503 if (attr
->screenWindowWidth
<= 0 || attr
->screenWindowHeight
<= 0 ||
504 attr
->rootWindowWidth
< 0 || attr
->rootWindowHeight
< 0)
505 return DMX_BAD_VALUE
;
507 /* The "screen" window must fit entirely within the BE display */
508 if (attr
->screenWindowXoffset
< 0 ||
509 attr
->screenWindowYoffset
< 0 ||
510 attr
->screenWindowXoffset
511 + attr
->screenWindowWidth
> (unsigned)dmxScreen
->beWidth
||
512 attr
->screenWindowYoffset
513 + attr
->screenWindowHeight
> (unsigned)dmxScreen
->beHeight
)
514 return DMX_BAD_VALUE
;
516 /* The "root" window must fit entirely within the "screen" window */
517 if (attr
->rootWindowXoffset
< 0 ||
518 attr
->rootWindowYoffset
< 0 ||
519 attr
->rootWindowXoffset
520 + attr
->rootWindowWidth
> attr
->screenWindowWidth
||
521 attr
->rootWindowYoffset
522 + attr
->rootWindowHeight
> attr
->screenWindowHeight
)
523 return DMX_BAD_VALUE
;
525 /* The "root" window must not expose unaddressable coordinates */
526 if (attr
->rootWindowXorigin
< 0 ||
527 attr
->rootWindowYorigin
< 0 ||
528 attr
->rootWindowXorigin
+ attr
->rootWindowWidth
> 32767 ||
529 attr
->rootWindowYorigin
+ attr
->rootWindowHeight
> 32767)
530 return DMX_BAD_VALUE
;
532 /* The "root" window must fit within the global bounding box */
533 if (attr
->rootWindowXorigin
534 + attr
->rootWindowWidth
> (unsigned)dmxGlobalWidth
||
535 attr
->rootWindowYorigin
536 + attr
->rootWindowHeight
> (unsigned)dmxGlobalHeight
)
537 return DMX_BAD_VALUE
;
539 /* FIXME: Handle the rest of the illegal value checking */
542 /* No illegal values found */
543 if (errorScreen
) *errorScreen
= 0;
545 for (i
= 0; i
< nscreens
; i
++) {
546 DMXScreenAttributesPtr attr
= &attribs
[i
];
547 int idx
= screens
[i
];
548 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
550 dmxLog(dmxInfo
, "Changing screen #%d attributes "
551 "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d "
552 "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n",
554 dmxScreen
->scrnWidth
, dmxScreen
->scrnHeight
,
555 dmxScreen
->scrnX
, dmxScreen
->scrnY
,
556 dmxScreen
->rootWidth
, dmxScreen
->rootHeight
,
557 dmxScreen
->rootX
, dmxScreen
->rootY
,
558 dmxScreen
->rootXOrigin
, dmxScreen
->rootYOrigin
,
559 attr
->screenWindowWidth
, attr
->screenWindowHeight
,
560 attr
->screenWindowXoffset
, attr
->screenWindowYoffset
,
561 attr
->rootWindowWidth
, attr
->rootWindowHeight
,
562 attr
->rootWindowXoffset
, attr
->rootWindowYoffset
,
563 attr
->rootWindowXorigin
, attr
->rootWindowYorigin
);
565 /* Configure "screen" window */
566 dmxConfigureScreenWindow(idx
,
567 attr
->screenWindowXoffset
,
568 attr
->screenWindowYoffset
,
569 attr
->screenWindowWidth
,
570 attr
->screenWindowHeight
);
572 /* Configure "root" window */
573 dmxConfigureRootWindow(idx
,
574 attr
->rootWindowXoffset
,
575 attr
->rootWindowYoffset
,
576 attr
->rootWindowWidth
,
577 attr
->rootWindowHeight
);
580 /* Set "root" window's origin */
581 dmxSetRootWindowOrigin(idx
,
582 attr
->rootWindowXorigin
,
583 attr
->rootWindowYorigin
);
586 /* Adjust the cursor boundaries */
587 dmxAdjustCursorBoundaries();
589 /* Force completion of the changes */
595 /** Configure the attributes of the global desktop. */
596 int dmxConfigureDesktop(DMXDesktopAttributesPtr attribs
)
598 if (attribs
->width
<= 0 || attribs
->width
>= 32767 ||
599 attribs
->height
<= 0 || attribs
->height
>= 32767)
600 return DMX_BAD_VALUE
;
602 /* If the desktop is shrinking, adjust the "root" windows on each
603 * "screen" window to only show the visible desktop. Also, handle
604 * the special case where the desktop shrinks such that the it no
605 * longer overlaps an portion of a "screen" window. */
606 if (attribs
->width
< dmxGlobalWidth
|| attribs
->height
< dmxGlobalHeight
) {
608 for (i
= 0; i
< dmxNumScreens
; i
++) {
609 DMXScreenInfo
*dmxScreen
= &dmxScreens
[i
];
610 if (dmxScreen
->rootXOrigin
611 + dmxScreen
->rootWidth
> attribs
->width
||
612 dmxScreen
->rootYOrigin
613 + dmxScreen
->rootHeight
> attribs
->height
) {
615 if ((w
= attribs
->width
- dmxScreen
->rootXOrigin
) < 0) w
= 0;
616 if ((h
= attribs
->height
- dmxScreen
->rootYOrigin
) < 0) h
= 0;
617 if (w
> dmxScreen
->scrnWidth
) w
= dmxScreen
->scrnWidth
;
618 if (h
> dmxScreen
->scrnHeight
) h
= dmxScreen
->scrnHeight
;
619 if (w
> dmxScreen
->rootWidth
) w
= dmxScreen
->rootWidth
;
620 if (h
> dmxScreen
->rootHeight
) h
= dmxScreen
->rootHeight
;
621 dmxConfigureRootWindow(i
,
629 /* Set the global width/height */
630 dmxSetWidthHeight(attribs
->width
, attribs
->height
);
632 /* Handle shift[XY] changes */
633 if (attribs
->shiftX
|| attribs
->shiftY
) {
635 for (i
= 0; i
< dmxNumScreens
; i
++) {
636 ScreenPtr pScreen
= screenInfo
.screens
[i
];
637 WindowPtr pChild
= WindowTable
[i
]->firstChild
;
639 /* Adjust child window's position */
640 pScreen
->MoveWindow(pChild
,
641 pChild
->origin
.x
- wBorderWidth(pChild
)
643 pChild
->origin
.y
- wBorderWidth(pChild
)
648 /* Note that the call to MoveWindow will eventually call
649 * dmxPositionWindow which will automatically create a
650 * window if it is now exposed on screen (for lazy
651 * window creation optimization) and it will properly
652 * set the offscreen flag.
655 pChild
= pChild
->nextSib
;
660 /* Update connection block, Xinerama, etc. -- these appears to
661 * already be handled in dmxConnectionBlockCallback(), which is
662 * called from dmxAdjustCursorBoundaries() [below]. */
664 /* Adjust the cursor boundaries */
665 dmxAdjustCursorBoundaries();
667 /* Force completion of the changes */
674 /** Create the scratch GCs per depth. */
675 static void dmxBECreateScratchGCs(int scrnNum
)
677 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
678 GCPtr
*ppGC
= pScreen
->GCperDepth
;
681 for (i
= 0; i
<= pScreen
->numDepths
; i
++)
682 dmxBECreateGC(pScreen
, ppGC
[i
]);
686 static Bool FoundPixImage
;
688 /** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs
689 * to have its image restored. When it is found, see if there is
690 * another screen with the same image. If so, copy the pixmap image
691 * from the existing screen to the newly created pixmap. */
692 static void dmxBERestorePixmapImage(pointer value
, XID id
, RESTYPE type
,
695 if ((type
& TypeMask
) == (XRT_PIXMAP
& TypeMask
)) {
696 PixmapPtr pDst
= (PixmapPtr
)p
;
697 int idx
= pDst
->drawable
.pScreen
->myNum
;
698 PanoramiXRes
*pXinPix
= (PanoramiXRes
*)value
;
702 pPix
= (PixmapPtr
)LookupIDByType(pXinPix
->info
[idx
].id
, RT_PIXMAP
);
703 if (pPix
!= pDst
) return; /* Not a match.... Next! */
705 for (i
= 0; i
< PanoramiXNumScreens
; i
++) {
707 dmxPixPrivPtr pSrcPriv
= NULL
;
709 if (i
== idx
) continue; /* Self replication is bad */
712 (PixmapPtr
)LookupIDByType(pXinPix
->info
[i
].id
, RT_PIXMAP
);
713 pSrcPriv
= DMX_GET_PIXMAP_PRIV(pSrc
);
714 if (pSrcPriv
->pixmap
) {
715 DMXScreenInfo
*dmxSrcScreen
= &dmxScreens
[i
];
716 DMXScreenInfo
*dmxDstScreen
= &dmxScreens
[idx
];
717 dmxPixPrivPtr pDstPriv
= DMX_GET_PIXMAP_PRIV(pDst
);
722 /* This should never happen, but just in case.... */
723 if (pSrc
->drawable
.width
!= pDst
->drawable
.width
||
724 pSrc
->drawable
.height
!= pDst
->drawable
.height
)
727 /* Copy from src pixmap to dst pixmap */
728 img
= XGetImage(dmxSrcScreen
->beDisplay
,
731 pSrc
->drawable
.width
, pSrc
->drawable
.height
,
735 for (j
= 0; j
< dmxDstScreen
->beNumPixmapFormats
; j
++) {
736 if (dmxDstScreen
->bePixmapFormats
[j
].depth
== img
->depth
) {
740 m
= GCFunction
| GCPlaneMask
| GCClipMask
;
742 v
.plane_mask
= AllPlanes
;
745 gc
= XCreateGC(dmxDstScreen
->beDisplay
,
746 dmxDstScreen
->scrnDefDrawables
[j
],
753 XPutImage(dmxDstScreen
->beDisplay
,
756 pDst
->drawable
.width
, pDst
->drawable
.height
);
757 XFreeGC(dmxDstScreen
->beDisplay
, gc
);
758 FoundPixImage
= True
;
760 dmxLog(dmxWarning
, "Could not create GC\n");
771 /** Restore the pixmap image either from another screen or from an image
772 * that was saved when the screen was previously detached. */
773 static void dmxBERestorePixmap(PixmapPtr pPixmap
)
778 /* If Xinerama is not active, there's nothing we can do (see comment
779 * in #else below for more info). */
780 if (noPanoramiXExtension
) {
781 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
785 FoundPixImage
= False
;
786 for (i
= currentMaxClients
; --i
>= 0; )
788 FindAllClientResources(clients
[i
], dmxBERestorePixmapImage
,
791 /* No corresponding pixmap image was found on other screens, so we
792 * need to copy it from the saved image when the screen was detached
794 if (!FoundPixImage
) {
795 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pPixmap
);
797 if (pPixPriv
->detachedImage
) {
798 ScreenPtr pScreen
= pPixmap
->drawable
.pScreen
;
799 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
802 for (i
= 0; i
< dmxScreen
->beNumPixmapFormats
; i
++) {
803 if (dmxScreen
->bePixmapFormats
[i
].depth
==
804 pPixPriv
->detachedImage
->depth
) {
808 m
= GCFunction
| GCPlaneMask
| GCClipMask
;
810 v
.plane_mask
= AllPlanes
;
813 gc
= XCreateGC(dmxScreen
->beDisplay
,
814 dmxScreen
->scrnDefDrawables
[i
],
821 XPutImage(dmxScreen
->beDisplay
,
824 pPixPriv
->detachedImage
,
826 pPixmap
->drawable
.width
, pPixmap
->drawable
.height
);
827 XFreeGC(dmxScreen
->beDisplay
, gc
);
829 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
832 XDestroyImage(pPixPriv
->detachedImage
);
833 pPixPriv
->detachedImage
= NULL
;
835 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
839 /* If Xinerama is not enabled, then there is no other copy of the
840 * pixmap image that we can restore. Saving all pixmap data is not
841 * a feasible option since there is no mechanism for updating pixmap
842 * data when a screen is detached, which means that the data that
843 * was previously saved would most likely be out of date. */
844 dmxLog(dmxWarning
, "Cannot restore pixmap image\n");
849 /** Create resources on the back-end server. This function is called
850 * from #dmxAttachScreen() via the dix layer's FindAllResources
851 * function. It walks all resources, compares them to the screen
852 * number passed in as \a n and calls the appropriate DMX function to
853 * create the associated resource on the back-end server. */
854 static void dmxBECreateResources(pointer value
, XID id
, RESTYPE type
,
857 int scrnNum
= (int)n
;
858 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
860 if ((type
& TypeMask
) == (RT_WINDOW
& TypeMask
)) {
861 /* Window resources are created below in dmxBECreateWindowTree */
862 } else if ((type
& TypeMask
) == (RT_PIXMAP
& TypeMask
)) {
863 PixmapPtr pPix
= value
;
864 if (pPix
->drawable
.pScreen
->myNum
== scrnNum
) {
865 dmxBECreatePixmap(pPix
);
866 dmxBERestorePixmap(pPix
);
868 } else if ((type
& TypeMask
) == (RT_GC
& TypeMask
)) {
870 if (pGC
->pScreen
->myNum
== scrnNum
) {
871 /* Create the GC on the back-end server */
872 dmxBECreateGC(pScreen
, pGC
);
873 /* Create any pixmaps associated with this GC */
874 if (!pGC
->tileIsPixel
) {
875 dmxBECreatePixmap(pGC
->tile
.pixmap
);
876 dmxBERestorePixmap(pGC
->tile
.pixmap
);
878 if (pGC
->stipple
!= pScreen
->PixmapPerDepth
[0]) {
879 dmxBECreatePixmap(pGC
->stipple
);
880 dmxBERestorePixmap(pGC
->stipple
);
882 if (pGC
->font
!= defaultFont
) {
883 (void)dmxBELoadFont(pScreen
, pGC
->font
);
885 /* Update the GC on the back-end server */
886 dmxChangeGC(pGC
, -1L);
888 } else if ((type
& TypeMask
) == (RT_FONT
& TypeMask
)) {
889 (void)dmxBELoadFont(pScreen
, (FontPtr
)value
);
890 } else if ((type
& TypeMask
) == (RT_CURSOR
& TypeMask
)) {
891 dmxBECreateCursor(pScreen
, (CursorPtr
)value
);
892 } else if ((type
& TypeMask
) == (RT_COLORMAP
& TypeMask
)) {
893 ColormapPtr pCmap
= value
;
894 if (pCmap
->pScreen
->myNum
== scrnNum
)
895 (void)dmxBECreateColormap((ColormapPtr
)value
);
898 /* TODO: Recreate Picture and GlyphSet resources */
899 } else if ((type
& TypeMask
) == (PictureType
& TypeMask
)) {
900 /* Picture resources are created when windows are created */
901 } else if ((type
& TypeMask
) == (GlyphSetType
& TypeMask
)) {
902 dmxBEFreeGlyphSet(pScreen
, (GlyphSetPtr
)value
);
906 /* Other resource types??? */
910 /** Create window hierachy on back-end server. The window tree is
911 * created in a special order (bottom most subwindow first) so that the
912 * #dmxCreateNonRootWindow() function does not need to recursively call
913 * itself to create each window's parents. This is required so that we
914 * have the opportunity to create each window's border and background
915 * pixmaps (where appropriate) before the window is created. */
916 static void dmxBECreateWindowTree(int idx
)
918 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
919 WindowPtr pRoot
= WindowTable
[idx
];
920 dmxWinPrivPtr pWinPriv
= DMX_GET_WINDOW_PRIV(pRoot
);
923 /* Create the pixmaps associated with the root window */
924 if (!pRoot
->borderIsPixel
) {
925 dmxBECreatePixmap(pRoot
->border
.pixmap
);
926 dmxBERestorePixmap(pRoot
->border
.pixmap
);
928 if (pRoot
->backgroundState
== BackgroundPixmap
) {
929 dmxBECreatePixmap(pRoot
->background
.pixmap
);
930 dmxBERestorePixmap(pRoot
->background
.pixmap
);
933 /* Create root window first */
934 dmxScreen
->rootWin
= pWinPriv
->window
= dmxCreateRootWindow(pRoot
);
935 XMapWindow(dmxScreen
->beDisplay
, dmxScreen
->rootWin
);
937 pWin
= pRoot
->lastChild
;
939 pWinPriv
= DMX_GET_WINDOW_PRIV(pWin
);
941 /* Create the pixmaps regardless of whether or not the
942 * window is created or not due to lazy window creation.
944 if (!pWin
->borderIsPixel
) {
945 dmxBECreatePixmap(pWin
->border
.pixmap
);
946 dmxBERestorePixmap(pWin
->border
.pixmap
);
948 if (pWin
->backgroundState
== BackgroundPixmap
) {
949 dmxBECreatePixmap(pWin
->background
.pixmap
);
950 dmxBERestorePixmap(pWin
->background
.pixmap
);
953 /* Reset the window attributes */
954 dmxGetDefaultWindowAttributes(pWin
,
958 /* Create the window */
959 if (pWinPriv
->mapped
&& !pWinPriv
->offscreen
)
960 dmxCreateAndRealizeWindow(pWin
, TRUE
);
962 /* Next, create the bottom-most child */
963 if (pWin
->lastChild
) {
964 pWin
= pWin
->lastChild
;
968 /* If the window has no children, move on to the next higher window */
969 while (!pWin
->prevSib
&& (pWin
!= pRoot
))
973 pWin
= pWin
->prevSib
;
977 /* When we reach the root window, we are finished */
983 /* Refresh screen by generating exposure events for all windows */
984 static void dmxForceExposures(int idx
)
986 ScreenPtr pScreen
= screenInfo
.screens
[idx
];
987 WindowPtr pRoot
= WindowTable
[idx
];
988 Bool anyMarked
= FALSE
;
991 for (pChild
= pRoot
->firstChild
; pChild
; pChild
= pChild
->nextSib
)
992 anyMarked
|= pScreen
->MarkOverlappedWindows(pChild
, pChild
,
995 /* If any windows have been marked, set the root window's
996 * clipList to be broken since it will be recalculated in
999 REGION_BREAK(pScreen
, &pRoot
->clipList
);
1000 pScreen
->ValidateTree(pRoot
, NULL
, VTBroken
);
1001 pScreen
->HandleExposures(pRoot
);
1002 if (pScreen
->PostValidateTree
)
1003 pScreen
->PostValidateTree(pRoot
, NULL
, VTBroken
);
1007 /** Compare the new and old screens to see if they are compatible. */
1008 static Bool
dmxCompareScreens(DMXScreenInfo
*new, DMXScreenInfo
*old
)
1012 if (new->beWidth
!= old
->beWidth
) return FALSE
;
1013 if (new->beHeight
!= old
->beHeight
) return FALSE
;
1014 if (new->beDepth
!= old
->beDepth
) return FALSE
;
1015 if (new->beBPP
!= old
->beBPP
) return FALSE
;
1017 if (new->beNumDepths
!= old
->beNumDepths
) return FALSE
;
1018 for (i
= 0; i
< old
->beNumDepths
; i
++)
1019 if (new->beDepths
[i
] != old
->beDepths
[i
]) return FALSE
;
1021 if (new->beNumPixmapFormats
!= old
->beNumPixmapFormats
) return FALSE
;
1022 for (i
= 0; i
< old
->beNumPixmapFormats
; i
++) {
1023 if (new->bePixmapFormats
[i
].depth
!=
1024 old
->bePixmapFormats
[i
].depth
) return FALSE
;
1025 if (new->bePixmapFormats
[i
].bits_per_pixel
!=
1026 old
->bePixmapFormats
[i
].bits_per_pixel
) return FALSE
;
1027 if (new->bePixmapFormats
[i
].scanline_pad
!=
1028 old
->bePixmapFormats
[i
].scanline_pad
) return FALSE
;
1031 if (new->beNumVisuals
!= old
->beNumVisuals
) return FALSE
;
1032 for (i
= 0; i
< old
->beNumVisuals
; i
++) {
1033 if (new->beVisuals
[i
].visualid
!=
1034 old
->beVisuals
[i
].visualid
) return FALSE
;
1035 if (new->beVisuals
[i
].screen
!=
1036 old
->beVisuals
[i
].screen
) return FALSE
;
1037 if (new->beVisuals
[i
].depth
!=
1038 old
->beVisuals
[i
].depth
) return FALSE
;
1039 if (new->beVisuals
[i
].class !=
1040 old
->beVisuals
[i
].class) return FALSE
;
1041 if (new->beVisuals
[i
].red_mask
!=
1042 old
->beVisuals
[i
].red_mask
) return FALSE
;
1043 if (new->beVisuals
[i
].green_mask
!=
1044 old
->beVisuals
[i
].green_mask
) return FALSE
;
1045 if (new->beVisuals
[i
].blue_mask
!=
1046 old
->beVisuals
[i
].blue_mask
) return FALSE
;
1047 if (new->beVisuals
[i
].colormap_size
!=
1048 old
->beVisuals
[i
].colormap_size
) return FALSE
;
1049 if (new->beVisuals
[i
].bits_per_rgb
!=
1050 old
->beVisuals
[i
].bits_per_rgb
) return FALSE
;
1053 if (new->beDefVisualIndex
!= old
->beDefVisualIndex
) return FALSE
;
1059 /** Restore Render's picture */
1060 static void dmxBERestoreRenderPict(pointer value
, XID id
, pointer n
)
1062 PicturePtr pPicture
= value
; /* The picture */
1063 DrawablePtr pDraw
= pPicture
->pDrawable
; /* The picture's drawable */
1064 int scrnNum
= (int)n
;
1066 if (pDraw
->pScreen
->myNum
!= scrnNum
) {
1067 /* Picture not on the screen we are restoring*/
1071 if (pDraw
->type
== DRAWABLE_PIXMAP
) {
1072 PixmapPtr pPixmap
= (PixmapPtr
)pDraw
;
1074 /* Create and restore the pixmap drawable */
1075 dmxBECreatePixmap(pPixmap
);
1076 dmxBERestorePixmap(pPixmap
);
1079 dmxBECreatePicture(pPicture
);
1082 /** Restore Render's glyphs */
1083 static void dmxBERestoreRenderGlyph(pointer value
, XID id
, pointer n
)
1085 GlyphSetPtr glyphSet
= value
;
1086 int scrnNum
= (int)n
;
1087 dmxGlyphPrivPtr glyphPriv
= DMX_GET_GLYPH_PRIV(glyphSet
);
1088 DMXScreenInfo
*dmxScreen
= &dmxScreens
[scrnNum
];
1099 if (glyphPriv
->glyphSets
[scrnNum
]) {
1100 /* Only restore glyphs on the screen we are attaching */
1104 /* First we must create the glyph set on the backend. */
1105 if ((beret
= dmxBECreateGlyphSet(scrnNum
, glyphSet
)) != Success
) {
1107 "\tdmxBERestoreRenderGlyph failed to create glyphset!\n");
1111 /* Now for the complex part, restore the glyph data */
1112 table
= glyphSet
->hash
.table
;
1114 /* We need to know how much memory to allocate for this part */
1115 for (i
= 0; i
< glyphSet
->hash
.hashSet
->size
; i
++) {
1116 GlyphRefPtr gr
= &table
[i
];
1117 GlyphPtr gl
= gr
->glyph
;
1119 if (!gl
|| gl
== DeletedGlyph
) continue;
1120 len_images
+= gl
->size
- sizeof(gl
->info
);
1123 /* Now allocate the memory we need */
1124 images
= ALLOCATE_LOCAL(len_images
*sizeof(char));
1125 gids
= ALLOCATE_LOCAL(glyphSet
->hash
.tableEntries
*sizeof(Glyph
));
1126 glyphs
= ALLOCATE_LOCAL(glyphSet
->hash
.tableEntries
*sizeof(XGlyphInfo
));
1128 memset(images
, 0, len_images
* sizeof(char));
1132 /* Fill the allocated memory with the proper data */
1133 for (i
= 0; i
< glyphSet
->hash
.hashSet
->size
; i
++) {
1134 GlyphRefPtr gr
= &table
[i
];
1135 GlyphPtr gl
= gr
->glyph
;
1137 if (!gl
|| gl
== DeletedGlyph
) continue;
1139 /* First lets put the data into gids */
1140 gids
[ctr
] = gr
->signature
;
1142 /* Next do the glyphs data structures */
1143 glyphs
[ctr
].width
= gl
->info
.width
;
1144 glyphs
[ctr
].height
= gl
->info
.height
;
1145 glyphs
[ctr
].x
= gl
->info
.x
;
1146 glyphs
[ctr
].y
= gl
->info
.y
;
1147 glyphs
[ctr
].xOff
= gl
->info
.xOff
;
1148 glyphs
[ctr
].yOff
= gl
->info
.yOff
;
1150 /* Copy the images from the DIX's data into the buffer */
1151 memcpy(pos
, gl
+1, gl
->size
- sizeof(gl
->info
));
1152 pos
+= gl
->size
- sizeof(gl
->info
);
1156 /* Now restore the glyph data */
1157 XRenderAddGlyphs(dmxScreen
->beDisplay
, glyphPriv
->glyphSets
[scrnNum
],
1158 gids
,glyphs
, glyphSet
->hash
.tableEntries
, images
,
1162 DEALLOCATE_LOCAL(len_images
);
1163 DEALLOCATE_LOCAL(gids
);
1164 DEALLOCATE_LOCAL(glyphs
);
1168 /** Reattach previously detached back-end screen. */
1169 int dmxAttachScreen(int idx
, DMXScreenAttributesPtr attr
)
1172 DMXScreenInfo
*dmxScreen
;
1173 CARD32 scrnNum
= idx
;
1174 DMXScreenInfo oldDMXScreen
;
1177 /* Return failure if dynamic addition/removal of screens is disabled */
1178 if (!dmxAddRemoveScreens
) {
1180 "Attempting to add a screen, but the AddRemoveScreen\n");
1182 "extension has not been enabled. To enable this extension\n");
1184 "add the \"-addremovescreens\" option either to the command\n");
1186 "line or in the configuration file.\n");
1190 /* Cannot add a screen that does not exist */
1191 if (idx
< 0 || idx
>= dmxNumScreens
) return 1;
1192 pScreen
= screenInfo
.screens
[idx
];
1193 dmxScreen
= &dmxScreens
[idx
];
1195 /* Cannot attach to a screen that is already opened */
1196 if (dmxScreen
->beDisplay
) {
1198 "Attempting to add screen #%d but a screen already exists\n",
1203 dmxLogOutput(dmxScreen
, "Attaching screen #%d\n", idx
);
1206 oldDMXScreen
= *dmxScreen
;
1208 /* Copy the name to the new screen */
1209 dmxScreen
->name
= strdup(attr
->displayName
);
1211 /* Open display and get all of the screen info */
1212 if (!dmxOpenDisplay(dmxScreen
)) {
1214 "dmxOpenDisplay: Unable to open display %s\n",
1217 /* Restore the old screen */
1218 *dmxScreen
= oldDMXScreen
;
1222 dmxSetErrorHandler(dmxScreen
);
1223 dmxCheckForWM(dmxScreen
);
1224 dmxGetScreenAttribs(dmxScreen
);
1226 if (!dmxGetVisualInfo(dmxScreen
)) {
1227 dmxLog(dmxWarning
, "dmxGetVisualInfo: No matching visuals found\n");
1228 XFree(dmxScreen
->beVisuals
);
1229 XCloseDisplay(dmxScreen
->beDisplay
);
1231 /* Restore the old screen */
1232 *dmxScreen
= oldDMXScreen
;
1236 dmxGetColormaps(dmxScreen
);
1237 dmxGetPixmapFormats(dmxScreen
);
1239 /* Verify that the screen to be added has the same info as the
1240 * previously added screen. */
1241 if (!dmxCompareScreens(dmxScreen
, &oldDMXScreen
)) {
1243 "New screen data (%s) does not match previously\n",
1246 "attached screen data (%s)\n",
1249 "All data must match in order to attach to screen #%d\n",
1251 XFree(dmxScreen
->beVisuals
);
1252 XFree(dmxScreen
->beDepths
);
1253 XFree(dmxScreen
->bePixmapFormats
);
1254 XCloseDisplay(dmxScreen
->beDisplay
);
1256 /* Restore the old screen */
1257 *dmxScreen
= oldDMXScreen
;
1261 /* Initialize the BE screen resources */
1262 dmxBEScreenInit(idx
, screenInfo
.screens
[idx
]);
1264 /* TODO: Handle GLX visual initialization. GLXProxy needs to be
1265 * updated to handle dynamic addition/removal of screens. */
1267 /* Create default stipple */
1268 dmxBECreatePixmap(pScreen
->PixmapPerDepth
[0]);
1269 dmxBERestorePixmap(pScreen
->PixmapPerDepth
[0]);
1271 /* Create the scratch GCs */
1272 dmxBECreateScratchGCs(idx
);
1274 /* Create the default font */
1275 (void)dmxBELoadFont(pScreen
, defaultFont
);
1277 /* Create all resources that don't depend on windows */
1278 for (i
= currentMaxClients
; --i
>= 0; )
1280 FindAllClientResources(clients
[i
], dmxBECreateResources
,
1283 /* Create window hierarchy (top down) */
1284 dmxBECreateWindowTree(idx
);
1287 /* Restore the picture state for RENDER */
1288 for (i
= currentMaxClients
; --i
>= 0; )
1290 FindClientResourcesByType(clients
[i
],PictureType
,
1291 dmxBERestoreRenderPict
,(pointer
)idx
);
1293 /* Restore the glyph state for RENDER */
1294 for (i
= currentMaxClients
; --i
>= 0; )
1296 FindClientResourcesByType(clients
[i
],GlyphSetType
,
1297 dmxBERestoreRenderGlyph
,(pointer
)idx
);
1300 /* Refresh screen by generating exposure events for all windows */
1301 dmxForceExposures(idx
);
1303 dmxSync(&dmxScreens
[idx
], TRUE
);
1305 /* We used these to compare the old and new screens. They are no
1306 * longer needed since we have a newly attached screen, so we can
1307 * now free the old screen's resources. */
1308 XFree(oldDMXScreen
.beVisuals
);
1309 XFree(oldDMXScreen
.beDepths
);
1310 XFree(oldDMXScreen
.bePixmapFormats
);
1311 /* TODO: should oldDMXScreen.name be freed?? */
1314 if (!noPanoramiXExtension
)
1315 return dmxConfigureScreenWindows(1, &scrnNum
, attr
, NULL
);
1318 return 0; /* Success */
1322 * Resources that may have state on the BE server and need to be freed:
1354 * SecurityAuthorizationResType
1364 /** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs
1365 * to have its image saved. */
1366 static void dmxBEFindPixmapImage(pointer value
, XID id
, RESTYPE type
,
1369 if ((type
& TypeMask
) == (XRT_PIXMAP
& TypeMask
)) {
1370 PixmapPtr pDst
= (PixmapPtr
)p
;
1371 int idx
= pDst
->drawable
.pScreen
->myNum
;
1372 PanoramiXRes
*pXinPix
= (PanoramiXRes
*)value
;
1376 pPix
= (PixmapPtr
)LookupIDByType(pXinPix
->info
[idx
].id
, RT_PIXMAP
);
1377 if (pPix
!= pDst
) return; /* Not a match.... Next! */
1379 for (i
= 0; i
< PanoramiXNumScreens
; i
++) {
1381 dmxPixPrivPtr pSrcPriv
= NULL
;
1383 if (i
== idx
) continue; /* Self replication is bad */
1386 (PixmapPtr
)LookupIDByType(pXinPix
->info
[i
].id
, RT_PIXMAP
);
1387 pSrcPriv
= DMX_GET_PIXMAP_PRIV(pSrc
);
1388 if (pSrcPriv
->pixmap
) {
1389 FoundPixImage
= True
;
1397 /** Save the pixmap image only when there is not another screen with
1398 * that pixmap from which the image can be read when the screen is
1399 * reattached. To do this, we first try to find a pixmap on another
1400 * screen corresponding to the one we are trying to save. If we find
1401 * one, then we do not need to save the image data since during
1402 * reattachment, the image data can be read from that other pixmap.
1403 * However, if we do not find one, then we need to save the image data.
1404 * The common case for these are for the default stipple and root
1406 static void dmxBESavePixmap(PixmapPtr pPixmap
)
1411 /* If Xinerama is not active, there's nothing we can do (see comment
1412 * in #else below for more info). */
1413 if (noPanoramiXExtension
) return;
1415 FoundPixImage
= False
;
1416 for (i
= currentMaxClients
; --i
>= 0; )
1418 FindAllClientResources(clients
[i
], dmxBEFindPixmapImage
,
1421 /* Save the image only if there is no other screens that have a
1422 * pixmap that corresponds to the one we are trying to save. */
1423 if (!FoundPixImage
) {
1424 dmxPixPrivPtr pPixPriv
= DMX_GET_PIXMAP_PRIV(pPixmap
);
1426 if (!pPixPriv
->detachedImage
) {
1427 ScreenPtr pScreen
= pPixmap
->drawable
.pScreen
;
1428 DMXScreenInfo
*dmxScreen
= &dmxScreens
[pScreen
->myNum
];
1430 pPixPriv
->detachedImage
= XGetImage(dmxScreen
->beDisplay
,
1433 pPixmap
->drawable
.width
,
1434 pPixmap
->drawable
.height
,
1437 if (!pPixPriv
->detachedImage
)
1438 dmxLog(dmxWarning
, "Cannot save pixmap image\n");
1442 /* NOTE: The only time there is a pixmap on another screen that
1443 * corresponds to the one we are trying to save is when Xinerama is
1444 * active. Otherwise, the pixmap image data is only stored on a
1445 * single screen, which means that once it is detached, that data is
1446 * lost. We could save the data here, but then that would require
1447 * us to implement the ability for Xdmx to keep the pixmap up to
1448 * date while the screen is detached, which is beyond the scope of
1449 * the current project. */
1454 /** Destroy resources on the back-end server. This function is called
1455 * from #dmxDetachScreen() via the dix layer's FindAllResources
1456 * function. It walks all resources, compares them to the screen
1457 * number passed in as \a n and calls the appropriate DMX function to
1458 * free the associated resource on the back-end server. */
1459 static void dmxBEDestroyResources(pointer value
, XID id
, RESTYPE type
,
1462 int scrnNum
= (int)n
;
1463 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
1465 if ((type
& TypeMask
) == (RT_WINDOW
& TypeMask
)) {
1466 /* Window resources are destroyed below in dmxBEDestroyWindowTree */
1467 } else if ((type
& TypeMask
) == (RT_PIXMAP
& TypeMask
)) {
1468 PixmapPtr pPix
= value
;
1469 if (pPix
->drawable
.pScreen
->myNum
== scrnNum
) {
1470 dmxBESavePixmap(pPix
);
1471 dmxBEFreePixmap(pPix
);
1473 } else if ((type
& TypeMask
) == (RT_GC
& TypeMask
)) {
1475 if (pGC
->pScreen
->myNum
== scrnNum
)
1477 } else if ((type
& TypeMask
) == (RT_FONT
& TypeMask
)) {
1478 dmxBEFreeFont(pScreen
, (FontPtr
)value
);
1479 } else if ((type
& TypeMask
) == (RT_CURSOR
& TypeMask
)) {
1480 dmxBEFreeCursor(pScreen
, (CursorPtr
)value
);
1481 } else if ((type
& TypeMask
) == (RT_COLORMAP
& TypeMask
)) {
1482 ColormapPtr pCmap
= value
;
1483 if (pCmap
->pScreen
->myNum
== scrnNum
)
1484 dmxBEFreeColormap((ColormapPtr
)value
);
1486 } else if ((type
& TypeMask
) == (PictureType
& TypeMask
)) {
1487 PicturePtr pPict
= value
;
1488 if (pPict
->pDrawable
->pScreen
->myNum
== scrnNum
) {
1489 /* Free the pixmaps on the backend if needed */
1490 if (pPict
->pDrawable
->type
== DRAWABLE_PIXMAP
) {
1491 PixmapPtr pPixmap
= (PixmapPtr
)(pPict
->pDrawable
);
1492 dmxBESavePixmap(pPixmap
);
1493 dmxBEFreePixmap(pPixmap
);
1495 dmxBEFreePicture((PicturePtr
)value
);
1497 } else if ((type
& TypeMask
) == (GlyphSetType
& TypeMask
)) {
1498 dmxBEFreeGlyphSet(pScreen
, (GlyphSetPtr
)value
);
1501 /* Other resource types??? */
1505 /** Destroy the scratch GCs that are created per depth. */
1506 static void dmxBEDestroyScratchGCs(int scrnNum
)
1508 ScreenPtr pScreen
= screenInfo
.screens
[scrnNum
];
1509 GCPtr
*ppGC
= pScreen
->GCperDepth
;
1512 for (i
= 0; i
<= pScreen
->numDepths
; i
++)
1513 dmxBEFreeGC(ppGC
[i
]);
1516 /** Destroy window hierachy on back-end server. To ensure that all
1517 * XDestroyWindow() calls succeed, they must be performed in a bottom
1518 * up order so that windows are not destroyed before their children.
1519 * XDestroyWindow(), which is called from #dmxBEDestrowWindow(), will
1520 * destroy a window as well as all of it's children. */
1521 static void dmxBEDestroyWindowTree(int idx
)
1523 WindowPtr pWin
= WindowTable
[idx
];
1524 WindowPtr pChild
= pWin
;
1527 if (pChild
->firstChild
) {
1528 pChild
= pChild
->firstChild
;
1532 /* Destroy the window */
1533 dmxBEDestroyWindow(pChild
);
1535 /* Make sure we destroy the window's border and background
1536 * pixmaps if they exist */
1537 if (!pChild
->borderIsPixel
) {
1538 dmxBESavePixmap(pChild
->border
.pixmap
);
1539 dmxBEFreePixmap(pChild
->border
.pixmap
);
1541 if (pChild
->backgroundState
== BackgroundPixmap
) {
1542 dmxBESavePixmap(pChild
->background
.pixmap
);
1543 dmxBEFreePixmap(pChild
->background
.pixmap
);
1546 while (!pChild
->nextSib
&& (pChild
!= pWin
)) {
1547 pChild
= pChild
->parent
;
1548 dmxBEDestroyWindow(pChild
);
1549 if (!pChild
->borderIsPixel
) {
1550 dmxBESavePixmap(pChild
->border
.pixmap
);
1551 dmxBEFreePixmap(pChild
->border
.pixmap
);
1553 if (pChild
->backgroundState
== BackgroundPixmap
) {
1554 dmxBESavePixmap(pChild
->background
.pixmap
);
1555 dmxBEFreePixmap(pChild
->background
.pixmap
);
1562 pChild
= pChild
->nextSib
;
1566 /** Detach back-end screen. */
1567 int dmxDetachScreen(int idx
)
1569 DMXScreenInfo
*dmxScreen
= &dmxScreens
[idx
];
1572 /* Return failure if dynamic addition/removal of screens is disabled */
1573 if (!dmxAddRemoveScreens
) {
1575 "Attempting to remove a screen, but the AddRemoveScreen\n");
1577 "extension has not been enabled. To enable this extension\n");
1579 "add the \"-addremovescreens\" option either to the command\n");
1581 "line or in the configuration file.\n");
1585 /* Cannot remove a screen that does not exist */
1586 if (idx
< 0 || idx
>= dmxNumScreens
) return 1;
1588 /* Cannot detach from a screen that is not opened */
1589 if (!dmxScreen
->beDisplay
) {
1591 "Attempting to remove screen #%d but it has not been opened\n",
1596 dmxLogOutput(dmxScreen
, "Detaching screen #%d\n", idx
);
1599 dmxInputDetachAll(dmxScreen
);
1601 /* Save all relevant state (TODO) */
1603 /* Free all non-window resources related to this screen */
1604 for (i
= currentMaxClients
; --i
>= 0; )
1606 FindAllClientResources(clients
[i
], dmxBEDestroyResources
,
1609 /* Free scratch GCs */
1610 dmxBEDestroyScratchGCs(idx
);
1612 /* Free window resources related to this screen */
1613 dmxBEDestroyWindowTree(idx
);
1615 /* Free default stipple */
1616 dmxBESavePixmap(screenInfo
.screens
[idx
]->PixmapPerDepth
[0]);
1617 dmxBEFreePixmap(screenInfo
.screens
[idx
]->PixmapPerDepth
[0]);
1619 /* Free the remaining screen resources and close the screen */
1620 dmxBECloseScreen(screenInfo
.screens
[idx
]);
1622 /* Adjust the cursor boundaries (paints detached console window) */
1623 dmxAdjustCursorBoundaries();
1625 return 0; /* Success */