XrrScreen.c revision b242714c
1b042e37fSmrg/* 2b042e37fSmrg * Copyright © 2006 Keith Packard 3b042e37fSmrg * 4b042e37fSmrg * Permission to use, copy, modify, distribute, and sell this software and its 5b042e37fSmrg * documentation for any purpose is hereby granted without fee, provided that 6b042e37fSmrg * the above copyright notice appear in all copies and that both that copyright 7b042e37fSmrg * notice and this permission notice appear in supporting documentation, and 8b042e37fSmrg * that the name of the copyright holders not be used in advertising or 9b042e37fSmrg * publicity pertaining to distribution of the software without specific, 10b042e37fSmrg * written prior permission. The copyright holders make no representations 11b042e37fSmrg * about the suitability of this software for any purpose. It is provided "as 12b042e37fSmrg * is" without express or implied warranty. 13b042e37fSmrg * 14b042e37fSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15b042e37fSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16b042e37fSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17b042e37fSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18b042e37fSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19b042e37fSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20b042e37fSmrg * OF THIS SOFTWARE. 21b042e37fSmrg */ 22b042e37fSmrg 23b042e37fSmrg#ifdef HAVE_CONFIG_H 24b042e37fSmrg#include <config.h> 25b042e37fSmrg#endif 26b042e37fSmrg 27b242714cSmrg#include <limits.h> 28b042e37fSmrg#include <stdio.h> 29b042e37fSmrg#include <X11/Xlib.h> 30b042e37fSmrg/* we need to be able to manipulate the Display structure on events */ 31b042e37fSmrg#include <X11/Xlibint.h> 32b042e37fSmrg#include <X11/extensions/render.h> 33b042e37fSmrg#include <X11/extensions/Xrender.h> 34b042e37fSmrg#include "Xrandrint.h" 35b042e37fSmrg 368c4a8e55Smrg/* 378c4a8e55Smrg * this is cheating on the knowledge that the two requests are identical 388c4a8e55Smrg * but for the request number. 398c4a8e55Smrg */ 408c4a8e55Smrgstatic XRRScreenResources * 418c4a8e55SmrgdoGetScreenResources (Display *dpy, Window window, int poll) 42b042e37fSmrg{ 43b042e37fSmrg XExtDisplayInfo *info = XRRFindDisplay(dpy); 44b042e37fSmrg xRRGetScreenResourcesReply rep; 45b042e37fSmrg xRRGetScreenResourcesReq *req; 46b042e37fSmrg _XAsyncHandler async; 47b042e37fSmrg _XRRVersionState async_state; 48b042e37fSmrg int nbytes, nbytesRead, rbytes; 49b042e37fSmrg int i; 50b042e37fSmrg xRRQueryVersionReq *vreq; 51b042e37fSmrg XRRScreenResources *xrsr; 52b042e37fSmrg char *names; 53b042e37fSmrg char *wire_names, *wire_name; 54b042e37fSmrg Bool getting_version = False; 55b042e37fSmrg XRandRInfo *xrri; 56b042e37fSmrg 578c4a8e55Smrg RRCheckExtension (dpy, info, NULL); 58b042e37fSmrg 59b042e37fSmrg LockDisplay (dpy); 60b042e37fSmrg xrri = (XRandRInfo *) info->data; 61b042e37fSmrg 62b042e37fSmrg if (xrri->major_version == -1) 63b042e37fSmrg { 64b042e37fSmrg /* hide a version query in the request */ 65b042e37fSmrg GetReq (RRQueryVersion, vreq); 66b042e37fSmrg vreq->reqType = info->codes->major_opcode; 67b042e37fSmrg vreq->randrReqType = X_RRQueryVersion; 68b042e37fSmrg vreq->majorVersion = RANDR_MAJOR; 69b042e37fSmrg vreq->minorVersion = RANDR_MINOR; 700597fb56Smrg 71b042e37fSmrg async_state.version_seq = dpy->request; 72b042e37fSmrg async_state.error = False; 73b042e37fSmrg async.next = dpy->async_handlers; 74b042e37fSmrg async.handler = _XRRVersionHandler; 75b042e37fSmrg async.data = (XPointer) &async_state; 76b042e37fSmrg dpy->async_handlers = &async; 77b042e37fSmrg 78b042e37fSmrg getting_version = True; 79b042e37fSmrg } 80b042e37fSmrg 81b042e37fSmrg GetReq (RRGetScreenResources, req); 82b042e37fSmrg req->reqType = info->codes->major_opcode; 838c4a8e55Smrg req->randrReqType = poll ? X_RRGetScreenResources 848c4a8e55Smrg : X_RRGetScreenResourcesCurrent; 85b042e37fSmrg req->window = window; 86b042e37fSmrg 87b042e37fSmrg if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) 88b042e37fSmrg { 89b042e37fSmrg if (getting_version) 90b042e37fSmrg DeqAsyncHandler (dpy, &async); 91b042e37fSmrg UnlockDisplay (dpy); 92b042e37fSmrg SyncHandle (); 93b042e37fSmrg return NULL; 94b042e37fSmrg } 95b042e37fSmrg if (getting_version) 96b042e37fSmrg { 97b042e37fSmrg DeqAsyncHandler (dpy, &async); 98b042e37fSmrg if (async_state.error) 99b042e37fSmrg { 100b042e37fSmrg UnlockDisplay (dpy); 101b042e37fSmrg SyncHandle(); 102b042e37fSmrg LockDisplay (dpy); 103b042e37fSmrg } 104b042e37fSmrg xrri->major_version = async_state.major_version; 105b042e37fSmrg xrri->minor_version = async_state.minor_version; 106b042e37fSmrg xrri->has_rates = _XRRHasRates (xrri->minor_version, xrri->major_version); 107b042e37fSmrg } 108b042e37fSmrg 109b242714cSmrg if (rep.length < INT_MAX >> 2) { 110b242714cSmrg nbytes = (long) rep.length << 2; 111b242714cSmrg 112b242714cSmrg nbytesRead = (long) (rep.nCrtcs * 4 + 113b242714cSmrg rep.nOutputs * 4 + 114b242714cSmrg rep.nModes * SIZEOF (xRRModeInfo) + 115b242714cSmrg ((rep.nbytesNames + 3) & ~3)); 116b242714cSmrg 117b242714cSmrg /* 118b242714cSmrg * first we must compute how much space to allocate for 119b242714cSmrg * randr library's use; we'll allocate the structures in a single 120b242714cSmrg * allocation, on cleanlyness grounds. 121b242714cSmrg */ 122b242714cSmrg 123b242714cSmrg rbytes = (sizeof (XRRScreenResources) + 124b242714cSmrg rep.nCrtcs * sizeof (RRCrtc) + 125b242714cSmrg rep.nOutputs * sizeof (RROutput) + 126b242714cSmrg rep.nModes * sizeof (XRRModeInfo) + 127b242714cSmrg rep.nbytesNames + rep.nModes); /* '\0' terminate names */ 128b242714cSmrg 129b242714cSmrg xrsr = (XRRScreenResources *) Xmalloc(rbytes); 130b242714cSmrg wire_names = (char *) Xmalloc (rep.nbytesNames); 131b242714cSmrg } else { 132b242714cSmrg nbytes = 0; 133b242714cSmrg nbytesRead = 0; 134b242714cSmrg rbytes = 0; 135b242714cSmrg xrsr = NULL; 136b242714cSmrg wire_names = NULL; 137b242714cSmrg } 138b042e37fSmrg 139b042e37fSmrg if (xrsr == NULL || wire_names == NULL) { 140b242714cSmrg Xfree (xrsr); 141b242714cSmrg Xfree (wire_names); 1428bd17e5fSmrg _XEatDataWords (dpy, rep.length); 143b042e37fSmrg UnlockDisplay (dpy); 144b042e37fSmrg SyncHandle (); 145b042e37fSmrg return NULL; 146b042e37fSmrg } 147b042e37fSmrg 148b042e37fSmrg xrsr->timestamp = rep.timestamp; 149b042e37fSmrg xrsr->configTimestamp = rep.configTimestamp; 150b042e37fSmrg xrsr->ncrtc = rep.nCrtcs; 151b042e37fSmrg xrsr->crtcs = (RRCrtc *) (xrsr + 1); 152b042e37fSmrg xrsr->noutput = rep.nOutputs; 153b042e37fSmrg xrsr->outputs = (RROutput *) (xrsr->crtcs + rep.nCrtcs); 154b042e37fSmrg xrsr->nmode = rep.nModes; 155b042e37fSmrg xrsr->modes = (XRRModeInfo *) (xrsr->outputs + rep.nOutputs); 156b042e37fSmrg names = (char *) (xrsr->modes + rep.nModes); 157b042e37fSmrg 15867594505Smrg _XRead32 (dpy, (long *) xrsr->crtcs, rep.nCrtcs << 2); 15967594505Smrg _XRead32 (dpy, (long *) xrsr->outputs, rep.nOutputs << 2); 1600597fb56Smrg 161b042e37fSmrg for (i = 0; i < rep.nModes; i++) { 162b042e37fSmrg xRRModeInfo modeInfo; 1630597fb56Smrg 164b042e37fSmrg _XReadPad (dpy, (char *) &modeInfo, SIZEOF (xRRModeInfo)); 165b042e37fSmrg xrsr->modes[i].id = modeInfo.id; 166b042e37fSmrg xrsr->modes[i].width = modeInfo.width; 167b042e37fSmrg xrsr->modes[i].height = modeInfo.height; 168b042e37fSmrg xrsr->modes[i].dotClock = modeInfo.dotClock; 169b042e37fSmrg xrsr->modes[i].hSyncStart = modeInfo.hSyncStart; 170b042e37fSmrg xrsr->modes[i].hSyncEnd = modeInfo.hSyncEnd; 171b042e37fSmrg xrsr->modes[i].hTotal = modeInfo.hTotal; 172b042e37fSmrg xrsr->modes[i].hSkew = modeInfo.hSkew; 173b042e37fSmrg xrsr->modes[i].vSyncStart = modeInfo.vSyncStart; 174b042e37fSmrg xrsr->modes[i].vSyncEnd = modeInfo.vSyncEnd; 175b042e37fSmrg xrsr->modes[i].vTotal = modeInfo.vTotal; 176b042e37fSmrg xrsr->modes[i].nameLength = modeInfo.nameLength; 177b042e37fSmrg xrsr->modes[i].modeFlags = modeInfo.modeFlags; 178b042e37fSmrg } 179b042e37fSmrg 180b042e37fSmrg /* 181b042e37fSmrg * Read names and '\0' pad each one 182b042e37fSmrg */ 183b042e37fSmrg _XReadPad (dpy, wire_names, rep.nbytesNames); 184b042e37fSmrg wire_name = wire_names; 185b042e37fSmrg for (i = 0; i < rep.nModes; i++) { 186b042e37fSmrg xrsr->modes[i].name = names; 187b242714cSmrg if (xrsr->modes[i].nameLength > rep.nbytesNames) { 188b242714cSmrg Xfree (xrsr); 189b242714cSmrg Xfree (wire_names); 190b242714cSmrg UnlockDisplay (dpy); 191b242714cSmrg SyncHandle (); 192b242714cSmrg return NULL; 193b242714cSmrg } 194b242714cSmrg rep.nbytesNames -= xrsr->modes[i].nameLength; 195b042e37fSmrg memcpy (names, wire_name, xrsr->modes[i].nameLength); 196b042e37fSmrg names[xrsr->modes[i].nameLength] = '\0'; 197b042e37fSmrg names += xrsr->modes[i].nameLength + 1; 198b042e37fSmrg wire_name += xrsr->modes[i].nameLength; 199b042e37fSmrg } 200b042e37fSmrg Xfree (wire_names); 2010597fb56Smrg 202b042e37fSmrg /* 203b042e37fSmrg * Skip any extra data 204b042e37fSmrg */ 205b042e37fSmrg if (nbytes > nbytesRead) 206b042e37fSmrg _XEatData (dpy, (unsigned long) (nbytes - nbytesRead)); 2070597fb56Smrg 208b042e37fSmrg UnlockDisplay (dpy); 209b042e37fSmrg SyncHandle(); 210b042e37fSmrg return (XRRScreenResources *) xrsr; 211b042e37fSmrg} 212b042e37fSmrg 2138c4a8e55SmrgXRRScreenResources * 2148c4a8e55SmrgXRRGetScreenResources(Display *dpy, Window window) 2158c4a8e55Smrg{ 2168c4a8e55Smrg return doGetScreenResources(dpy, window, 1); 2178c4a8e55Smrg} 2188c4a8e55Smrg 2198c4a8e55SmrgXRRScreenResources * 2208c4a8e55SmrgXRRGetScreenResourcesCurrent(Display *dpy, Window window) 2218c4a8e55Smrg{ 2228c4a8e55Smrg return doGetScreenResources(dpy, window, 0); 2238c4a8e55Smrg} 2248c4a8e55Smrg 225b042e37fSmrgvoid 226b042e37fSmrgXRRFreeScreenResources (XRRScreenResources *resources) 227b042e37fSmrg{ 228b042e37fSmrg Xfree (resources); 229b042e37fSmrg} 230b042e37fSmrg 231b042e37fSmrgStatus 232b042e37fSmrgXRRGetScreenSizeRange (Display *dpy, Window window, 233b042e37fSmrg int *minWidth, int *minHeight, 234b042e37fSmrg int *maxWidth, int *maxHeight) 235b042e37fSmrg{ 236b042e37fSmrg XExtDisplayInfo *info = XRRFindDisplay(dpy); 237b042e37fSmrg xRRGetScreenSizeRangeReq *req; 238b042e37fSmrg xRRGetScreenSizeRangeReply rep; 239b042e37fSmrg 240b042e37fSmrg RRCheckExtension (dpy, info, 0); 241b042e37fSmrg LockDisplay (dpy); 242b042e37fSmrg GetReq (RRGetScreenSizeRange, req); 243b042e37fSmrg req->reqType = info->codes->major_opcode; 244b042e37fSmrg req->randrReqType = X_RRGetScreenSizeRange; 245b042e37fSmrg req->window = window; 246b042e37fSmrg if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) 247b042e37fSmrg { 248b042e37fSmrg UnlockDisplay (dpy); 249b042e37fSmrg SyncHandle (); 250b042e37fSmrg return False; 251b042e37fSmrg } 252b042e37fSmrg UnlockDisplay (dpy); 253b042e37fSmrg SyncHandle (); 254b042e37fSmrg *minWidth = rep.minWidth; 255b042e37fSmrg *minHeight = rep.minHeight; 256b042e37fSmrg *maxWidth = rep.maxWidth; 257b042e37fSmrg *maxHeight = rep.maxHeight; 258b042e37fSmrg return True; 259b042e37fSmrg} 260b042e37fSmrg 261b042e37fSmrgvoid 262b042e37fSmrgXRRSetScreenSize (Display *dpy, Window window, 263b042e37fSmrg int width, int height, 264b042e37fSmrg int mmWidth, int mmHeight) 265b042e37fSmrg{ 266b042e37fSmrg XExtDisplayInfo *info = XRRFindDisplay(dpy); 267b042e37fSmrg xRRSetScreenSizeReq *req; 268b042e37fSmrg 269b042e37fSmrg RRSimpleCheckExtension (dpy, info); 270b042e37fSmrg LockDisplay (dpy); 271b042e37fSmrg GetReq (RRSetScreenSize, req); 272b042e37fSmrg req->reqType = info->codes->major_opcode; 273b042e37fSmrg req->randrReqType = X_RRSetScreenSize; 274b042e37fSmrg req->window = window; 275b042e37fSmrg req->width = width; 276b042e37fSmrg req->height = height; 277b042e37fSmrg req->widthInMillimeters = mmWidth; 278b042e37fSmrg req->heightInMillimeters = mmHeight; 279b042e37fSmrg UnlockDisplay (dpy); 280b042e37fSmrg SyncHandle (); 281b042e37fSmrg} 282