/* * Copyright © 2006 Keith Packard * * 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 the copyright holders not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no representations * about the suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS 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. */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <limits.h> #include <stdio.h> #include <X11/Xlib.h> /* we need to be able to manipulate the Display structure on events */ #include <X11/Xlibint.h> #include <X11/extensions/render.h> #include <X11/extensions/Xrender.h> #include "Xrandrint.h" /* * this is cheating on the knowledge that the two requests are identical * but for the request number. */ static XRRScreenResources * doGetScreenResources (Display *dpy, Window window, int poll) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRGetScreenResourcesReply rep; xRRGetScreenResourcesReq *req; _XAsyncHandler async; _XRRVersionState async_state; int nbytes, nbytesRead, rbytes; int i; xRRQueryVersionReq *vreq; XRRScreenResources *xrsr; char *names; char *wire_names, *wire_name; Bool getting_version = False; XRandRInfo *xrri; RRCheckExtension (dpy, info, NULL); LockDisplay (dpy); xrri = (XRandRInfo *) info->data; if (xrri->major_version == -1) { /* hide a version query in the request */ GetReq (RRQueryVersion, vreq); vreq->reqType = info->codes->major_opcode; vreq->randrReqType = X_RRQueryVersion; vreq->majorVersion = RANDR_MAJOR; vreq->minorVersion = RANDR_MINOR; async_state.version_seq = dpy->request; async_state.error = False; async.next = dpy->async_handlers; async.handler = _XRRVersionHandler; async.data = (XPointer) &async_state; dpy->async_handlers = &async; getting_version = True; } GetReq (RRGetScreenResources, req); req->reqType = info->codes->major_opcode; req->randrReqType = poll ? X_RRGetScreenResources : X_RRGetScreenResourcesCurrent; req->window = window; if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { if (getting_version) DeqAsyncHandler (dpy, &async); UnlockDisplay (dpy); SyncHandle (); return NULL; } if (getting_version) { DeqAsyncHandler (dpy, &async); if (async_state.error) { UnlockDisplay (dpy); SyncHandle(); LockDisplay (dpy); } xrri->major_version = async_state.major_version; xrri->minor_version = async_state.minor_version; xrri->has_rates = _XRRHasRates (xrri->minor_version, xrri->major_version); } if (rep.length < INT_MAX >> 2) { nbytes = (long) rep.length << 2; nbytesRead = (long) (rep.nCrtcs * 4 + rep.nOutputs * 4 + rep.nModes * SIZEOF (xRRModeInfo) + ((rep.nbytesNames + 3) & ~3)); /* * first we must compute how much space to allocate for * randr library's use; we'll allocate the structures in a single * allocation, on cleanlyness grounds. */ rbytes = (sizeof (XRRScreenResources) + rep.nCrtcs * sizeof (RRCrtc) + rep.nOutputs * sizeof (RROutput) + rep.nModes * sizeof (XRRModeInfo) + rep.nbytesNames + rep.nModes); /* '\0' terminate names */ xrsr = (XRRScreenResources *) Xmalloc(rbytes); wire_names = (char *) Xmalloc (rep.nbytesNames); } else { nbytes = 0; nbytesRead = 0; rbytes = 0; xrsr = NULL; wire_names = NULL; } if (xrsr == NULL || wire_names == NULL) { Xfree (xrsr); Xfree (wire_names); _XEatDataWords (dpy, rep.length); UnlockDisplay (dpy); SyncHandle (); return NULL; } xrsr->timestamp = rep.timestamp; xrsr->configTimestamp = rep.configTimestamp; xrsr->ncrtc = rep.nCrtcs; xrsr->crtcs = (RRCrtc *) (xrsr + 1); xrsr->noutput = rep.nOutputs; xrsr->outputs = (RROutput *) (xrsr->crtcs + rep.nCrtcs); xrsr->nmode = rep.nModes; xrsr->modes = (XRRModeInfo *) (xrsr->outputs + rep.nOutputs); names = (char *) (xrsr->modes + rep.nModes); _XRead32 (dpy, (long *) xrsr->crtcs, rep.nCrtcs << 2); _XRead32 (dpy, (long *) xrsr->outputs, rep.nOutputs << 2); for (i = 0; i < rep.nModes; i++) { xRRModeInfo modeInfo; _XReadPad (dpy, (char *) &modeInfo, SIZEOF (xRRModeInfo)); xrsr->modes[i].id = modeInfo.id; xrsr->modes[i].width = modeInfo.width; xrsr->modes[i].height = modeInfo.height; xrsr->modes[i].dotClock = modeInfo.dotClock; xrsr->modes[i].hSyncStart = modeInfo.hSyncStart; xrsr->modes[i].hSyncEnd = modeInfo.hSyncEnd; xrsr->modes[i].hTotal = modeInfo.hTotal; xrsr->modes[i].hSkew = modeInfo.hSkew; xrsr->modes[i].vSyncStart = modeInfo.vSyncStart; xrsr->modes[i].vSyncEnd = modeInfo.vSyncEnd; xrsr->modes[i].vTotal = modeInfo.vTotal; xrsr->modes[i].nameLength = modeInfo.nameLength; xrsr->modes[i].modeFlags = modeInfo.modeFlags; } /* * Read names and '\0' pad each one */ _XReadPad (dpy, wire_names, rep.nbytesNames); wire_name = wire_names; for (i = 0; i < rep.nModes; i++) { xrsr->modes[i].name = names; if (xrsr->modes[i].nameLength > rep.nbytesNames) { Xfree (xrsr); Xfree (wire_names); UnlockDisplay (dpy); SyncHandle (); return NULL; } rep.nbytesNames -= xrsr->modes[i].nameLength; memcpy (names, wire_name, xrsr->modes[i].nameLength); names[xrsr->modes[i].nameLength] = '\0'; names += xrsr->modes[i].nameLength + 1; wire_name += xrsr->modes[i].nameLength; } Xfree (wire_names); /* * Skip any extra data */ if (nbytes > nbytesRead) _XEatData (dpy, (unsigned long) (nbytes - nbytesRead)); UnlockDisplay (dpy); SyncHandle(); return (XRRScreenResources *) xrsr; } XRRScreenResources * XRRGetScreenResources(Display *dpy, Window window) { return doGetScreenResources(dpy, window, 1); } XRRScreenResources * XRRGetScreenResourcesCurrent(Display *dpy, Window window) { return doGetScreenResources(dpy, window, 0); } void XRRFreeScreenResources (XRRScreenResources *resources) { Xfree (resources); } Status XRRGetScreenSizeRange (Display *dpy, Window window, int *minWidth, int *minHeight, int *maxWidth, int *maxHeight) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRGetScreenSizeRangeReq *req; xRRGetScreenSizeRangeReply rep; RRCheckExtension (dpy, info, 0); LockDisplay (dpy); GetReq (RRGetScreenSizeRange, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRGetScreenSizeRange; req->window = window; if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { UnlockDisplay (dpy); SyncHandle (); return False; } UnlockDisplay (dpy); SyncHandle (); *minWidth = rep.minWidth; *minHeight = rep.minHeight; *maxWidth = rep.maxWidth; *maxHeight = rep.maxHeight; return True; } void XRRSetScreenSize (Display *dpy, Window window, int width, int height, int mmWidth, int mmHeight) { XExtDisplayInfo *info = XRRFindDisplay(dpy); xRRSetScreenSizeReq *req; RRSimpleCheckExtension (dpy, info); LockDisplay (dpy); GetReq (RRSetScreenSize, req); req->reqType = info->codes->major_opcode; req->randrReqType = X_RRSetScreenSize; req->window = window; req->width = width; req->height = height; req->widthInMillimeters = mmWidth; req->heightInMillimeters = mmHeight; UnlockDisplay (dpy); SyncHandle (); }