Xrandr.c revision b042e37f
1/* 2 * $XFree86: xc/lib/Xrandr/Xrandr.c,v 1.13tsi Exp $ 3 * 4 * Copyright © 2000 Compaq Computer Corporation, Inc. 5 * Copyright © 2002 Hewlett Packard Company, Inc. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that 10 * copyright notice and this permission notice appear in supporting 11 * documentation, and that the name of Compaq or HP not be used in advertising 12 * or publicity pertaining to distribution of the software without specific, 13 * written prior permission. HP makes no representations about the 14 * suitability of this software for any purpose. It is provided "as is" 15 * without express or implied warranty. 16 * 17 * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ 19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Author: Jim Gettys, HP Labs, HP. 25 */ 26 27#ifdef HAVE_CONFIG_H 28#include <config.h> 29#endif 30 31#include <stdio.h> 32#include <X11/Xlib.h> 33/* we need to be able to manipulate the Display structure on events */ 34#include <X11/Xlibint.h> 35#include <X11/extensions/render.h> 36#include <X11/extensions/Xrender.h> 37#include "Xrandrint.h" 38 39XExtensionInfo XRRExtensionInfo; 40char XRRExtensionName[] = RANDR_NAME; 41 42static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire); 43static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire); 44 45static int 46XRRCloseDisplay (Display *dpy, XExtCodes *codes); 47 48static /* const */ XExtensionHooks rr_extension_hooks = { 49 NULL, /* create_gc */ 50 NULL, /* copy_gc */ 51 NULL, /* flush_gc */ 52 NULL, /* free_gc */ 53 NULL, /* create_font */ 54 NULL, /* free_font */ 55 XRRCloseDisplay, /* close_display */ 56 XRRWireToEvent, /* wire_to_event */ 57 XRREventToWire, /* event_to_wire */ 58 NULL, /* error */ 59 NULL, /* error_string */ 60}; 61 62static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire) 63{ 64 XExtDisplayInfo *info = XRRFindDisplay(dpy); 65 66 RRCheckExtension(dpy, info, False); 67 68 switch ((wire->u.u.type & 0x7F) - info->codes->first_event) 69 { 70 case RRScreenChangeNotify: { 71 XRRScreenChangeNotifyEvent *aevent= (XRRScreenChangeNotifyEvent *) event; 72 xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire; 73 aevent->type = awire->type & 0x7F; 74 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); 75 aevent->send_event = (awire->type & 0x80) != 0; 76 aevent->display = dpy; 77 aevent->window = awire->window; 78 aevent->root = awire->root; 79 aevent->timestamp = awire->timestamp; 80 aevent->config_timestamp = awire->configTimestamp; 81 aevent->size_index = awire->sizeID; 82 aevent->subpixel_order = awire->subpixelOrder; 83 aevent->rotation = awire->rotation; 84 aevent->width = awire->widthInPixels; 85 aevent->height = awire->heightInPixels; 86 aevent->mwidth = awire->widthInMillimeters; 87 aevent->mheight = awire->heightInMillimeters; 88 return True; 89 } 90 case RRNotify: { 91 XRRNotifyEvent *aevent = (XRRNotifyEvent *) event; 92 xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire; 93 aevent->type = awire->type & 0x7F; 94 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); 95 aevent->send_event = (awire->type & 0x80) != 0; 96 aevent->display = dpy; 97 aevent->window = awire->window; 98 aevent->subtype = awire->subCode; 99 switch (aevent->subtype) { 100 case RRNotify_OutputChange: { 101 XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event; 102 xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire; 103 aevent->output = awire->output; 104 aevent->crtc = awire->crtc; 105 aevent->mode = awire->mode; 106 aevent->rotation = awire->rotation; 107 aevent->connection = awire->connection; 108 aevent->subpixel_order = awire->subpixelOrder; 109 return True; 110 } 111 case RRNotify_CrtcChange: { 112 XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event; 113 xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire; 114 aevent->crtc = awire->crtc; 115 aevent->mode = awire->mode; 116 aevent->rotation = awire->rotation; 117 aevent->x = awire->x; 118 aevent->y = awire->y; 119 aevent->width = awire->width; 120 aevent->height = awire->height; 121 return True; 122 } 123 case RRNotify_OutputProperty: { 124 XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event; 125 xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire; 126 aevent->output = awire->output; 127 aevent->property = awire->atom; 128 aevent->timestamp = awire->timestamp; 129 aevent->state = awire->state; 130 return True; 131 } 132 133 break; 134 } 135 } 136 } 137 138 return False; 139} 140 141static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire) 142{ 143 XExtDisplayInfo *info = XRRFindDisplay(dpy); 144 145 RRCheckExtension(dpy, info, False); 146 147 switch ((event->type & 0x7F) - info->codes->first_event) 148 { 149 case RRScreenChangeNotify: { 150 xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire; 151 XRRScreenChangeNotifyEvent *aevent = (XRRScreenChangeNotifyEvent *) event; 152 awire->type = aevent->type | (aevent->send_event ? 0x80 : 0); 153 awire->rotation = (CARD8) aevent->rotation; 154 awire->sequenceNumber = aevent->serial & 0xFFFF; 155 awire->timestamp = aevent->timestamp; 156 awire->configTimestamp = aevent->config_timestamp; 157 awire->root = aevent->root; 158 awire->window = aevent->window; 159 awire->sizeID = aevent->size_index; 160 awire->subpixelOrder = aevent->subpixel_order; 161 awire->widthInPixels = aevent->width; 162 awire->heightInPixels = aevent->height; 163 awire->widthInMillimeters = aevent->mwidth; 164 awire->heightInMillimeters = aevent->mheight; 165 return True; 166 } 167 case RRNotify: { 168 xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire; 169 XRRNotifyEvent *aevent = (XRRNotifyEvent *) event; 170 awire->type = aevent->type | (aevent->send_event ? 0x80 : 0); 171 awire->sequenceNumber = aevent->serial & 0xFFFF; 172 awire->window = aevent->window; 173 awire->subCode = aevent->subtype; 174 switch (aevent->subtype) { 175 case RRNotify_OutputChange: { 176 xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire; 177 XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event; 178 awire->output = aevent->output; 179 awire->crtc = aevent->crtc; 180 awire->mode = aevent->mode; 181 awire->rotation = aevent->rotation; 182 awire->connection = aevent->connection; 183 awire->subpixelOrder = aevent->subpixel_order; 184 return True; 185 } 186 case RRNotify_CrtcChange: { 187 xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire; 188 XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event; 189 awire->crtc = aevent->crtc; 190 awire->mode = aevent->mode; 191 awire->rotation = aevent->rotation; 192 awire->x = aevent->x; 193 awire->y = aevent->y; 194 awire->width = aevent->width; 195 awire->height = aevent->height; 196 return True; 197 } 198 case RRNotify_OutputProperty: { 199 xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire; 200 XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event; 201 awire->output = aevent->output; 202 awire->atom = aevent->property; 203 awire->timestamp = aevent->timestamp; 204 awire->state = aevent->state; 205 return True; 206 } 207 } 208 } 209 } 210 return False; 211} 212 213XExtDisplayInfo * 214XRRFindDisplay (Display *dpy) 215{ 216 XExtDisplayInfo *dpyinfo; 217 XRandRInfo *xrri; 218 int i, numscreens; 219 220 dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy); 221 if (!dpyinfo) { 222 dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy, 223 XRRExtensionName, 224 &rr_extension_hooks, 225 RRNumberEvents, 0); 226 numscreens = ScreenCount(dpy); 227 xrri = Xmalloc (sizeof(XRandRInfo) + 228 sizeof(char *) * numscreens); 229 xrri->config = (XRRScreenConfiguration **)(xrri + 1); 230 for(i = 0; i < numscreens; i++) 231 xrri->config[i] = NULL; 232 xrri->major_version = -1; 233 dpyinfo->data = (char *) xrri; 234 } 235 return dpyinfo; 236} 237 238static int 239XRRCloseDisplay (Display *dpy, XExtCodes *codes) 240{ 241 int i; 242 XRRScreenConfiguration **configs; 243 XExtDisplayInfo *info = XRRFindDisplay (dpy); 244 XRandRInfo *xrri; 245 246 LockDisplay(dpy); 247 /* 248 * free cached data 249 */ 250 if (XextHasExtension(info)) { 251 xrri = (XRandRInfo *) info->data; 252 if (xrri) { 253 configs = xrri->config; 254 255 for (i = 0; i < ScreenCount(dpy); i++) { 256 if (configs[i] != NULL) XFree (configs[i]); 257 } 258 XFree (xrri); 259 } 260 } 261 UnlockDisplay(dpy); 262 return XextRemoveDisplay (&XRRExtensionInfo, dpy); 263} 264 265int XRRRootToScreen(Display *dpy, Window root) 266{ 267 int snum; 268 for (snum = 0; snum < ScreenCount(dpy); snum++) { 269 if (RootWindow(dpy, snum) == root) return snum; 270 } 271 return -1; 272} 273 274 275Bool XRRQueryExtension (Display *dpy, int *event_basep, int *error_basep) 276{ 277 XExtDisplayInfo *info = XRRFindDisplay (dpy); 278 279 if (XextHasExtension(info)) { 280 *event_basep = info->codes->first_event; 281 *error_basep = info->codes->first_error; 282 return True; 283 } else { 284 return False; 285 } 286} 287 288Bool 289_XRRHasRates (int major, int minor) 290{ 291 return major > 1 || (major == 1 && minor >= 1); 292} 293 294Status XRRQueryVersion (Display *dpy, 295 int *major_versionp, 296 int *minor_versionp) 297{ 298 XExtDisplayInfo *info = XRRFindDisplay (dpy); 299 xRRQueryVersionReply rep; 300 xRRQueryVersionReq *req; 301 XRandRInfo *xrri; 302 303 RRCheckExtension (dpy, info, 0); 304 305 xrri = (XRandRInfo *) info->data; 306 307 /* 308 * only get the version information from the server if we don't have it already 309 */ 310 if (xrri->major_version == -1) { 311 LockDisplay (dpy); 312 GetReq (RRQueryVersion, req); 313 req->reqType = info->codes->major_opcode; 314 req->randrReqType = X_RRQueryVersion; 315 req->majorVersion = RANDR_MAJOR; 316 req->minorVersion = RANDR_MINOR; 317 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) { 318 UnlockDisplay (dpy); 319 SyncHandle (); 320 return 0; 321 } 322 xrri->major_version = rep.majorVersion; 323 xrri->minor_version = rep.minorVersion; 324 xrri->has_rates = _XRRHasRates (xrri->major_version, xrri->minor_version); 325 UnlockDisplay (dpy); 326 SyncHandle (); 327 } 328 *major_versionp = xrri->major_version; 329 *minor_versionp = xrri->minor_version; 330 return 1; 331} 332 333Bool 334_XRRVersionHandler (Display *dpy, 335 xReply *rep, 336 char *buf, 337 int len, 338 XPointer data) 339{ 340 xRRQueryVersionReply replbuf; 341 xRRQueryVersionReply *repl; 342 _XRRVersionState *state = (_XRRVersionState *) data; 343 344 if (dpy->last_request_read != state->version_seq) 345 return False; 346 if (rep->generic.type == X_Error) 347 { 348 state->error = True; 349 return False; 350 } 351 repl = (xRRQueryVersionReply *) 352 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len, 353 (SIZEOF(xRRQueryVersionReply) - SIZEOF(xReply)) >> 2, 354 True); 355 state->major_version = repl->majorVersion; 356 state->minor_version = repl->minorVersion; 357 return True; 358} 359 360/* 361 * in protocol version 0.1, routine added to allow selecting for new events. 362 */ 363 364void XRRSelectInput (Display *dpy, Window window, int mask) 365{ 366 XExtDisplayInfo *info = XRRFindDisplay (dpy); 367 xRRSelectInputReq *req; 368 369 RRSimpleCheckExtension (dpy, info); 370 371 LockDisplay (dpy); 372 GetReq (RRSelectInput, req); 373 req->reqType = info->codes->major_opcode; 374 req->randrReqType = X_RRSelectInput; 375 req->window = window; 376 req->enable = 0; 377 if (mask) req->enable = mask; 378 UnlockDisplay (dpy); 379 SyncHandle (); 380 return; 381} 382 383int XRRUpdateConfiguration(XEvent *event) 384{ 385 XRRScreenChangeNotifyEvent *scevent; 386 XConfigureEvent *rcevent; 387 Display *dpy = event->xany.display; 388 XExtDisplayInfo *info; 389 XRandRInfo *xrri; 390 int snum; 391 392 /* first, see if it is a vanilla configure notify event */ 393 if (event->type == ConfigureNotify) { 394 rcevent = (XConfigureEvent *) event; 395 snum = XRRRootToScreen(dpy, rcevent->window); 396 dpy->screens[snum].width = rcevent->width; 397 dpy->screens[snum].height = rcevent->height; 398 return 1; 399 } 400 401 info = XRRFindDisplay(dpy); 402 RRCheckExtension (dpy, info, 0); 403 404 switch (event->type - info->codes->first_event) { 405 case RRScreenChangeNotify: 406 scevent = (XRRScreenChangeNotifyEvent *) event; 407 snum = XRRRootToScreen(dpy, 408 ((XRRScreenChangeNotifyEvent *) event)->root); 409 if (scevent->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 410 dpy->screens[snum].width = scevent->height; 411 dpy->screens[snum].height = scevent->width; 412 dpy->screens[snum].mwidth = scevent->mheight; 413 dpy->screens[snum].mheight = scevent->mwidth; 414 } else { 415 dpy->screens[snum].width = scevent->width; 416 dpy->screens[snum].height = scevent->height; 417 dpy->screens[snum].mwidth = scevent->mwidth; 418 dpy->screens[snum].mheight = scevent->mheight; 419 } 420 XRenderSetSubpixelOrder (dpy, snum, scevent->subpixel_order); 421 break; 422 default: 423 return 0; 424 } 425 xrri = (XRandRInfo *) info->data; 426 /* 427 * so the next time someone wants some data, it will be fetched; 428 * it might be better to force the round trip immediately, but 429 * I dislike pounding the server simultaneously when not necessary 430 */ 431 if (xrri->config[snum] != NULL) { 432 XFree (xrri->config[snum]); 433 xrri->config[snum] = NULL; 434 } 435 return 1; 436} 437