/* * Copyright © 2008 Novell, Inc. * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of * Novell, Inc. not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior permission. * Novell, Inc. makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: David Reveman */ #ifdef HAVE_DMX_CONFIG_H #include #endif #ifdef RANDR #include "dmx.h" #include "dmxlog.h" #include "dmxextension.h" #include "dmxcb.h" #include "dmxrandr.h" #include "dmxclient.h" #include "dmxatom.h" #include "dmxwindow.h" #ifdef PANORAMIX #include "panoramiX.h" #include "panoramiXsrv.h" #endif #include static int xRROutputsForFirstScreen = 1; static int xRRCrtcsForFirstScreen = 1; static DMXScreenInfo * dmxRRGetScreenForCrtc (ScreenPtr pScreen, RRCrtcPtr crtc) { int i; rrScrPriv (pScreen); for (i = 0; i < pScrPriv->numCrtcs; i++) if (pScrPriv->crtcs[i] == crtc) break; if (i == pScrPriv->numCrtcs) return NULL; if (i < xRRCrtcsForFirstScreen) return dmxScreens; return &dmxScreens[((i - xRRCrtcsForFirstScreen) / xRRCrtcsPerScreen) + 1]; } static DMXScreenInfo * dmxRRGetScreenForOutput (ScreenPtr pScreen, RROutputPtr output) { int i; rrScrPriv (pScreen); for (i = 0; i < pScrPriv->numOutputs; i++) if (pScrPriv->outputs[i] == output) break; if (i == pScrPriv->numOutputs) return NULL; if (i < xRROutputsForFirstScreen) return dmxScreens; return &dmxScreens[((i - xRROutputsForFirstScreen) / xRROutputsPerScreen) + 1]; } static RRModePtr dmxRRGetMode (XRRScreenResources *r, unsigned long mode) { xRRModeInfo modeInfo; int i; for (i = 0; i < r->nmode; i++) { if (r->modes[i].id == mode) { memset (&modeInfo, '\0', sizeof (modeInfo)); modeInfo.width = r->modes[i].width; modeInfo.height = r->modes[i].height; modeInfo.dotClock = r->modes[i].dotClock; modeInfo.hSyncStart = r->modes[i].hSyncStart; modeInfo.hSyncEnd = r->modes[i].hSyncEnd; modeInfo.hTotal = r->modes[i].hTotal; modeInfo.hSkew = r->modes[i].hSkew; modeInfo.vSyncStart = r->modes[i].vSyncStart; modeInfo.vSyncEnd = r->modes[i].vSyncEnd; modeInfo.vTotal = r->modes[i].vTotal; modeInfo.nameLength = strlen (r->modes[i].name); modeInfo.modeFlags = r->modes[i].modeFlags; return RRModeGet (&modeInfo, r->modes[i].name); } } return NULL; } static RRCrtcPtr dmxRRGetCrtc (ScreenPtr pScreen, DMXScreenInfo *dmxScreen, unsigned long crtc) { int baseCrtc = 0; int numCrtc = xRRCrtcsForFirstScreen; int i; rrScrPriv (pScreen); if (!crtc) return NULL; if (dmxScreen != dmxScreens) { baseCrtc = xRRCrtcsForFirstScreen + ((dmxScreen - dmxScreens) - 1) * xRRCrtcsPerScreen; numCrtc = xRRCrtcsPerScreen; } for (i = 0; i < numCrtc; i++) if (pScrPriv->crtcs[baseCrtc + i]->devPrivate == (void *) crtc) return pScrPriv->crtcs[baseCrtc + i]; return NULL; } static RROutputPtr dmxRRGetOutput (ScreenPtr pScreen, DMXScreenInfo *dmxScreen, unsigned long output) { int baseOutput = 0; int numOutput = xRROutputsForFirstScreen; int i; rrScrPriv (pScreen); if (!output) return NULL; if (dmxScreen != dmxScreens) { baseOutput = xRROutputsForFirstScreen + ((dmxScreen - dmxScreens) - 1) * xRROutputsPerScreen; numOutput = xRROutputsPerScreen; } for (i = 0; i < numOutput; i++) if (pScrPriv->outputs[baseOutput + i]->devPrivate == (void *) output) return pScrPriv->outputs[baseOutput + i]; return NULL; } static Bool dmxRRUpdateCrtc (ScreenPtr pScreen, DMXScreenInfo *dmxScreen, XRRScreenResources *r, unsigned long xcrtc) { XRRCrtcInfo *c = NULL; RRCrtcPtr crtc; RRModePtr mode = NULL; RROutputPtr *outputs = NULL; XRRCrtcGamma *gamma = NULL; int i, noutput = 0; crtc = dmxRRGetCrtc (pScreen, dmxScreen, xcrtc); if (!crtc) return TRUE; /* do nothing if the crtc doesn't exist */ XLIB_PROLOGUE (dmxScreen); c = XRRGetCrtcInfo (dmxScreen->beDisplay, r, xcrtc); XLIB_EPILOGUE (dmxScreen); if (!c) return FALSE; if (c->noutput) { outputs = xalloc (sizeof (RROutputPtr) * c->noutput); if (!outputs) return FALSE; } if (c->mode) mode = dmxRRGetMode (r, c->mode); for (i = 0; i < c->noutput; i++) { outputs[noutput] = dmxRRGetOutput (pScreen, dmxScreen, c->outputs[i]); if (outputs[noutput]) noutput++; } XLIB_PROLOGUE (dmxScreen); gamma = XRRGetCrtcGamma (dmxScreen->beDisplay, xcrtc); XLIB_EPILOGUE (dmxScreen); if (!gamma) return FALSE; RRCrtcGammaSet (crtc, gamma->red, gamma->green, gamma->blue); XRRFreeGamma (gamma); RRCrtcNotify (crtc, mode, c->x, c->y, c->rotation, noutput, outputs); if (outputs) xfree (outputs); XRRFreeCrtcInfo (c); return TRUE; } static Bool dmxRRUpdateOutput (ScreenPtr pScreen, DMXScreenInfo *dmxScreen, XRRScreenResources *r, unsigned long xoutput) { XRROutputInfo *o = NULL; RROutputPtr output, *clones = NULL; RRModePtr *modes = NULL; RRCrtcPtr *crtcs = NULL; int i, nclone = 0, ncrtc = 0; output = dmxRRGetOutput (pScreen, dmxScreen, xoutput); if (!output) return TRUE; /* do nothing if the output doesn't exist */ XLIB_PROLOGUE (dmxScreen); o = XRRGetOutputInfo (dmxScreen->beDisplay, r, xoutput); XLIB_EPILOGUE (dmxScreen); if (!o) return FALSE; if (o->nclone) { clones = xalloc (sizeof (RROutputPtr) * o->nclone); if (!clones) return FALSE; } if (o->nmode) { modes = xalloc (sizeof (RRModePtr) * o->nmode); if (!modes) return FALSE; } if (o->ncrtc) { crtcs = xalloc (sizeof (RRCrtcPtr) * o->ncrtc); if (!crtcs) return FALSE; } for (i = 0; i < o->nclone; i++) { clones[nclone] = dmxRRGetOutput (pScreen, dmxScreen, o->clones[i]); if (clones[nclone]) nclone++; } for (i = 0; i < o->ncrtc; i++) { crtcs[ncrtc] = dmxRRGetCrtc (pScreen, dmxScreen, o->crtcs[i]); if (crtcs[ncrtc]) ncrtc++; } for (i = 0; i < o->nmode; i++) { modes[i] = dmxRRGetMode (r, o->modes[i]); if (!modes[i]) return FALSE; } if (!RROutputSetClones (output, clones, nclone)) return FALSE; if (!RROutputSetModes (output, modes, o->nmode, o->npreferred)) return FALSE; if (!RROutputSetCrtcs (output, crtcs, ncrtc)) return FALSE; if (!RROutputSetConnection (output, o->connection)) return FALSE; if (!RROutputSetSubpixelOrder (output, o->subpixel_order)) return FALSE; if (!RROutputSetPhysicalSize (output, o->mm_width, o->mm_height)) return FALSE; if (clones) xfree (clones); if (modes) xfree (modes); if (crtcs) xfree (crtcs); XRRFreeOutputInfo (o); return TRUE; } static Bool dmxRRUpdateOutputProperty (ScreenPtr pScreen, DMXScreenInfo *dmxScreen, XRRScreenResources *r, unsigned long xoutput, unsigned long xproperty) { RROutputPtr output; XRRPropertyInfo *info = NULL; unsigned char *prop; int format, status = !Success; unsigned long nElements, bytesAfter; Atom type, atom; INT32 *values = NULL; output = dmxRRGetOutput (pScreen, dmxScreen, xoutput); if (!output) return TRUE; /* do nothing if the output doesn't exist */ atom = dmxAtom (dmxScreen, xproperty); XLIB_PROLOGUE (dmxScreen); status = XRRGetOutputProperty (dmxScreen->beDisplay, xoutput, xproperty, 0, 8192, FALSE, FALSE, AnyPropertyType, &type, &format, &nElements, &bytesAfter, &prop); XLIB_EPILOGUE (dmxScreen); if (status != Success) return FALSE; XLIB_PROLOGUE (dmxScreen); info = XRRQueryOutputProperty (dmxScreen->beDisplay, xoutput, xproperty); XLIB_EPILOGUE (dmxScreen); if (!info) return FALSE; if (info->num_values) { int i; values = xalloc (info->num_values * sizeof (INT32)); if (!values) return FALSE; for (i = 0; i < info->num_values; i++) values[i] = info->values[i]; } if (type == XA_ATOM && format == 32) { INT32 *atoms = (INT32 *) prop; int i; for (i = 0; i < nElements; i++) atoms[i] = dmxAtom (dmxScreen, atoms[i]); if (!info->range && info->num_values > 0) { for (i = 0; i < info->num_values; i++) values[i] = dmxAtom (dmxScreen, values[i]); } } RRConfigureOutputProperty (output, atom, FALSE, info->range, info->immutable, info->num_values, values); RRChangeOutputProperty (output, atom, type, format, PropModeReplace, nElements, prop, FALSE, TRUE); if (values) xfree (values); XFree (info); XFree (prop); return TRUE; } static Bool dmxRRGetInfo (ScreenPtr pScreen, Rotation *rotations) { int i; rrScrPriv (pScreen); if (pScreen->myNum) { *rotations = RR_Rotate_0; return TRUE; } for (i = 0; i < dmxNumScreens; i++) { DMXScreenInfo *dmxScreen = &dmxScreens[i]; XRRScreenResources *r = NULL; int outputsPerScreen = xRROutputsForFirstScreen; int baseOutput = 0; int crtcsPerScreen = xRRCrtcsForFirstScreen; int baseCrtc = 0; int j; if (i) { outputsPerScreen = xRROutputsPerScreen; baseOutput = xRROutputsForFirstScreen + (i - 1) * xRROutputsPerScreen; crtcsPerScreen = xRRCrtcsPerScreen; baseCrtc = xRRCrtcsForFirstScreen + (i - 1) * xRRCrtcsPerScreen; } assert (baseOutput + outputsPerScreen <= pScrPriv->numOutputs); assert (baseCrtc + crtcsPerScreen <= pScrPriv->numCrtcs); dmxScreen->beRandrPending = TRUE; if (dmxScreen->beRandr && dmxScreen->beDisplay) { XLIB_PROLOGUE (dmxScreen); r = XRRGetScreenResources (dmxScreen->beDisplay, dmxScreen->scrnWin); XLIB_EPILOGUE (dmxScreen); if (r) { if (r->noutput > outputsPerScreen) dmxLog (dmxWarning, "dmxRRGetInfo: ignoring %d BE server outputs\n", r->noutput - outputsPerScreen); if (r->ncrtc > crtcsPerScreen) dmxLog (dmxWarning, "dmxRRGetInfo: ignoring %d BE server crtcs\n", r->ncrtc - crtcsPerScreen); } } for (j = 0; j < outputsPerScreen; j++) { RROutputPtr output = pScrPriv->outputs[baseOutput + j]; if (r && j < r->noutput) output->devPrivate = (void *) r->outputs[j]; else output->devPrivate = NULL; } for (j = 0; j < crtcsPerScreen; j++) { RRCrtcPtr crtc = pScrPriv->crtcs[baseCrtc + j]; crtc->devPrivate = NULL; if (r && j < r->ncrtc) crtc->devPrivate = (void *) r->crtcs[j]; else crtc->devPrivate = NULL; } for (j = 0; j < outputsPerScreen; j++) { RROutputPtr output = pScrPriv->outputs[baseOutput + j]; if (r) { if (j < r->noutput) { #ifdef _XSERVER64 Atom64 *props = NULL; #else Atom *props = NULL; #endif int nProp = 0, k; if (!dmxRRUpdateOutput (pScreen, dmxScreen, r, r->outputs[j])) return (dmxScreen->beRandrPending = FALSE); XLIB_PROLOGUE (dmxScreen); props = XRRListOutputProperties (dmxScreen->beDisplay, r->outputs[j], &nProp); XLIB_EPILOGUE (dmxScreen); if (nProp) { for (k = 0; k < nProp; k++) if (!dmxRRUpdateOutputProperty (pScreen, dmxScreen, r, r->outputs[j], props[k])) return (dmxScreen->beRandrPending = FALSE); XFree (props); } } else { if (!RROutputSetModes (output, NULL, 0, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetClones (output, NULL, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetCrtcs (output, NULL, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetConnection (output, RR_Disconnected)) return (dmxScreen->beRandrPending = FALSE); } } else if (dmxScreen->beDisplay && j == 0) { RRModePtr mode; xRRModeInfo modeInfo; char name[64]; sprintf (name, "%dx%d", dmxScreen->scrnWidth, dmxScreen->scrnHeight); memset (&modeInfo, '\0', sizeof (modeInfo)); modeInfo.width = dmxScreen->scrnWidth; modeInfo.height = dmxScreen->scrnHeight; modeInfo.nameLength = strlen (name); mode = RRModeGet (&modeInfo, name); if (!mode) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetModes (output, &mode, 1, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetClones (output, NULL, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetCrtcs (output, &pScrPriv->crtcs[baseCrtc], 1)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetConnection (output, RR_Connected)) return (dmxScreen->beRandrPending = FALSE); } else { if (!RROutputSetModes (output, NULL, 0, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetClones (output, NULL, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetCrtcs (output, NULL, 0)) return (dmxScreen->beRandrPending = FALSE); if (!RROutputSetConnection (output, RR_Disconnected)) return FALSE; } } for (j = 0; j < crtcsPerScreen; j++) { RRCrtcPtr crtc = pScrPriv->crtcs[baseCrtc + j]; if (r) { if (j < r->ncrtc) { if (!dmxRRUpdateCrtc (pScreen, dmxScreen, r, r->crtcs[j])) return (dmxScreen->beRandrPending = FALSE); } else { RRCrtcNotify (crtc, NULL, 0, 0, RR_Rotate_0, 0, NULL); } } else if (dmxScreen->beDisplay && j == 0) { RRModePtr mode; xRRModeInfo modeInfo; char name[64]; sprintf (name, "%dx%d", dmxScreen->scrnWidth, dmxScreen->scrnHeight); memset (&modeInfo, '\0', sizeof (modeInfo)); modeInfo.width = dmxScreen->scrnWidth; modeInfo.height = dmxScreen->scrnHeight; modeInfo.nameLength = strlen (name); mode = RRModeGet (&modeInfo, name); if (!mode) return (dmxScreen->beRandrPending = FALSE); RRCrtcNotify (crtc, mode, dmxScreen->rootX, dmxScreen->rootY, RR_Rotate_0, 1, &pScrPriv->outputs[baseOutput]); } else { RRCrtcNotify (crtc, NULL, 0, 0, RR_Rotate_0, 0, NULL); } } if (r) XRRFreeScreenResources (r); dmxScreen->beRandrPending = FALSE; } *rotations = RR_Rotate_0; for (i = 0; i < pScrPriv->numCrtcs; i++) *rotations |= pScrPriv->crtcs[i]->rotations; return TRUE; } static unsigned long dmxRRGetXMode (XRRScreenResources *r, RRModePtr mode) { xRRModeInfo modeInfo = mode->mode; int i; for (i = 0; i < r->nmode; i++) { if (modeInfo.width == r->modes[i].width && modeInfo.height == r->modes[i].height && modeInfo.dotClock == r->modes[i].dotClock && modeInfo.hSyncStart == r->modes[i].hSyncStart && modeInfo.hSyncEnd == r->modes[i].hSyncEnd && modeInfo.hTotal == r->modes[i].hTotal && modeInfo.hSkew == r->modes[i].hSkew && modeInfo.vSyncStart == r->modes[i].vSyncStart && modeInfo.vSyncEnd == r->modes[i].vSyncEnd && modeInfo.vTotal == r->modes[i].vTotal && modeInfo.nameLength == r->modes[i].nameLength && modeInfo.modeFlags == r->modes[i].modeFlags) { if (!memcmp (r->modes[i].name, mode->name, modeInfo.nameLength)) return r->modes[i].id; } } return None; } static Bool dmxRRScreenSetSize (ScreenPtr pScreen, CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight) { #ifdef PANORAMIX if (!noPanoramiXExtension) { int i; for (i = 0; i < dmxNumScreens; i++) dmxResizeRootWindow (WindowTable[i], 0, 0, width, height); for (i = 0; i < dmxNumScreens; i++) dmxUpdateScreenResources (screenInfo.screens[i], 0, 0, width, height); dmxSetWidthHeight (width, height); dmxConnectionBlockCallback (); } else #endif { dmxResizeRootWindow (WindowTable[pScreen->myNum], 0, 0, width, height); dmxUpdateScreenResources (pScreen, 0, 0, width, height); } pScreen->mmWidth = mmWidth; pScreen->mmHeight = mmHeight; RRScreenSizeNotify (pScreen); return TRUE; } static Bool dmxRRCrtcSet (ScreenPtr pScreen, RRCrtcPtr crtc, RRModePtr mode, int x, int y, Rotation rotation, int numOutputs, RROutputPtr *outputs) { XRRScreenResources *r = NULL; #ifdef _XSERVER64 RROutput64 *o = NULL; #else RROutput *o = NULL; #endif RRMode m = None; Status status = !RRSetConfigSuccess; int i; DMXScreenInfo *dmxScreen; dmxScreen = dmxRRGetScreenForCrtc (pScreen, crtc); if (!dmxScreen) return FALSE; if (dmxScreen->beRandrPending) return RRCrtcNotify (crtc, mode, x, y, rotation, numOutputs, outputs); for (i = 0; i < numOutputs; i++) if (!dmxRRGetOutput (pScreen, dmxScreen, (unsigned long) outputs[i]->devPrivate)) return FALSE; if (numOutputs) { o = xalloc (sizeof (*o) * numOutputs); if (!o) return FALSE; } XLIB_PROLOGUE (dmxScreen); r = XRRGetScreenResources (dmxScreen->beDisplay, DefaultRootWindow (dmxScreen->beDisplay)); XLIB_EPILOGUE (dmxScreen); if (!r) return FALSE; if (mode) { m = dmxRRGetXMode (r, mode); if (!m) { XRRFreeScreenResources (r); if (o) xfree (o); return FALSE; } } for (i = 0; i < numOutputs; i++) o[i] = (unsigned long) outputs[i]->devPrivate; XLIB_PROLOGUE (dmxScreen); status = XRRSetCrtcConfig (dmxScreen->beDisplay, r, (unsigned long) crtc->devPrivate, CurrentTime, x, y, m, rotation, o, numOutputs); XLIB_EPILOGUE (dmxScreen); XRRFreeScreenResources (r); if (o) xfree (o); if (status != RRSetConfigSuccess) return FALSE; return RRCrtcNotify (crtc, mode, x, y, rotation, numOutputs, outputs); } static Bool dmxRRCrtcSetGamma (ScreenPtr pScreen, RRCrtcPtr crtc) { XRRCrtcGamma *gamma; DMXScreenInfo *dmxScreen; dmxScreen = dmxRRGetScreenForCrtc (pScreen, crtc); if (!dmxScreen) return FALSE; if (dmxScreen->beRandrPending) return TRUE; gamma = XRRAllocGamma (crtc->gammaSize); if (!gamma) return FALSE; memcpy (gamma->red, crtc->gammaRed, gamma->size * sizeof (CARD16)); memcpy (gamma->green, crtc->gammaGreen, gamma->size * sizeof (CARD16)); memcpy (gamma->blue, crtc->gammaBlue, gamma->size * sizeof (CARD16)); XLIB_PROLOGUE (dmxScreen); XRRSetCrtcGamma (dmxScreen->beDisplay, (unsigned long) crtc->devPrivate, gamma); XLIB_EPILOGUE (dmxScreen); XRRFreeGamma (gamma); return TRUE; } static Bool dmxRROutputSetProperty (ScreenPtr pScreen, RROutputPtr output, Atom property, RRPropertyValuePtr value) { RRPropertyPtr p; #ifdef _XSERVER64 Atom64 atom = 0, type = 0; #else Atom atom = 0, type = 0; #endif long *values = value->data; long *validValues; int i; DMXScreenInfo *dmxScreen; dmxScreen = dmxRRGetScreenForOutput (pScreen, output); if (!dmxScreen) return FALSE; if (dmxScreen->beRandrPending) return TRUE; p = RRQueryOutputProperty (output, property); if (!p) return FALSE; validValues = p->valid_values; atom = dmxBEAtom (dmxScreen, property); type = dmxBEAtom (dmxScreen, value->type); if (type == XA_ATOM && value->format == 32) { INT32 *atoms = (INT32 *) value->data; for (i = 0; i < value->size; i++) if (!ValidAtom (atoms[i])) return FALSE; if (p->num_valid > 0) { for (i = 0; i < p->num_valid; i++) if (!ValidAtom (p->valid_values[i])) return FALSE; for (i = 0; i < value->size; i++) { int j; for (j = 0; j < p->num_valid; j++) if (p->valid_values[j] == atoms[i]) break; if (j == p->num_valid) return FALSE; } validValues = xalloc (p->num_valid * sizeof (long)); if (!validValues) return FALSE; for (i = 0; i < p->num_valid; i++) validValues[i] = dmxBEAtom (dmxScreen, p->valid_values[i]); } if (value->size) { int size = value->size * (value->format / 8); values = xalloc (size); if (!values) return FALSE; for (i = 0; i < value->size; i++) values[i] = dmxBEAtom (dmxScreen, atoms[i]); } } else { if (p->num_valid > 0) { validValues = xalloc (p->num_valid * sizeof (long)); if (!validValues) return FALSE; for (i = 0; i < p->num_valid; i++) validValues[i] = p->valid_values[i]; } } XLIB_PROLOGUE (dmxScreen); XRRConfigureOutputProperty (dmxScreen->beDisplay, (unsigned long) output->devPrivate, atom, p->is_pending, p->range, p->num_valid, validValues); XRRChangeOutputProperty (dmxScreen->beDisplay, (unsigned long) output->devPrivate, atom, type, value->format, PropModeReplace, (unsigned char *) values, value->size); XLIB_EPILOGUE (dmxScreen); if (validValues != p->valid_values) xfree (validValues); if (values != value->data) xfree (values); return TRUE; } static Bool dmxRROutputValidateMode (ScreenPtr pScreen, RROutputPtr output, RRModePtr mode) { XRRModeInfo *modeInfo; #ifdef _XSERVER64 RRMode64 m = 0; #else RRMode m = 0; #endif DMXScreenInfo *dmxScreen; dmxScreen = dmxRRGetScreenForOutput (pScreen, output); if (!dmxScreen) return FALSE; if (dmxScreen->beRandrPending) return TRUE; modeInfo = XRRAllocModeInfo (mode->name, mode->mode.nameLength); if (!modeInfo) return FALSE; modeInfo->width = mode->mode.width; modeInfo->height = mode->mode.height; modeInfo->dotClock = mode->mode.dotClock; modeInfo->hSyncStart = mode->mode.hSyncStart; modeInfo->hSyncEnd = mode->mode.hSyncEnd; modeInfo->hTotal = mode->mode.hTotal; modeInfo->hSkew = mode->mode.hSkew; modeInfo->vSyncStart = mode->mode.vSyncStart; modeInfo->vSyncEnd = mode->mode.vSyncEnd; modeInfo->vTotal = mode->mode.vTotal; modeInfo->modeFlags = mode->mode.modeFlags; XLIB_PROLOGUE (dmxScreen); m = XRRCreateMode (dmxScreen->beDisplay, DefaultRootWindow (dmxScreen->beDisplay), modeInfo); XLIB_EPILOGUE (dmxScreen); if (!m) return FALSE; XRRFreeModeInfo (modeInfo); XLIB_PROLOGUE (dmxScreen); XRRAddOutputMode (dmxScreen->beDisplay, (unsigned long) output->devPrivate, m); XLIB_EPILOGUE (dmxScreen); return TRUE; } static void dmxRRModeDestroy (ScreenPtr pScreen, RRModePtr mode) { XRRScreenResources *r; int i; for (i = 0; i < dmxNumScreens; i++) { DMXScreenInfo *dmxScreen = &dmxScreens[i]; if (!dmxScreen->beRandr) continue; if (dmxScreen->beRandrPending) continue; r = NULL; XLIB_PROLOGUE (dmxScreen); r = XRRGetScreenResources (dmxScreen->beDisplay, dmxScreen->scrnWin); XLIB_EPILOGUE (dmxScreen); if (r) { #ifdef _XSERVER64 RRMode64 m; #else RRMode m; #endif m = dmxRRGetXMode (r, mode); if (m) { XLIB_PROLOGUE (dmxScreen); XRRDestroyMode (dmxScreen->beDisplay, m); XLIB_EPILOGUE (dmxScreen); } XRRFreeScreenResources (r); } } } Bool dmxScreenEventCheckRR (ScreenPtr pScreen, xcb_generic_event_t *event) { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; switch (event->response_type & ~0x80) { case XCB_MAP_NOTIFY: if (((xcb_map_notify_event_t *) event)->window == dmxScreen->rootWin) return TRUE; return FALSE; case XCB_CONFIGURE_NOTIFY: { xcb_configure_notify_event_t *xconfigure = (xcb_configure_notify_event_t *) event; XEvent X; if (xconfigure->window == dmxScreen->scrnWin) { if (dmxScreen->scrnWidth == xconfigure->width && dmxScreen->scrnHeight == xconfigure->height) return TRUE; dmxScreen->scrnWidth = xconfigure->width; dmxScreen->scrnHeight = xconfigure->height; } else if (xconfigure->window == dmxScreen->rootWin) { if (dmxScreen->rootX == xconfigure->x && dmxScreen->rootY == xconfigure->y) return TRUE; dmxScreen->rootX = xconfigure->x; dmxScreen->rootY = xconfigure->y; } else { return FALSE; } X.xconfigure.type = XCB_CONFIGURE_NOTIFY; X.xconfigure.display = dmxScreen->beDisplay; X.xconfigure.window = xconfigure->window; X.xconfigure.width = xconfigure->width; X.xconfigure.height = xconfigure->height; XRRUpdateConfiguration (&X); } break; default: if (!dmxScreen->beRandr) return FALSE; switch ((event->response_type & ~0x80) - dmxScreen->beRandrEventBase) { case XCB_RANDR_SCREEN_CHANGE_NOTIFY: { xcb_randr_screen_change_notify_event_t *scevent = (xcb_randr_screen_change_notify_event_t *) event; XRRScreenChangeNotifyEvent X; X.type = event->response_type; X.display = dmxScreen->beDisplay; X.root = scevent->root; X.width = scevent->width; X.mwidth = scevent->mwidth; X.height = scevent->height; X.mheight = scevent->mheight; X.rotation = scevent->rotation; X.subpixel_order = scevent->subpixel_order; XRRUpdateConfiguration ((XEvent *) &X); } break; case XCB_RANDR_NOTIFY: break; default: return FALSE; } } dmxScreen->beWidth = DisplayWidth (dmxScreen->beDisplay, DefaultScreen (dmxScreen->beDisplay)); dmxScreen->beHeight = DisplayHeight (dmxScreen->beDisplay, DefaultScreen (dmxScreen->beDisplay)); RRGetInfo (screenInfo.screens[0]); return TRUE; } Bool dmxRRScreenInit (ScreenPtr pScreen) { rrScrPrivPtr pScrPriv; if (!RRScreenInit (pScreen)) return FALSE; pScrPriv = rrGetScrPriv (pScreen); pScrPriv->rrGetInfo = dmxRRGetInfo; pScrPriv->rrScreenSetSize = dmxRRScreenSetSize; pScrPriv->rrCrtcSet = dmxRRCrtcSet; pScrPriv->rrCrtcSetGamma = dmxRRCrtcSetGamma; pScrPriv->rrOutputSetProperty = dmxRROutputSetProperty; pScrPriv->rrOutputValidateMode = dmxRROutputValidateMode; pScrPriv->rrModeDestroy = dmxRRModeDestroy; RRScreenSetSizeRange (pScreen, 1, 1, SHRT_MAX, SHRT_MAX); if (pScreen->myNum) { char name[64]; int i; for (i = 0; i < xRROutputsPerScreen; i++) { sprintf (name, "dmx%d", (pScreen->myNum - 1) * xRROutputsPerScreen + i); if (!RROutputCreate (screenInfo.screens[0], name, strlen (name), NULL)) return FALSE; } for (i = 0; i < xRRCrtcsPerScreen; i++) if (!RRCrtcCreate (screenInfo.screens[0], NULL)) return FALSE; } else { XRRScreenResources *r = NULL; DMXScreenInfo *dmxScreen = dmxScreens; Display *display = dmxScreen->beDisplay; if (display && dmxScreens->beRandr) { XLIB_PROLOGUE (dmxScreens); r = XRRGetScreenResources (display, DefaultRootWindow (display)); XLIB_EPILOGUE (dmxScreens); } if (r) { int i; xRROutputsForFirstScreen = r->noutput; xRRCrtcsForFirstScreen = r->ncrtc; for (i = 0; i < r->noutput; i++) { XRROutputInfo *o; o = XRRGetOutputInfo (display, r, r->outputs[i]); if (!o) return FALSE; if (!RROutputCreate (screenInfo.screens[0], o->name, strlen (o->name), NULL)) return FALSE; } for (i = 0; i < r->ncrtc; i++) if (!RRCrtcCreate (screenInfo.screens[0], NULL)) return FALSE; XRRFreeScreenResources (r); } else { if (!RROutputCreate (screenInfo.screens[0], "default", 7, NULL)) return FALSE; if (!RRCrtcCreate (screenInfo.screens[0], NULL)) return FALSE; } } return TRUE; } Bool dmxBERRScreenInit (ScreenPtr pScreen) { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; if (!dmxScreen->beRandr) return FALSE; XLIB_PROLOGUE (dmxScreen); XRRSelectInput (dmxScreen->beDisplay, DefaultRootWindow (dmxScreen->beDisplay), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RROutputPropertyNotifyMask); XLIB_EPILOGUE (dmxScreen); return TRUE; } void dmxBERRScreenFini (ScreenPtr pScreen) { DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; if (dmxScreen->beRandr) { XLIB_PROLOGUE (dmxScreen); XRRSelectInput (dmxScreen->beDisplay, DefaultRootWindow (dmxScreen->beDisplay), 0); XLIB_EPILOGUE (dmxScreen); } } #endif