diff options
Diffstat (limited to 'nx-X11/programs/Xserver/hw/dmx/dmxextension.c')
-rw-r--r-- | nx-X11/programs/Xserver/hw/dmx/dmxextension.c | 1497 |
1 files changed, 1497 insertions, 0 deletions
diff --git a/nx-X11/programs/Xserver/hw/dmx/dmxextension.c b/nx-X11/programs/Xserver/hw/dmx/dmxextension.c new file mode 100644 index 000000000..feadb5e31 --- /dev/null +++ b/nx-X11/programs/Xserver/hw/dmx/dmxextension.c @@ -0,0 +1,1497 @@ +/* $XFree86$ */ +/* + * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. + * + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * Author: + * Rickard E. (Rik) Faith <faith@redhat.com> + * Kevin E. Martin <kem@redhat.com> + * + */ + +/** \file + * This file provides the only interface to the X server extension support + * in programs/Xserver/Xext. Those programs should only include dmxext.h + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxinit.h" +#include "dmxextension.h" +#include "dmxwindow.h" +#include "dmxcb.h" +#include "dmxcursor.h" +#include "dmxpixmap.h" +#include "dmxgc.h" +#include "dmxfont.h" +#include "dmxcmap.h" +#ifdef RENDER +#include "dmxpict.h" +#endif +#include "dmxinput.h" +#include "dmxsync.h" +#include "dmxscrinit.h" +#include "input/dmxinputinit.h" + +#include "windowstr.h" +#include "inputstr.h" /* For DeviceIntRec */ +#include <X11/extensions/dmxproto.h> /* For DMX_BAD_* */ +#include "cursorstr.h" + +/* The default font is declared in dix/globals.c, but is not included in + * _any_ header files. */ +extern FontPtr defaultFont; + +/** This routine provides information to the DMX protocol extension + * about a particular screen. */ +Bool dmxGetScreenAttributes(int physical, DMXScreenAttributesPtr attr) +{ + DMXScreenInfo *dmxScreen; + + if (physical < 0 || physical >= dmxNumScreens) return FALSE; + + dmxScreen = &dmxScreens[physical]; + attr->displayName = dmxScreen->name; +#ifdef PANORAMIX + attr->logicalScreen = noPanoramiXExtension ? dmxScreen->index : 0; +#else + attr->logicalScreen = dmxScreen->index; +#endif + + attr->screenWindowWidth = dmxScreen->scrnWidth; + attr->screenWindowHeight = dmxScreen->scrnHeight; + attr->screenWindowXoffset = dmxScreen->scrnX; + attr->screenWindowYoffset = dmxScreen->scrnY; + + attr->rootWindowWidth = dmxScreen->rootWidth; + attr->rootWindowHeight = dmxScreen->rootHeight; + attr->rootWindowXoffset = dmxScreen->rootX; + attr->rootWindowYoffset = dmxScreen->rootY; + + attr->rootWindowXorigin = dmxScreen->rootXOrigin; + attr->rootWindowYorigin = dmxScreen->rootYOrigin; + + return TRUE; +} + +/** This routine provides information to the DMX protocol extension + * about a particular window. */ +Bool dmxGetWindowAttributes(WindowPtr pWindow, DMXWindowAttributesPtr attr) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + attr->screen = pWindow->drawable.pScreen->myNum; + attr->window = pWinPriv->window; + + attr->pos.x = pWindow->drawable.x; + attr->pos.y = pWindow->drawable.y; + attr->pos.width = pWindow->drawable.width; + attr->pos.height = pWindow->drawable.height; + + if (!pWinPriv->window || pWinPriv->offscreen) { + attr->vis.x = 0; + attr->vis.y = 0; + attr->vis.height = 0; + attr->vis.width = 0; + return pWinPriv->window ? TRUE : FALSE; + } + + /* Compute display-relative coordinates */ + attr->vis.x = pWindow->drawable.x; + attr->vis.y = pWindow->drawable.y; + attr->vis.width = pWindow->drawable.width; + attr->vis.height = pWindow->drawable.height; + + if (attr->pos.x < 0) { + attr->vis.x -= attr->pos.x; + attr->vis.width = attr->pos.x + attr->pos.width - attr->vis.x; + } + if (attr->pos.x + attr->pos.width > pWindow->drawable.pScreen->width) { + if (attr->pos.x < 0) + attr->vis.width = pWindow->drawable.pScreen->width; + else + attr->vis.width = pWindow->drawable.pScreen->width - attr->pos.x; + } + if (attr->pos.y < 0) { + attr->vis.y -= attr->pos.y; + attr->vis.height = attr->pos.y + attr->pos.height - attr->vis.y; + } + if (attr->pos.y + attr->pos.height > pWindow->drawable.pScreen->height) { + if (attr->pos.y < 0) + attr->vis.height = pWindow->drawable.pScreen->height; + else + attr->vis.height = pWindow->drawable.pScreen->height - attr->pos.y; + } + + /* Convert to window-relative coordinates */ + attr->vis.x -= attr->pos.x; + attr->vis.y -= attr->pos.y; + + return TRUE; +} + +void dmxGetDesktopAttributes(DMXDesktopAttributesPtr attr) +{ + attr->width = dmxGlobalWidth; + attr->height = dmxGlobalHeight; + attr->shiftX = 0; /* NOTE: The upper left hand corner of */ + attr->shiftY = 0; /* the desktop is always <0,0>. */ +} + +/** Return the total number of devices, not just #dmxNumInputs. The + * number returned should be the same as that returned by + * XListInputDevices. */ +int dmxGetInputCount(void) +{ + int i, total; + + for (total = i = 0; i < dmxNumInputs; i++) total += dmxInputs[i].numDevs; + return total; +} + +/** Return information about the device with id = \a deviceId. This + * information is primarily for the #ProcDMXGetInputAttributes() + * function, which does not have access to the appropriate data + * structure. */ +int dmxGetInputAttributes(int deviceId, DMXInputAttributesPtr attr) +{ + int i, j; + DMXInputInfo *dmxInput; + + if (deviceId < 0) return -1; + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (deviceId != dmxLocal->pDevice->id) continue; + attr->isCore = !!dmxLocal->isCore; + attr->sendsCore = !!dmxLocal->sendsCore; + attr->detached = !!dmxInput->detached; + attr->physicalScreen = -1; + attr->physicalId = -1; + attr->name = NULL; + switch (dmxLocal->extType) { + case DMX_LOCAL_TYPE_LOCAL: + attr->inputType = 0; + break; + case DMX_LOCAL_TYPE_CONSOLE: + attr->inputType = 1; + attr->name = dmxInput->name; + attr->physicalId = dmxLocal->deviceId; + break; + case DMX_LOCAL_TYPE_BACKEND: + case DMX_LOCAL_TYPE_COMMON: + attr->inputType = 2; + attr->physicalScreen = dmxInput->scrnIdx; + attr->name = dmxInput->name; + attr->physicalId = dmxLocal->deviceId; + break; + } + return 0; /* Success */ + } + } + return -1; /* Failure */ +} + +/** Reinitialized the cursor boundaries. */ +static void dmxAdjustCursorBoundaries(void) +{ + int i; + + dmxReInitOrigins(); + dmxInitOverlap(); + dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX); + dmxConnectionBlockCallback(); + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (!dmxInput->detached) dmxInputReInit(dmxInput); + } + + dmxCheckCursor(); + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (!dmxInput->detached) dmxInputLateReInit(dmxInput); + } +} + +/** Add an input with the specified attributes. If the input is added, + * the physical id is returned in \a deviceId. */ +int dmxAddInput(DMXInputAttributesPtr attr, int *id) +{ + int retcode = BadValue; + + if (attr->inputType == 1) /* console */ + retcode = dmxInputAttachConsole(attr->name, attr->sendsCore, id); + else if (attr->inputType == 2) /* backend */ + retcode = dmxInputAttachBackend(attr->physicalScreen, + attr->sendsCore,id); + + if (retcode == Success) { + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + } + + return retcode; +} + +/** Remove the input with physical id \a id. */ +int dmxRemoveInput(int id) +{ + return dmxInputDetachId(id); +} + +/** Return the value of #dmxNumScreens -- the total number of backend + * screens in use (these are logical screens and may be larger than the + * number of backend displays). */ +unsigned long dmxGetNumScreens(void) +{ + return dmxNumScreens; +} + +/** Make sure that #dmxCreateAndRealizeWindow has been called for \a + * pWindow. */ +void dmxForceWindowCreation(WindowPtr pWindow) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + if (!pWinPriv->window) dmxCreateAndRealizeWindow(pWindow, TRUE); +} + +/** Flush pending syncs for all screens. */ +void dmxFlushPendingSyncs(void) +{ + dmxSync(NULL, TRUE); +} + +/** Update DMX's screen resources to match those of the newly moved + * and/or resized "root" window. */ +void dmxUpdateScreenResources(ScreenPtr pScreen, int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + WindowPtr pRoot = WindowTable[pScreen->myNum]; + WindowPtr pChild; + Bool anyMarked = FALSE; + + /* Handle special case where width and/or height are zero */ + if (w == 0 || h == 0) { + w = 1; + h = 1; + } + + /* Change screen size */ + pScreen->width = w; + pScreen->height = h; + + /* Reset the root window's drawable's size */ + pRoot->drawable.width = w; + pRoot->drawable.height = h; + + /* Set the root window's new winSize and borderSize */ + pRoot->winSize.extents.x1 = 0; + pRoot->winSize.extents.y1 = 0; + pRoot->winSize.extents.x2 = w; + pRoot->winSize.extents.y2 = h; + + pRoot->borderSize.extents.x1 = 0; + pRoot->borderSize.extents.y1 = 0; + pRoot->borderSize.extents.x2 = w; + pRoot->borderSize.extents.y2 = h; + + /* Recompute this screen's mmWidth & mmHeight */ + pScreen->mmWidth = + (w * 254 + dmxScreen->beXDPI * 5) / (dmxScreen->beXDPI * 10); + pScreen->mmHeight = + (h * 254 + dmxScreen->beYDPI * 5) / (dmxScreen->beYDPI * 10); + + /* Recompute this screen's window's clip rects as follows: */ + /* 1. Mark all of root's children's windows */ + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) + anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, + (WindowPtr *)NULL); + + /* 2. Set the root window's borderClip */ + pRoot->borderClip.extents.x1 = 0; + pRoot->borderClip.extents.y1 = 0; + pRoot->borderClip.extents.x2 = w; + pRoot->borderClip.extents.y2 = h; + + /* 3. Set the root window's clipList */ + if (anyMarked) { + /* If any windows have been marked, set the root window's + * clipList to be broken since it will be recalculated in + * ValidateTree() + */ + REGION_BREAK(pScreen, &pRoot->clipList); + } else { + /* Otherwise, we just set it directly since there are no + * windows visible on this screen + */ + pRoot->clipList.extents.x1 = 0; + pRoot->clipList.extents.y1 = 0; + pRoot->clipList.extents.x2 = w; + pRoot->clipList.extents.y2 = h; + } + + /* 4. Revalidate all clip rects and generate expose events */ + if (anyMarked) { + pScreen->ValidateTree(pRoot, NULL, VTBroken); + pScreen->HandleExposures(pRoot); + if (pScreen->PostValidateTree) + pScreen->PostValidateTree(pRoot, NULL, VTBroken); + } +} + +#ifdef PANORAMIX +#include "panoramiXsrv.h" + +/* Defined in dix/events.c */ +extern void ReinitializeRootWindow(WindowPtr win, int xoff, int yoff); + +/** Change the "screen" window attributes by resizing the actual window + * on the back-end display (if necessary). */ +static void dmxConfigureScreenWindow(int idx, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + ScreenPtr pScreen = screenInfo.screens[idx]; + + /* Resize "screen" window */ + if (dmxScreen->scrnX != x || + dmxScreen->scrnY != y || + dmxScreen->scrnWidth != w || + dmxScreen->scrnHeight != h) { + dmxResizeScreenWindow(pScreen, x, y, w, h); + } + + /* Change "screen" window values */ + dmxScreen->scrnX = x; + dmxScreen->scrnY = y; + dmxScreen->scrnWidth = w; + dmxScreen->scrnHeight = h; +} + +/** Change the "root" window position and size by resizing the actual + * window on the back-end display (if necessary) and updating all of + * DMX's resources by calling #dmxUpdateScreenResources. */ +static void dmxConfigureRootWindow(int idx, int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + WindowPtr pRoot = WindowTable[idx]; + + /* NOTE: Either this function or the ones that it calls must handle + * the case where w == 0 || h == 0. Currently, the functions that + * this one calls handle that case. */ + + /* 1. Resize "root" window */ + if (dmxScreen->rootX != x || + dmxScreen->rootY != y || + dmxScreen->rootWidth != w || + dmxScreen->rootHeight != h) { + dmxResizeRootWindow(pRoot, x, y, w, h); + } + + /* 2. Update all of the screen's resources associated with this root + * window */ + if (dmxScreen->rootWidth != w || + dmxScreen->rootHeight != h) { + dmxUpdateScreenResources(screenInfo.screens[idx], x, y, w, h); + } + + /* Change "root" window values */ + dmxScreen->rootX = x; + dmxScreen->rootY = y; + dmxScreen->rootWidth = w; + dmxScreen->rootHeight = h; +} + +/** Change the "root" window's origin by updating DMX's internal data + * structures (dix and Xinerama) to use the new origin and adjust the + * positions of windows that overlap this "root" window. */ +static void dmxSetRootWindowOrigin(int idx, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + ScreenPtr pScreen = screenInfo.screens[idx]; + WindowPtr pRoot = WindowTable[idx]; + WindowPtr pChild; + int xoff; + int yoff; + + /* Change "root" window's origin */ + dmxScreen->rootXOrigin = x; + dmxScreen->rootYOrigin = y; + + /* Compute offsets here in case <x,y> has been changed above */ + xoff = x - dixScreenOrigins[idx].x; + yoff = y - dixScreenOrigins[idx].y; + + /* Adjust the root window's position in dixScreenOrigins */ + dixScreenOrigins[idx].x = dmxScreen->rootXOrigin; + dixScreenOrigins[idx].y = dmxScreen->rootYOrigin; + + /* Recalculate the Xinerama regions and data structs */ + XineramaReinitData(pScreen); + + /* Adjust each of the root window's children */ + if (!idx) ReinitializeRootWindow(WindowTable[0], xoff, yoff); + pChild = pRoot->firstChild; + while (pChild) { + /* Adjust child window's position */ + pScreen->MoveWindow(pChild, + pChild->origin.x - wBorderWidth(pChild) - xoff, + pChild->origin.y - wBorderWidth(pChild) - yoff, + pChild->nextSib, + VTMove); + + /* Note that the call to MoveWindow will eventually call + * dmxPositionWindow which will automatically create a + * window if it is now exposed on screen (for lazy window + * creation optimization) and it will properly set the + * offscreen flag. + */ + + pChild = pChild->nextSib; + } +} + +/** Configure the attributes of each "screen" and "root" window. */ +int dmxConfigureScreenWindows(int nscreens, + CARD32 *screens, + DMXScreenAttributesPtr attribs, + int *errorScreen) +{ + int i; + + for (i = 0; i < nscreens; i++) { + DMXScreenAttributesPtr attr = &attribs[i]; + int idx = screens[i]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + if (errorScreen) *errorScreen = i; + + if (!dmxScreen->beDisplay) return DMX_BAD_VALUE; + + /* Check for illegal values */ + if (idx < 0 || idx >= dmxNumScreens) return BadValue; + + /* The "screen" and "root" windows must have valid sizes */ + if (attr->screenWindowWidth <= 0 || attr->screenWindowHeight <= 0 || + attr->rootWindowWidth < 0 || attr->rootWindowHeight < 0) + return DMX_BAD_VALUE; + + /* The "screen" window must fit entirely within the BE display */ + if (attr->screenWindowXoffset < 0 || + attr->screenWindowYoffset < 0 || + attr->screenWindowXoffset + + attr->screenWindowWidth > (unsigned)dmxScreen->beWidth || + attr->screenWindowYoffset + + attr->screenWindowHeight > (unsigned)dmxScreen->beHeight) + return DMX_BAD_VALUE; + + /* The "root" window must fit entirely within the "screen" window */ + if (attr->rootWindowXoffset < 0 || + attr->rootWindowYoffset < 0 || + attr->rootWindowXoffset + + attr->rootWindowWidth > attr->screenWindowWidth || + attr->rootWindowYoffset + + attr->rootWindowHeight > attr->screenWindowHeight) + return DMX_BAD_VALUE; + + /* The "root" window must not expose unaddressable coordinates */ + if (attr->rootWindowXorigin < 0 || + attr->rootWindowYorigin < 0 || + attr->rootWindowXorigin + attr->rootWindowWidth > 32767 || + attr->rootWindowYorigin + attr->rootWindowHeight > 32767) + return DMX_BAD_VALUE; + + /* The "root" window must fit within the global bounding box */ + if (attr->rootWindowXorigin + + attr->rootWindowWidth > (unsigned)dmxGlobalWidth || + attr->rootWindowYorigin + + attr->rootWindowHeight > (unsigned)dmxGlobalHeight) + return DMX_BAD_VALUE; + + /* FIXME: Handle the rest of the illegal value checking */ + } + + /* No illegal values found */ + if (errorScreen) *errorScreen = 0; + + for (i = 0; i < nscreens; i++) { + DMXScreenAttributesPtr attr = &attribs[i]; + int idx = screens[i]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + dmxLog(dmxInfo, "Changing screen #%d attributes " + "from %dx%d+%d+%d %dx%d+%d+%d +%d+%d " + "to %dx%d+%d+%d %dx%d+%d+%d +%d+%d\n", + idx, + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, + attr->screenWindowWidth, attr->screenWindowHeight, + attr->screenWindowXoffset, attr->screenWindowYoffset, + attr->rootWindowWidth, attr->rootWindowHeight, + attr->rootWindowXoffset, attr->rootWindowYoffset, + attr->rootWindowXorigin, attr->rootWindowYorigin); + + /* Configure "screen" window */ + dmxConfigureScreenWindow(idx, + attr->screenWindowXoffset, + attr->screenWindowYoffset, + attr->screenWindowWidth, + attr->screenWindowHeight); + + /* Configure "root" window */ + dmxConfigureRootWindow(idx, + attr->rootWindowXoffset, + attr->rootWindowYoffset, + attr->rootWindowWidth, + attr->rootWindowHeight); + + + /* Set "root" window's origin */ + dmxSetRootWindowOrigin(idx, + attr->rootWindowXorigin, + attr->rootWindowYorigin); + } + + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + + return Success; +} + +/** Configure the attributes of the global desktop. */ +int dmxConfigureDesktop(DMXDesktopAttributesPtr attribs) +{ + if (attribs->width <= 0 || attribs->width >= 32767 || + attribs->height <= 0 || attribs->height >= 32767) + return DMX_BAD_VALUE; + + /* If the desktop is shrinking, adjust the "root" windows on each + * "screen" window to only show the visible desktop. Also, handle + * the special case where the desktop shrinks such that the it no + * longer overlaps an portion of a "screen" window. */ + if (attribs->width < dmxGlobalWidth || attribs->height < dmxGlobalHeight) { + int i; + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + if (dmxScreen->rootXOrigin + + dmxScreen->rootWidth > attribs->width || + dmxScreen->rootYOrigin + + dmxScreen->rootHeight > attribs->height) { + int w, h; + if ((w = attribs->width - dmxScreen->rootXOrigin) < 0) w = 0; + if ((h = attribs->height - dmxScreen->rootYOrigin) < 0) h = 0; + if (w > dmxScreen->scrnWidth) w = dmxScreen->scrnWidth; + if (h > dmxScreen->scrnHeight) h = dmxScreen->scrnHeight; + if (w > dmxScreen->rootWidth) w = dmxScreen->rootWidth; + if (h > dmxScreen->rootHeight) h = dmxScreen->rootHeight; + dmxConfigureRootWindow(i, + dmxScreen->rootX, + dmxScreen->rootY, + w, h); + } + } + } + + /* Set the global width/height */ + dmxSetWidthHeight(attribs->width, attribs->height); + + /* Handle shift[XY] changes */ + if (attribs->shiftX || attribs->shiftY) { + int i; + for (i = 0; i < dmxNumScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + WindowPtr pChild = WindowTable[i]->firstChild; + while (pChild) { + /* Adjust child window's position */ + pScreen->MoveWindow(pChild, + pChild->origin.x - wBorderWidth(pChild) + - attribs->shiftX, + pChild->origin.y - wBorderWidth(pChild) + - attribs->shiftY, + pChild->nextSib, + VTMove); + + /* Note that the call to MoveWindow will eventually call + * dmxPositionWindow which will automatically create a + * window if it is now exposed on screen (for lazy + * window creation optimization) and it will properly + * set the offscreen flag. + */ + + pChild = pChild->nextSib; + } + } + } + + /* Update connection block, Xinerama, etc. -- these appears to + * already be handled in dmxConnectionBlockCallback(), which is + * called from dmxAdjustCursorBoundaries() [below]. */ + + /* Adjust the cursor boundaries */ + dmxAdjustCursorBoundaries(); + + /* Force completion of the changes */ + dmxSync(NULL, TRUE); + + return Success; +} +#endif + +/** Create the scratch GCs per depth. */ +static void dmxBECreateScratchGCs(int scrnNum) +{ + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + GCPtr *ppGC = pScreen->GCperDepth; + int i; + + for (i = 0; i <= pScreen->numDepths; i++) + dmxBECreateGC(pScreen, ppGC[i]); +} + +#ifdef PANORAMIX +static Bool FoundPixImage; + +/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs + * to have its image restored. When it is found, see if there is + * another screen with the same image. If so, copy the pixmap image + * from the existing screen to the newly created pixmap. */ +static void dmxBERestorePixmapImage(pointer value, XID id, RESTYPE type, + pointer p) +{ + if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPix = (PanoramiXRes *)value; + PixmapPtr pPix; + int i; + + pPix = (PixmapPtr)LookupIDByType(pXinPix->info[idx].id, RT_PIXMAP); + if (pPix != pDst) return; /* Not a match.... Next! */ + + for (i = 0; i < PanoramiXNumScreens; i++) { + PixmapPtr pSrc; + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + pSrc = + (PixmapPtr)LookupIDByType(pXinPix->info[i].id, RT_PIXMAP); + pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); + if (pSrcPriv->pixmap) { + DMXScreenInfo *dmxSrcScreen = &dmxScreens[i]; + DMXScreenInfo *dmxDstScreen = &dmxScreens[idx]; + dmxPixPrivPtr pDstPriv = DMX_GET_PIXMAP_PRIV(pDst); + XImage *img; + int j; + XlibGC gc = NULL; + + /* This should never happen, but just in case.... */ + if (pSrc->drawable.width != pDst->drawable.width || + pSrc->drawable.height != pDst->drawable.height) + return; + + /* Copy from src pixmap to dst pixmap */ + img = XGetImage(dmxSrcScreen->beDisplay, + pSrcPriv->pixmap, + 0, 0, + pSrc->drawable.width, pSrc->drawable.height, + -1, + ZPixmap); + + for (j = 0; j < dmxDstScreen->beNumPixmapFormats; j++) { + if (dmxDstScreen->bePixmapFormats[j].depth == img->depth) { + unsigned long m; + XGCValues v; + + m = GCFunction | GCPlaneMask | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.clip_mask = None; + + gc = XCreateGC(dmxDstScreen->beDisplay, + dmxDstScreen->scrnDefDrawables[j], + m, &v); + break; + } + } + + if (gc) { + XPutImage(dmxDstScreen->beDisplay, + pDstPriv->pixmap, + gc, img, 0, 0, 0, 0, + pDst->drawable.width, pDst->drawable.height); + XFreeGC(dmxDstScreen->beDisplay, gc); + FoundPixImage = True; + } else { + dmxLog(dmxWarning, "Could not create GC\n"); + } + + XDestroyImage(img); + return; + } + } + } +} +#endif + +/** Restore the pixmap image either from another screen or from an image + * that was saved when the screen was previously detached. */ +static void dmxBERestorePixmap(PixmapPtr pPixmap) +{ +#ifdef PANORAMIX + int i; + + /* If Xinerama is not active, there's nothing we can do (see comment + * in #else below for more info). */ + if (noPanoramiXExtension) { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + return; + } + + FoundPixImage = False; + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBERestorePixmapImage, + (pointer)pPixmap); + + /* No corresponding pixmap image was found on other screens, so we + * need to copy it from the saved image when the screen was detached + * (if available). */ + if (!FoundPixImage) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (pPixPriv->detachedImage) { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + XlibGC gc = NULL; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (dmxScreen->bePixmapFormats[i].depth == + pPixPriv->detachedImage->depth) { + unsigned long m; + XGCValues v; + + m = GCFunction | GCPlaneMask | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.clip_mask = None; + + gc = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i], + m, &v); + break; + } + } + + if (gc) { + XPutImage(dmxScreen->beDisplay, + pPixPriv->pixmap, + gc, + pPixPriv->detachedImage, + 0, 0, 0, 0, + pPixmap->drawable.width, pPixmap->drawable.height); + XFreeGC(dmxScreen->beDisplay, gc); + } else { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + } + + XDestroyImage(pPixPriv->detachedImage); + pPixPriv->detachedImage = NULL; + } else { + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + } + } +#else + /* If Xinerama is not enabled, then there is no other copy of the + * pixmap image that we can restore. Saving all pixmap data is not + * a feasible option since there is no mechanism for updating pixmap + * data when a screen is detached, which means that the data that + * was previously saved would most likely be out of date. */ + dmxLog(dmxWarning, "Cannot restore pixmap image\n"); + return; +#endif +} + +/** Create resources on the back-end server. This function is called + * from #dmxAttachScreen() via the dix layer's FindAllResources + * function. It walks all resources, compares them to the screen + * number passed in as \a n and calls the appropriate DMX function to + * create the associated resource on the back-end server. */ +static void dmxBECreateResources(pointer value, XID id, RESTYPE type, + pointer n) +{ + int scrnNum = (int)n; + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + + if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { + /* Window resources are created below in dmxBECreateWindowTree */ + } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { + PixmapPtr pPix = value; + if (pPix->drawable.pScreen->myNum == scrnNum) { + dmxBECreatePixmap(pPix); + dmxBERestorePixmap(pPix); + } + } else if ((type & TypeMask) == (RT_GC & TypeMask)) { + GCPtr pGC = value; + if (pGC->pScreen->myNum == scrnNum) { + /* Create the GC on the back-end server */ + dmxBECreateGC(pScreen, pGC); + /* Create any pixmaps associated with this GC */ + if (!pGC->tileIsPixel) { + dmxBECreatePixmap(pGC->tile.pixmap); + dmxBERestorePixmap(pGC->tile.pixmap); + } + if (pGC->stipple != pScreen->PixmapPerDepth[0]) { + dmxBECreatePixmap(pGC->stipple); + dmxBERestorePixmap(pGC->stipple); + } + if (pGC->font != defaultFont) { + (void)dmxBELoadFont(pScreen, pGC->font); + } + /* Update the GC on the back-end server */ + dmxChangeGC(pGC, -1L); + } + } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { + (void)dmxBELoadFont(pScreen, (FontPtr)value); + } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { + dmxBECreateCursor(pScreen, (CursorPtr)value); + } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { + ColormapPtr pCmap = value; + if (pCmap->pScreen->myNum == scrnNum) + (void)dmxBECreateColormap((ColormapPtr)value); +#if 0 +#ifdef RENDER + /* TODO: Recreate Picture and GlyphSet resources */ + } else if ((type & TypeMask) == (PictureType & TypeMask)) { + /* Picture resources are created when windows are created */ + } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { + dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); +#endif +#endif + } else { + /* Other resource types??? */ + } +} + +/** Create window hierachy on back-end server. The window tree is + * created in a special order (bottom most subwindow first) so that the + * #dmxCreateNonRootWindow() function does not need to recursively call + * itself to create each window's parents. This is required so that we + * have the opportunity to create each window's border and background + * pixmaps (where appropriate) before the window is created. */ +static void dmxBECreateWindowTree(int idx) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + WindowPtr pRoot = WindowTable[idx]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); + WindowPtr pWin; + + /* Create the pixmaps associated with the root window */ + if (!pRoot->borderIsPixel) { + dmxBECreatePixmap(pRoot->border.pixmap); + dmxBERestorePixmap(pRoot->border.pixmap); + } + if (pRoot->backgroundState == BackgroundPixmap) { + dmxBECreatePixmap(pRoot->background.pixmap); + dmxBERestorePixmap(pRoot->background.pixmap); + } + + /* Create root window first */ + dmxScreen->rootWin = pWinPriv->window = dmxCreateRootWindow(pRoot); + XMapWindow(dmxScreen->beDisplay, dmxScreen->rootWin); + + pWin = pRoot->lastChild; + while (pWin) { + pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + + /* Create the pixmaps regardless of whether or not the + * window is created or not due to lazy window creation. + */ + if (!pWin->borderIsPixel) { + dmxBECreatePixmap(pWin->border.pixmap); + dmxBERestorePixmap(pWin->border.pixmap); + } + if (pWin->backgroundState == BackgroundPixmap) { + dmxBECreatePixmap(pWin->background.pixmap); + dmxBERestorePixmap(pWin->background.pixmap); + } + + /* Reset the window attributes */ + dmxGetDefaultWindowAttributes(pWin, + &pWinPriv->cmap, + &pWinPriv->visual); + + /* Create the window */ + if (pWinPriv->mapped && !pWinPriv->offscreen) + dmxCreateAndRealizeWindow(pWin, TRUE); + + /* Next, create the bottom-most child */ + if (pWin->lastChild) { + pWin = pWin->lastChild; + continue; + } + + /* If the window has no children, move on to the next higher window */ + while (!pWin->prevSib && (pWin != pRoot)) + pWin = pWin->parent; + + if (pWin->prevSib) { + pWin = pWin->prevSib; + continue; + } + + /* When we reach the root window, we are finished */ + if (pWin == pRoot) + break; + } +} + +/* Refresh screen by generating exposure events for all windows */ +static void dmxForceExposures(int idx) +{ + ScreenPtr pScreen = screenInfo.screens[idx]; + WindowPtr pRoot = WindowTable[idx]; + Bool anyMarked = FALSE; + WindowPtr pChild; + + for (pChild = pRoot->firstChild; pChild; pChild = pChild->nextSib) + anyMarked |= pScreen->MarkOverlappedWindows(pChild, pChild, + (WindowPtr *)NULL); + if (anyMarked) { + /* If any windows have been marked, set the root window's + * clipList to be broken since it will be recalculated in + * ValidateTree() + */ + REGION_BREAK(pScreen, &pRoot->clipList); + pScreen->ValidateTree(pRoot, NULL, VTBroken); + pScreen->HandleExposures(pRoot); + if (pScreen->PostValidateTree) + pScreen->PostValidateTree(pRoot, NULL, VTBroken); + } +} + +/** Compare the new and old screens to see if they are compatible. */ +static Bool dmxCompareScreens(DMXScreenInfo *new, DMXScreenInfo *old) +{ + int i; + + if (new->beWidth != old->beWidth) return FALSE; + if (new->beHeight != old->beHeight) return FALSE; + if (new->beDepth != old->beDepth) return FALSE; + if (new->beBPP != old->beBPP) return FALSE; + + if (new->beNumDepths != old->beNumDepths) return FALSE; + for (i = 0; i < old->beNumDepths; i++) + if (new->beDepths[i] != old->beDepths[i]) return FALSE; + + if (new->beNumPixmapFormats != old->beNumPixmapFormats) return FALSE; + for (i = 0; i < old->beNumPixmapFormats; i++) { + if (new->bePixmapFormats[i].depth != + old->bePixmapFormats[i].depth) return FALSE; + if (new->bePixmapFormats[i].bits_per_pixel != + old->bePixmapFormats[i].bits_per_pixel) return FALSE; + if (new->bePixmapFormats[i].scanline_pad != + old->bePixmapFormats[i].scanline_pad) return FALSE; + } + + if (new->beNumVisuals != old->beNumVisuals) return FALSE; + for (i = 0; i < old->beNumVisuals; i++) { + if (new->beVisuals[i].visualid != + old->beVisuals[i].visualid) return FALSE; + if (new->beVisuals[i].screen != + old->beVisuals[i].screen) return FALSE; + if (new->beVisuals[i].depth != + old->beVisuals[i].depth) return FALSE; + if (new->beVisuals[i].class != + old->beVisuals[i].class) return FALSE; + if (new->beVisuals[i].red_mask != + old->beVisuals[i].red_mask) return FALSE; + if (new->beVisuals[i].green_mask != + old->beVisuals[i].green_mask) return FALSE; + if (new->beVisuals[i].blue_mask != + old->beVisuals[i].blue_mask) return FALSE; + if (new->beVisuals[i].colormap_size != + old->beVisuals[i].colormap_size) return FALSE; + if (new->beVisuals[i].bits_per_rgb != + old->beVisuals[i].bits_per_rgb) return FALSE; + } + + if (new->beDefVisualIndex != old->beDefVisualIndex) return FALSE; + + return TRUE; +} + +/** Reattach previously detached back-end screen. */ +int dmxAttachScreen(int idx, DMXScreenAttributesPtr attr) +{ + ScreenPtr pScreen = screenInfo.screens[idx]; + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + CARD32 scrnNum = idx; + DMXScreenInfo oldDMXScreen; + int i; + + /* Return failure if dynamic addition/removal of screens is disabled */ + if (!dmxAddRemoveScreens) { + dmxLog(dmxWarning, + "Attempting to add a screen, but the AddRemoveScreen\n"); + dmxLog(dmxWarning, + "extension has not been enabled. To enable this extension\n"); + dmxLog(dmxWarning, + "add the \"-addremovescreens\" option either to the command\n"); + dmxLog(dmxWarning, + "line or in the configuration file.\n"); + return 1; + } + + /* Cannot add a screen that does not exist */ + if (idx < 0 || idx >= dmxNumScreens) return 1; + + /* Cannot attach to a screen that is already opened */ + if (dmxScreen->beDisplay) { + dmxLog(dmxWarning, + "Attempting to add screen #%d but a screen already exists\n", + idx); + return 1; + } + + dmxLogOutput(dmxScreen, "Attaching screen #%d\n", idx); + + /* Save old info */ + oldDMXScreen = *dmxScreen; + + /* Copy the name to the new screen */ + dmxScreen->name = strdup(attr->displayName); + + /* Open display and get all of the screen info */ + if (!dmxOpenDisplay(dmxScreen)) { + dmxLog(dmxWarning, + "dmxOpenDisplay: Unable to open display %s\n", + dmxScreen->name); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + dmxSetErrorHandler(dmxScreen); + dmxCheckForWM(dmxScreen); + dmxGetScreenAttribs(dmxScreen); + + if (!dmxGetVisualInfo(dmxScreen)) { + dmxLog(dmxWarning, "dmxGetVisualInfo: No matching visuals found\n"); + XFree(dmxScreen->beVisuals); + XCloseDisplay(dmxScreen->beDisplay); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + dmxGetColormaps(dmxScreen); + dmxGetPixmapFormats(dmxScreen); + + /* Verify that the screen to be added has the same info as the + * previously added screen. */ + if (!dmxCompareScreens(dmxScreen, &oldDMXScreen)) { + dmxLog(dmxWarning, + "New screen data (%s) does not match previously\n", + dmxScreen->name); + dmxLog(dmxWarning, + "attached screen data (%s)\n", + oldDMXScreen.name); + dmxLog(dmxWarning, + "All data must match in order to attach to screen #%d\n", + idx); + XFree(dmxScreen->beVisuals); + XFree(dmxScreen->beDepths); + XFree(dmxScreen->bePixmapFormats); + XCloseDisplay(dmxScreen->beDisplay); + + /* Restore the old screen */ + *dmxScreen = oldDMXScreen; + return 1; + } + + /* Initialize the BE screen resources */ + dmxBEScreenInit(idx, screenInfo.screens[idx]); + + /* TODO: Handle GLX visual initialization. GLXProxy needs to be + * updated to handle dynamic addition/removal of screens. */ + + /* Create default stipple */ + dmxBECreatePixmap(pScreen->PixmapPerDepth[0]); + dmxBERestorePixmap(pScreen->PixmapPerDepth[0]); + + /* Create the scratch GCs */ + dmxBECreateScratchGCs(idx); + + /* Create the default font */ + (void)dmxBELoadFont(pScreen, defaultFont); + + /* Create all resources that don't depend on windows */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBECreateResources, + (pointer)idx); + + /* Create window hierarchy (top down) */ + dmxBECreateWindowTree(idx); + + /* Refresh screen by generating exposure events for all windows */ + dmxForceExposures(idx); + + dmxSync(&dmxScreens[idx], TRUE); + + /* We used these to compare the old and new screens. They are no + * longer needed since we have a newly attached screen, so we can + * now free the old screen's resources. */ + XFree(oldDMXScreen.beVisuals); + XFree(oldDMXScreen.beDepths); + XFree(oldDMXScreen.bePixmapFormats); + /* TODO: should oldDMXScreen.name be freed?? */ + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + return dmxConfigureScreenWindows(1, &scrnNum, attr, NULL); + else +#endif + return 0; /* Success */ +} + +/* + * Resources that may have state on the BE server and need to be freed: + * + * RT_NONE + * RT_WINDOW + * RT_PIXMAP + * RT_GC + * RT_FONT + * RT_CURSOR + * RT_COLORMAP + * RT_CMAPENTRY + * RT_OTHERCLIENT + * RT_PASSIVEGRAB + * XRT_WINDOW + * XRT_PIXMAP + * XRT_GC + * XRT_COLORMAP + * XRT_PICTURE + * PictureType + * PictFormatType + * GlyphSetType + * ClientType + * EventType + * RT_INPUTCLIENT + * XETrapType + * RTCounter + * RTAwait + * RTAlarmClient + * RT_XKBCLIENT + * RTContext + * TagResType + * StalledResType + * RT_APPGROUP + * SecurityAuthorizationResType + * RTEventClient + * __glXContextRes + * __glXClientRes + * __glXPixmapRes + * __glXWindowRes + * __glXPbufferRes + */ + +#ifdef PANORAMIX +/** Search the Xinerama XRT_PIXMAP resources for the pixmap that needs + * to have its image saved. */ +static void dmxBEFindPixmapImage(pointer value, XID id, RESTYPE type, + pointer p) +{ + if ((type & TypeMask) == (XRT_PIXMAP & TypeMask)) { + PixmapPtr pDst = (PixmapPtr)p; + int idx = pDst->drawable.pScreen->myNum; + PanoramiXRes *pXinPix = (PanoramiXRes *)value; + PixmapPtr pPix; + int i; + + pPix = (PixmapPtr)LookupIDByType(pXinPix->info[idx].id, RT_PIXMAP); + if (pPix != pDst) return; /* Not a match.... Next! */ + + for (i = 0; i < PanoramiXNumScreens; i++) { + PixmapPtr pSrc; + dmxPixPrivPtr pSrcPriv = NULL; + + if (i == idx) continue; /* Self replication is bad */ + + pSrc = + (PixmapPtr)LookupIDByType(pXinPix->info[i].id, RT_PIXMAP); + pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc); + if (pSrcPriv->pixmap) { + FoundPixImage = True; + return; + } + } + } +} +#endif + +/** Save the pixmap image only when there is not another screen with + * that pixmap from which the image can be read when the screen is + * reattached. To do this, we first try to find a pixmap on another + * screen corresponding to the one we are trying to save. If we find + * one, then we do not need to save the image data since during + * reattachment, the image data can be read from that other pixmap. + * However, if we do not find one, then we need to save the image data. + * The common case for these are for the default stipple and root + * tile. */ +static void dmxBESavePixmap(PixmapPtr pPixmap) +{ +#ifdef PANORAMIX + int i; + + /* If Xinerama is not active, there's nothing we can do (see comment + * in #else below for more info). */ + if (noPanoramiXExtension) return; + + FoundPixImage = False; + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBEFindPixmapImage, + (pointer)pPixmap); + + /* Save the image only if there is no other screens that have a + * pixmap that corresponds to the one we are trying to save. */ + if (!FoundPixImage) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (!pPixPriv->detachedImage) { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + pPixPriv->detachedImage = XGetImage(dmxScreen->beDisplay, + pPixPriv->pixmap, + 0, 0, + pPixmap->drawable.width, + pPixmap->drawable.height, + -1, + ZPixmap); + if (!pPixPriv->detachedImage) + dmxLog(dmxWarning, "Cannot save pixmap image\n"); + } + } +#else + /* NOTE: The only time there is a pixmap on another screen that + * corresponds to the one we are trying to save is when Xinerama is + * active. Otherwise, the pixmap image data is only stored on a + * single screen, which means that once it is detached, that data is + * lost. We could save the data here, but then that would require + * us to implement the ability for Xdmx to keep the pixmap up to + * date while the screen is detached, which is beyond the scope of + * the current project. */ + return; +#endif +} + +/** Destroy resources on the back-end server. This function is called + * from #dmxDetachScreen() via the dix layer's FindAllResources + * function. It walks all resources, compares them to the screen + * number passed in as \a n and calls the appropriate DMX function to + * free the associated resource on the back-end server. */ +static void dmxBEDestroyResources(pointer value, XID id, RESTYPE type, + pointer n) +{ + int scrnNum = (int)n; + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + + if ((type & TypeMask) == (RT_WINDOW & TypeMask)) { + /* Window resources are destroyed below in dmxBEDestroyWindowTree */ + } else if ((type & TypeMask) == (RT_PIXMAP & TypeMask)) { + PixmapPtr pPix = value; + if (pPix->drawable.pScreen->myNum == scrnNum) { + dmxBESavePixmap(pPix); + dmxBEFreePixmap(pPix); + } + } else if ((type & TypeMask) == (RT_GC & TypeMask)) { + GCPtr pGC = value; + if (pGC->pScreen->myNum == scrnNum) + dmxBEFreeGC(pGC); + } else if ((type & TypeMask) == (RT_FONT & TypeMask)) { + dmxBEFreeFont(pScreen, (FontPtr)value); + } else if ((type & TypeMask) == (RT_CURSOR & TypeMask)) { + dmxBEFreeCursor(pScreen, (CursorPtr)value); + } else if ((type & TypeMask) == (RT_COLORMAP & TypeMask)) { + ColormapPtr pCmap = value; + if (pCmap->pScreen->myNum == scrnNum) + dmxBEFreeColormap((ColormapPtr)value); +#ifdef RENDER + } else if ((type & TypeMask) == (PictureType & TypeMask)) { + PicturePtr pPict = value; + if (pPict->pDrawable->pScreen->myNum == scrnNum) + dmxBEFreePicture((PicturePtr)value); + } else if ((type & TypeMask) == (GlyphSetType & TypeMask)) { + dmxBEFreeGlyphSet(pScreen, (GlyphSetPtr)value); +#endif + } else { + /* Other resource types??? */ + } +} + +/** Destroy the scratch GCs that are created per depth. */ +static void dmxBEDestroyScratchGCs(int scrnNum) +{ + ScreenPtr pScreen = screenInfo.screens[scrnNum]; + GCPtr *ppGC = pScreen->GCperDepth; + int i; + + for (i = 0; i <= pScreen->numDepths; i++) + dmxBEFreeGC(ppGC[i]); +} + +/** Destroy window hierachy on back-end server. To ensure that all + * XDestroyWindow() calls succeed, they must be performed in a bottom + * up order so that windows are not destroyed before their children. + * XDestroyWindow(), which is called from #dmxBEDestrowWindow(), will + * destroy a window as well as all of it's children. */ +static void dmxBEDestroyWindowTree(int idx) +{ + WindowPtr pWin = WindowTable[idx]; + WindowPtr pChild = pWin; + + while (1) { + if (pChild->firstChild) { + pChild = pChild->firstChild; + continue; + } + + /* Destroy the window */ + dmxBEDestroyWindow(pChild); + + /* Make sure we destroy the window's border and background + * pixmaps if they exist */ + if (!pChild->borderIsPixel) { + dmxBESavePixmap(pChild->border.pixmap); + dmxBEFreePixmap(pChild->border.pixmap); + } + if (pChild->backgroundState == BackgroundPixmap) { + dmxBESavePixmap(pChild->background.pixmap); + dmxBEFreePixmap(pChild->background.pixmap); + } + + while (!pChild->nextSib && (pChild != pWin)) { + pChild = pChild->parent; + dmxBEDestroyWindow(pChild); + if (!pChild->borderIsPixel) { + dmxBESavePixmap(pChild->border.pixmap); + dmxBEFreePixmap(pChild->border.pixmap); + } + if (pChild->backgroundState == BackgroundPixmap) { + dmxBESavePixmap(pChild->background.pixmap); + dmxBEFreePixmap(pChild->background.pixmap); + } + } + + if (pChild == pWin) + break; + + pChild = pChild->nextSib; + } +} + +/** Detach back-end screen. */ +int dmxDetachScreen(int idx) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + int i; + + /* Return failure if dynamic addition/removal of screens is disabled */ + if (!dmxAddRemoveScreens) { + dmxLog(dmxWarning, + "Attempting to remove a screen, but the AddRemoveScreen\n"); + dmxLog(dmxWarning, + "extension has not been enabled. To enable this extension\n"); + dmxLog(dmxWarning, + "add the \"-addremovescreens\" option either to the command\n"); + dmxLog(dmxWarning, + "line or in the configuration file.\n"); + return 1; + } + + /* Cannot remove a screen that does not exist */ + if (idx < 0 || idx >= dmxNumScreens) return 1; + + /* Cannot detach from a screen that is not opened */ + if (!dmxScreen->beDisplay) { + dmxLog(dmxWarning, + "Attempting to remove screen #%d but it has not been opened\n", + idx); + return 1; + } + + dmxLogOutput(dmxScreen, "Detaching screen #%d\n", idx); + + /* Detach input */ + dmxInputDetachAll(dmxScreen); + + /* Save all relevant state (TODO) */ + + /* Free all non-window resources related to this screen */ + for (i = currentMaxClients; --i >= 0; ) + if (clients[i]) + FindAllClientResources(clients[i], dmxBEDestroyResources, + (pointer)idx); + + /* Free scratch GCs */ + dmxBEDestroyScratchGCs(idx); + + /* Free window resources related to this screen */ + dmxBEDestroyWindowTree(idx); + + /* Free default stipple */ + dmxBESavePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); + dmxBEFreePixmap(screenInfo.screens[idx]->PixmapPerDepth[0]); + + /* Free the remaining screen resources and close the screen */ + dmxBECloseScreen(screenInfo.screens[idx]); + + /* Adjust the cursor boundaries (paints detached console window) */ + dmxAdjustCursorBoundaries(); + + return 0; /* Success */ +} |