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