Initial commit
[xorg_rtime.git] / xorg-server-1.4 / hw / dmx / dmxextension.c
blob103364446a925dc3b1250cd830a3dcc998d601ba
1 /*
2 * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
4 * All Rights Reserved.
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
25 * SOFTWARE.
29 * Author:
30 * Rickard E. (Rik) Faith <faith@redhat.com>
31 * Kevin E. Martin <kem@redhat.com>
35 /** \file
36 * This file provides the only interface to the X server extension support
37 * in programs/Xserver/Xext. Those programs should only include dmxext.h
40 #ifdef HAVE_DMX_CONFIG_H
41 #include <dmx-config.h>
42 #endif
44 #include "dmx.h"
45 #include "dmxinit.h"
46 #include "dmxextension.h"
47 #include "dmxwindow.h"
48 #include "dmxcb.h"
49 #include "dmxcursor.h"
50 #include "dmxpixmap.h"
51 #include "dmxgc.h"
52 #include "dmxfont.h"
53 #include "dmxcmap.h"
54 #ifdef RENDER
55 #include "dmxpict.h"
56 #endif
57 #include "dmxinput.h"
58 #include "dmxsync.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;
81 #ifdef PANORAMIX
82 attr->logicalScreen = noPanoramiXExtension ? dmxScreen->index : 0;
83 #else
84 attr->logicalScreen = dmxScreen->index;
85 #endif
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;
100 return TRUE;
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) {
118 attr->vis.x = 0;
119 attr->vis.y = 0;
120 attr->vis.height = 0;
121 attr->vis.width = 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) {
136 if (attr->pos.x < 0)
137 attr->vis.width = pWindow->drawable.pScreen->width;
138 else
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) {
146 if (attr->pos.y < 0)
147 attr->vis.height = pWindow->drawable.pScreen->height;
148 else
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;
156 return TRUE;
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)
172 int i, total;
174 for (total = i = 0; i < dmxNumInputs; i++) total += dmxInputs[i].numDevs;
175 return total;
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
181 * structure. */
182 int dmxGetInputAttributes(int deviceId, DMXInputAttributesPtr attr)
184 int i, j;
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;
198 attr->name = NULL;
199 switch (dmxLocal->extType) {
200 case DMX_LOCAL_TYPE_LOCAL:
201 attr->inputType = 0;
202 break;
203 case DMX_LOCAL_TYPE_CONSOLE:
204 attr->inputType = 1;
205 attr->name = dmxInput->name;
206 attr->physicalId = dmxLocal->deviceId;
207 break;
208 case DMX_LOCAL_TYPE_BACKEND:
209 case DMX_LOCAL_TYPE_COMMON:
210 attr->inputType = 2;
211 attr->physicalScreen = dmxInput->scrnIdx;
212 attr->name = dmxInput->name;
213 attr->physicalId = dmxLocal->deviceId;
214 break;
216 return 0; /* Success */
219 return -1; /* Failure */
222 /** Reinitialized the cursor boundaries. */
223 static void dmxAdjustCursorBoundaries(void)
225 int i;
227 dmxReInitOrigins();
228 dmxInitOverlap();
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);
236 dmxCheckCursor();
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,
254 attr->sendsCore,id);
256 if (retcode == Success) {
257 /* Adjust the cursor boundaries */
258 dmxAdjustCursorBoundaries();
260 /* Force completion of the changes */
261 dmxSync(NULL, TRUE);
264 return retcode;
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
282 * pWindow. */
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)
292 dmxSync(NULL, TRUE);
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];
301 WindowPtr pChild;
302 Bool anyMarked = FALSE;
304 /* Handle special case where width and/or height are zero */
305 if (w == 0 || h == 0) {
306 w = 1;
307 h = 1;
310 /* Change screen size */
311 pScreen->width = w;
312 pScreen->height = h;
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 */
330 pScreen->mmWidth =
331 (w * 254 + dmxScreen->beXDPI * 5) / (dmxScreen->beXDPI * 10);
332 pScreen->mmHeight =
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,
339 (WindowPtr *)NULL);
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 */
348 if (anyMarked) {
349 /* If any windows have been marked, set the root window's
350 * clipList to be broken since it will be recalculated in
351 * ValidateTree()
353 REGION_BREAK(pScreen, &pRoot->clipList);
354 } else {
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 */
365 if (anyMarked) {
366 pScreen->ValidateTree(pRoot, NULL, VTBroken);
367 pScreen->HandleExposures(pRoot);
368 if (pScreen->PostValidateTree)
369 pScreen->PostValidateTree(pRoot, NULL, VTBroken);
373 #ifdef PANORAMIX
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
420 * window */
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];
441 WindowPtr pChild;
442 int xoff;
443 int yoff;
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;
463 while (pChild) {
464 /* Adjust child window's position */
465 pScreen->MoveWindow(pChild,
466 pChild->origin.x - wBorderWidth(pChild) - xoff,
467 pChild->origin.y - wBorderWidth(pChild) - yoff,
468 pChild->nextSib,
469 VTMove);
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
475 * offscreen flag.
478 pChild = pChild->nextSib;
482 /** Configure the attributes of each "screen" and "root" window. */
483 int dmxConfigureScreenWindows(int nscreens,
484 CARD32 *screens,
485 DMXScreenAttributesPtr attribs,
486 int *errorScreen)
488 int i;
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",
553 idx,
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 */
590 dmxSync(NULL, TRUE);
592 return Success;
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) {
607 int i;
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) {
614 int w, h;
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,
622 dmxScreen->rootX,
623 dmxScreen->rootY,
624 w, h);
629 /* Set the global width/height */
630 dmxSetWidthHeight(attribs->width, attribs->height);
632 /* Handle shift[XY] changes */
633 if (attribs->shiftX || attribs->shiftY) {
634 int i;
635 for (i = 0; i < dmxNumScreens; i++) {
636 ScreenPtr pScreen = screenInfo.screens[i];
637 WindowPtr pChild = WindowTable[i]->firstChild;
638 while (pChild) {
639 /* Adjust child window's position */
640 pScreen->MoveWindow(pChild,
641 pChild->origin.x - wBorderWidth(pChild)
642 - attribs->shiftX,
643 pChild->origin.y - wBorderWidth(pChild)
644 - attribs->shiftY,
645 pChild->nextSib,
646 VTMove);
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 */
668 dmxSync(NULL, TRUE);
670 return Success;
672 #endif
674 /** Create the scratch GCs per depth. */
675 static void dmxBECreateScratchGCs(int scrnNum)
677 ScreenPtr pScreen = screenInfo.screens[scrnNum];
678 GCPtr *ppGC = pScreen->GCperDepth;
679 int i;
681 for (i = 0; i <= pScreen->numDepths; i++)
682 dmxBECreateGC(pScreen, ppGC[i]);
685 #ifdef PANORAMIX
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,
693 pointer p)
695 if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) {
696 PixmapPtr pDst = (PixmapPtr)p;
697 int idx = pDst->drawable.pScreen->myNum;
698 PanoramiXRes *pXinPix = (PanoramiXRes *)value;
699 PixmapPtr pPix;
700 int i;
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++) {
706 PixmapPtr pSrc;
707 dmxPixPrivPtr pSrcPriv = NULL;
709 if (i == idx) continue; /* Self replication is bad */
711 pSrc =
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);
718 XImage *img;
719 int j;
720 XlibGC gc = NULL;
722 /* This should never happen, but just in case.... */
723 if (pSrc->drawable.width != pDst->drawable.width ||
724 pSrc->drawable.height != pDst->drawable.height)
725 return;
727 /* Copy from src pixmap to dst pixmap */
728 img = XGetImage(dmxSrcScreen->beDisplay,
729 pSrcPriv->pixmap,
730 0, 0,
731 pSrc->drawable.width, pSrc->drawable.height,
733 ZPixmap);
735 for (j = 0; j < dmxDstScreen->beNumPixmapFormats; j++) {
736 if (dmxDstScreen->bePixmapFormats[j].depth == img->depth) {
737 unsigned long m;
738 XGCValues v;
740 m = GCFunction | GCPlaneMask | GCClipMask;
741 v.function = GXcopy;
742 v.plane_mask = AllPlanes;
743 v.clip_mask = None;
745 gc = XCreateGC(dmxDstScreen->beDisplay,
746 dmxDstScreen->scrnDefDrawables[j],
747 m, &v);
748 break;
752 if (gc) {
753 XPutImage(dmxDstScreen->beDisplay,
754 pDstPriv->pixmap,
755 gc, img, 0, 0, 0, 0,
756 pDst->drawable.width, pDst->drawable.height);
757 XFreeGC(dmxDstScreen->beDisplay, gc);
758 FoundPixImage = True;
759 } else {
760 dmxLog(dmxWarning, "Could not create GC\n");
763 XDestroyImage(img);
764 return;
769 #endif
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)
775 #ifdef PANORAMIX
776 int i;
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");
782 return;
785 FoundPixImage = False;
786 for (i = currentMaxClients; --i >= 0; )
787 if (clients[i])
788 FindAllClientResources(clients[i], dmxBERestorePixmapImage,
789 (pointer)pPixmap);
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
793 * (if available). */
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];
800 XlibGC gc = NULL;
802 for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
803 if (dmxScreen->bePixmapFormats[i].depth ==
804 pPixPriv->detachedImage->depth) {
805 unsigned long m;
806 XGCValues v;
808 m = GCFunction | GCPlaneMask | GCClipMask;
809 v.function = GXcopy;
810 v.plane_mask = AllPlanes;
811 v.clip_mask = None;
813 gc = XCreateGC(dmxScreen->beDisplay,
814 dmxScreen->scrnDefDrawables[i],
815 m, &v);
816 break;
820 if (gc) {
821 XPutImage(dmxScreen->beDisplay,
822 pPixPriv->pixmap,
824 pPixPriv->detachedImage,
825 0, 0, 0, 0,
826 pPixmap->drawable.width, pPixmap->drawable.height);
827 XFreeGC(dmxScreen->beDisplay, gc);
828 } else {
829 dmxLog(dmxWarning, "Cannot restore pixmap image\n");
832 XDestroyImage(pPixPriv->detachedImage);
833 pPixPriv->detachedImage = NULL;
834 } else {
835 dmxLog(dmxWarning, "Cannot restore pixmap image\n");
838 #else
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");
845 return;
846 #endif
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,
855 pointer n)
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)) {
869 GCPtr pGC = value;
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);
896 #if 0
897 #ifdef RENDER
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);
903 #endif
904 #endif
905 } else {
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);
921 WindowPtr pWin;
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;
938 while (pWin) {
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,
955 &pWinPriv->cmap,
956 &pWinPriv->visual);
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;
965 continue;
968 /* If the window has no children, move on to the next higher window */
969 while (!pWin->prevSib && (pWin != pRoot))
970 pWin = pWin->parent;
972 if (pWin->prevSib) {
973 pWin = pWin->prevSib;
974 continue;
977 /* When we reach the root window, we are finished */
978 if (pWin == pRoot)
979 break;
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;
989 WindowPtr pChild;
991 for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib)
992 anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild,
993 (WindowPtr *)NULL);
994 if (anyMarked) {
995 /* If any windows have been marked, set the root window's
996 * clipList to be broken since it will be recalculated in
997 * ValidateTree()
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)
1010 int i;
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;
1055 return TRUE;
1058 #ifdef RENDER
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*/
1068 return;
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];
1089 GlyphRefPtr table;
1090 char *images;
1091 Glyph *gids;
1092 XGlyphInfo *glyphs;
1093 char *pos;
1094 int beret;
1095 int len_images = 0;
1096 int i;
1097 int ctr;
1099 if (glyphPriv->glyphSets[scrnNum]) {
1100 /* Only restore glyphs on the screen we are attaching */
1101 return;
1104 /* First we must create the glyph set on the backend. */
1105 if ((beret = dmxBECreateGlyphSet(scrnNum, glyphSet)) != Success) {
1106 dmxLog(dmxWarning,
1107 "\tdmxBERestoreRenderGlyph failed to create glyphset!\n");
1108 return;
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));
1129 pos = images;
1130 ctr = 0;
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);
1153 ctr++;
1156 /* Now restore the glyph data */
1157 XRenderAddGlyphs(dmxScreen->beDisplay, glyphPriv->glyphSets[scrnNum],
1158 gids,glyphs, glyphSet->hash.tableEntries, images,
1159 len_images);
1161 /* Clean up */
1162 DEALLOCATE_LOCAL(len_images);
1163 DEALLOCATE_LOCAL(gids);
1164 DEALLOCATE_LOCAL(glyphs);
1166 #endif
1168 /** Reattach previously detached back-end screen. */
1169 int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr)
1171 ScreenPtr pScreen;
1172 DMXScreenInfo *dmxScreen;
1173 CARD32 scrnNum = idx;
1174 DMXScreenInfo oldDMXScreen;
1175 int i;
1177 /* Return failure if dynamic addition/removal of screens is disabled */
1178 if (!dmxAddRemoveScreens) {
1179 dmxLog(dmxWarning,
1180 "Attempting to add a screen, but the AddRemoveScreen\n");
1181 dmxLog(dmxWarning,
1182 "extension has not been enabled. To enable this extension\n");
1183 dmxLog(dmxWarning,
1184 "add the \"-addremovescreens\" option either to the command\n");
1185 dmxLog(dmxWarning,
1186 "line or in the configuration file.\n");
1187 return 1;
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) {
1197 dmxLog(dmxWarning,
1198 "Attempting to add screen #%d but a screen already exists\n",
1199 idx);
1200 return 1;
1203 dmxLogOutput(dmxScreen, "Attaching screen #%d\n", idx);
1205 /* Save old info */
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)) {
1213 dmxLog(dmxWarning,
1214 "dmxOpenDisplay: Unable to open display %s\n",
1215 dmxScreen->name);
1217 /* Restore the old screen */
1218 *dmxScreen = oldDMXScreen;
1219 return 1;
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;
1233 return 1;
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)) {
1242 dmxLog(dmxWarning,
1243 "New screen data (%s) does not match previously\n",
1244 dmxScreen->name);
1245 dmxLog(dmxWarning,
1246 "attached screen data (%s)\n",
1247 oldDMXScreen.name);
1248 dmxLog(dmxWarning,
1249 "All data must match in order to attach to screen #%d\n",
1250 idx);
1251 XFree(dmxScreen->beVisuals);
1252 XFree(dmxScreen->beDepths);
1253 XFree(dmxScreen->bePixmapFormats);
1254 XCloseDisplay(dmxScreen->beDisplay);
1256 /* Restore the old screen */
1257 *dmxScreen = oldDMXScreen;
1258 return 1;
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; )
1279 if (clients[i])
1280 FindAllClientResources(clients[i], dmxBECreateResources,
1281 (pointer)idx);
1283 /* Create window hierarchy (top down) */
1284 dmxBECreateWindowTree(idx);
1286 #ifdef RENDER
1287 /* Restore the picture state for RENDER */
1288 for (i = currentMaxClients; --i >= 0; )
1289 if (clients[i])
1290 FindClientResourcesByType(clients[i],PictureType,
1291 dmxBERestoreRenderPict,(pointer)idx);
1293 /* Restore the glyph state for RENDER */
1294 for (i = currentMaxClients; --i >= 0; )
1295 if (clients[i])
1296 FindClientResourcesByType(clients[i],GlyphSetType,
1297 dmxBERestoreRenderGlyph,(pointer)idx);
1298 #endif
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?? */
1313 #ifdef PANORAMIX
1314 if (!noPanoramiXExtension)
1315 return dmxConfigureScreenWindows(1, &scrnNum, attr, NULL);
1316 else
1317 #endif
1318 return 0; /* Success */
1322 * Resources that may have state on the BE server and need to be freed:
1324 * RT_NONE
1325 * RT_WINDOW
1326 * RT_PIXMAP
1327 * RT_GC
1328 * RT_FONT
1329 * RT_CURSOR
1330 * RT_COLORMAP
1331 * RT_CMAPENTRY
1332 * RT_OTHERCLIENT
1333 * RT_PASSIVEGRAB
1334 * XRT_WINDOW
1335 * XRT_PIXMAP
1336 * XRT_GC
1337 * XRT_COLORMAP
1338 * XRT_PICTURE
1339 * PictureType
1340 * PictFormatType
1341 * GlyphSetType
1342 * ClientType
1343 * EventType
1344 * RT_INPUTCLIENT
1345 * XETrapType
1346 * RTCounter
1347 * RTAwait
1348 * RTAlarmClient
1349 * RT_XKBCLIENT
1350 * RTContext
1351 * TagResType
1352 * StalledResType
1353 * RT_APPGROUP
1354 * SecurityAuthorizationResType
1355 * RTEventClient
1356 * __glXContextRes
1357 * __glXClientRes
1358 * __glXPixmapRes
1359 * __glXWindowRes
1360 * __glXPbufferRes
1363 #ifdef PANORAMIX
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,
1367 pointer p)
1369 if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) {
1370 PixmapPtr pDst = (PixmapPtr)p;
1371 int idx = pDst->drawable.pScreen->myNum;
1372 PanoramiXRes *pXinPix = (PanoramiXRes *)value;
1373 PixmapPtr pPix;
1374 int i;
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++) {
1380 PixmapPtr pSrc;
1381 dmxPixPrivPtr pSrcPriv = NULL;
1383 if (i == idx) continue; /* Self replication is bad */
1385 pSrc =
1386 (PixmapPtr)LookupIDByType(pXinPix->info[i].id, RT_PIXMAP);
1387 pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc);
1388 if (pSrcPriv->pixmap) {
1389 FoundPixImage = True;
1390 return;
1395 #endif
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
1405 * tile. */
1406 static void dmxBESavePixmap(PixmapPtr pPixmap)
1408 #ifdef PANORAMIX
1409 int i;
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; )
1417 if (clients[i])
1418 FindAllClientResources(clients[i], dmxBEFindPixmapImage,
1419 (pointer)pPixmap);
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,
1431 pPixPriv->pixmap,
1432 0, 0,
1433 pPixmap->drawable.width,
1434 pPixmap->drawable.height,
1436 ZPixmap);
1437 if (!pPixPriv->detachedImage)
1438 dmxLog(dmxWarning, "Cannot save pixmap image\n");
1441 #else
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. */
1450 return;
1451 #endif
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,
1460 pointer n)
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)) {
1474 GCPtr pGC = value;
1475 if (pGC->pScreen->myNum == scrnNum)
1476 dmxBEFreeGC(pGC);
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);
1485 #ifdef RENDER
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);
1499 #endif
1500 } else {
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;
1510 int i;
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;
1526 while (1) {
1527 if (pChild->firstChild) {
1528 pChild = pChild->firstChild;
1529 continue;
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);
1559 if (pChild == pWin)
1560 break;
1562 pChild = pChild->nextSib;
1566 /** Detach back-end screen. */
1567 int dmxDetachScreen(int idx)
1569 DMXScreenInfo *dmxScreen = &dmxScreens[idx];
1570 int i;
1572 /* Return failure if dynamic addition/removal of screens is disabled */
1573 if (!dmxAddRemoveScreens) {
1574 dmxLog(dmxWarning,
1575 "Attempting to remove a screen, but the AddRemoveScreen\n");
1576 dmxLog(dmxWarning,
1577 "extension has not been enabled. To enable this extension\n");
1578 dmxLog(dmxWarning,
1579 "add the \"-addremovescreens\" option either to the command\n");
1580 dmxLog(dmxWarning,
1581 "line or in the configuration file.\n");
1582 return 1;
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) {
1590 dmxLog(dmxWarning,
1591 "Attempting to remove screen #%d but it has not been opened\n",
1592 idx);
1593 return 1;
1596 dmxLogOutput(dmxScreen, "Detaching screen #%d\n", idx);
1598 /* Detach input */
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; )
1605 if (clients[i])
1606 FindAllClientResources(clients[i], dmxBEDestroyResources,
1607 (pointer)idx);
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 */