2 * Copyright © 2000 Compaq Computer Corporation, Inc.
3 * Copyright © 2002 Hewlett Packard Company, Inc.
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Compaq or HP not be used in advertising
10 * or publicity pertaining to distribution of the software without specific,
11 * written prior permission. HP makes no representations about the
12 * suitability of this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
15 * HP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL COMPAQ
17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Author: Jim Gettys, HP Labs, HP.
31 /* we need to be able to manipulate the Display structure on events */
32 #include <X11/Xlibint.h>
33 #include <X11/extensions/render.h>
34 #include <X11/extensions/Xrender.h>
35 #include "Xrandrint.h"
37 static XExtensionInfo XRRExtensionInfo;
38 _X_HIDDEN char XRRExtensionName[] = RANDR_NAME;
40 static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
41 static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire);
44 XRRCloseDisplay (Display *dpy, XExtCodes *codes);
46 static /* const */ XExtensionHooks rr_extension_hooks = {
51 NULL, /* create_font */
53 XRRCloseDisplay, /* close_display */
54 XRRWireToEvent, /* wire_to_event */
55 XRREventToWire, /* event_to_wire */
57 NULL, /* error_string */
60 static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
62 XExtDisplayInfo *info = XRRFindDisplay(dpy);
64 RRCheckExtension(dpy, info, False);
66 switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
68 case RRScreenChangeNotify: {
69 XRRScreenChangeNotifyEvent *aevent= (XRRScreenChangeNotifyEvent *) event;
70 xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
71 aevent->type = awire->type & 0x7F;
72 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
73 aevent->send_event = (awire->type & 0x80) != 0;
74 aevent->display = dpy;
75 aevent->window = awire->window;
76 aevent->root = awire->root;
77 aevent->timestamp = awire->timestamp;
78 aevent->config_timestamp = awire->configTimestamp;
79 aevent->size_index = awire->sizeID;
80 aevent->subpixel_order = awire->subpixelOrder;
81 aevent->rotation = awire->rotation;
82 aevent->width = awire->widthInPixels;
83 aevent->height = awire->heightInPixels;
84 aevent->mwidth = awire->widthInMillimeters;
85 aevent->mheight = awire->heightInMillimeters;
89 switch (wire->u.u.detail) {
90 case RRNotify_OutputChange: {
91 XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
92 xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) 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 aevent->output = awire->output;
100 aevent->crtc = awire->crtc;
101 aevent->mode = awire->mode;
102 aevent->rotation = awire->rotation;
103 aevent->connection = awire->connection;
104 aevent->subpixel_order = awire->subpixelOrder;
107 case RRNotify_CrtcChange: {
108 XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
109 xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
110 aevent->type = awire->type & 0x7F;
111 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
112 aevent->send_event = (awire->type & 0x80) != 0;
113 aevent->display = dpy;
114 aevent->window = awire->window;
115 aevent->subtype = awire->subCode;
116 aevent->crtc = awire->crtc;
117 aevent->mode = awire->mode;
118 aevent->rotation = awire->rotation;
119 aevent->x = awire->x;
120 aevent->y = awire->y;
121 aevent->width = awire->width;
122 aevent->height = awire->height;
125 case RRNotify_OutputProperty: {
126 XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
127 xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
128 aevent->type = awire->type & 0x7F;
129 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
130 aevent->send_event = (awire->type & 0x80) != 0;
131 aevent->display = dpy;
132 aevent->window = awire->window;
133 aevent->subtype = awire->subCode;
134 aevent->output = awire->output;
135 aevent->property = awire->atom;
136 aevent->timestamp = awire->timestamp;
137 aevent->state = awire->state;
140 case RRNotify_ProviderChange: {
141 XRRProviderChangeNotifyEvent *aevent = (XRRProviderChangeNotifyEvent *) event;
142 xRRProviderChangeNotifyEvent *awire = (xRRProviderChangeNotifyEvent *) wire;
143 aevent->type = awire->type & 0x7F;
144 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
145 aevent->send_event = (awire->type & 0x80) != 0;
146 aevent->display = dpy;
147 aevent->window = awire->window;
148 aevent->subtype = awire->subCode;
149 aevent->provider = awire->provider;
150 aevent->timestamp = awire->timestamp;
153 case RRNotify_ProviderProperty: {
154 XRRProviderPropertyNotifyEvent *aevent = (XRRProviderPropertyNotifyEvent *) event;
155 xRRProviderPropertyNotifyEvent *awire = (xRRProviderPropertyNotifyEvent *) wire;
156 aevent->type = awire->type & 0x7F;
157 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
158 aevent->send_event = (awire->type & 0x80) != 0;
159 aevent->display = dpy;
160 aevent->window = awire->window;
161 aevent->subtype = awire->subCode;
162 aevent->provider = awire->provider;
163 aevent->property = awire->atom;
164 aevent->timestamp = awire->timestamp;
165 aevent->state = awire->state;
168 case RRNotify_ResourceChange: {
169 XRRResourceChangeNotifyEvent *aevent = (XRRResourceChangeNotifyEvent *) event;
170 xRRResourceChangeNotifyEvent *awire = (xRRResourceChangeNotifyEvent *) wire;
171 aevent->type = awire->type & 0x7F;
172 aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire);
173 aevent->send_event = (awire->type & 0x80) != 0;
174 aevent->display = dpy;
175 aevent->window = awire->window;
176 aevent->subtype = awire->subCode;
177 aevent->timestamp = awire->timestamp;
188 static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire)
190 XExtDisplayInfo *info = XRRFindDisplay(dpy);
192 RRCheckExtension(dpy, info, False);
194 switch ((event->type & 0x7F) - info->codes->first_event)
196 case RRScreenChangeNotify: {
197 xRRScreenChangeNotifyEvent *awire = (xRRScreenChangeNotifyEvent *) wire;
198 XRRScreenChangeNotifyEvent *aevent = (XRRScreenChangeNotifyEvent *) event;
199 awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
200 awire->rotation = (CARD8) aevent->rotation;
201 awire->sequenceNumber = aevent->serial & 0xFFFF;
202 awire->timestamp = aevent->timestamp;
203 awire->configTimestamp = aevent->config_timestamp;
204 awire->root = aevent->root;
205 awire->window = aevent->window;
206 awire->sizeID = aevent->size_index;
207 awire->subpixelOrder = aevent->subpixel_order;
208 awire->widthInPixels = aevent->width;
209 awire->heightInPixels = aevent->height;
210 awire->widthInMillimeters = aevent->mwidth;
211 awire->heightInMillimeters = aevent->mheight;
215 xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
216 XRRNotifyEvent *aevent = (XRRNotifyEvent *) event;
217 awire->type = aevent->type | (aevent->send_event ? 0x80 : 0);
218 awire->sequenceNumber = aevent->serial & 0xFFFF;
219 awire->subCode = aevent->subtype;
220 switch (aevent->subtype) {
221 case RRNotify_OutputChange: {
222 xRROutputChangeNotifyEvent *awire = (xRROutputChangeNotifyEvent *) wire;
223 XRROutputChangeNotifyEvent *aevent = (XRROutputChangeNotifyEvent *) event;
224 awire->window = aevent->window;
225 awire->output = aevent->output;
226 awire->crtc = aevent->crtc;
227 awire->mode = aevent->mode;
228 awire->rotation = aevent->rotation;
229 awire->connection = aevent->connection;
230 awire->subpixelOrder = aevent->subpixel_order;
233 case RRNotify_CrtcChange: {
234 xRRCrtcChangeNotifyEvent *awire = (xRRCrtcChangeNotifyEvent *) wire;
235 XRRCrtcChangeNotifyEvent *aevent = (XRRCrtcChangeNotifyEvent *) event;
236 awire->window = aevent->window;
237 awire->crtc = aevent->crtc;
238 awire->mode = aevent->mode;
239 awire->rotation = aevent->rotation;
240 awire->x = aevent->x;
241 awire->y = aevent->y;
242 awire->width = aevent->width;
243 awire->height = aevent->height;
246 case RRNotify_OutputProperty: {
247 xRROutputPropertyNotifyEvent *awire = (xRROutputPropertyNotifyEvent *) wire;
248 XRROutputPropertyNotifyEvent *aevent = (XRROutputPropertyNotifyEvent *) event;
249 awire->window = aevent->window;
250 awire->output = aevent->output;
251 awire->atom = aevent->property;
252 awire->timestamp = aevent->timestamp;
253 awire->state = aevent->state;
256 case RRNotify_ProviderChange: {
257 xRRProviderChangeNotifyEvent *awire = (xRRProviderChangeNotifyEvent *) wire;
258 XRRProviderChangeNotifyEvent *aevent = (XRRProviderChangeNotifyEvent *) event;
259 awire->window = aevent->window;
260 awire->provider = aevent->provider;
263 case RRNotify_ProviderProperty: {
264 xRRProviderPropertyNotifyEvent *awire = (xRRProviderPropertyNotifyEvent *) wire;
265 XRRProviderPropertyNotifyEvent *aevent = (XRRProviderPropertyNotifyEvent *) event;
266 awire->window = aevent->window;
267 awire->provider = aevent->provider;
268 awire->atom = aevent->property;
269 awire->timestamp = aevent->timestamp;
270 awire->state = aevent->state;
273 case RRNotify_ResourceChange: {
274 xRRResourceChangeNotifyEvent *awire = (xRRResourceChangeNotifyEvent *) wire;
275 XRRResourceChangeNotifyEvent *aevent = (XRRResourceChangeNotifyEvent *) event;
276 awire->window = aevent->window;
277 awire->timestamp = aevent->timestamp;
286 _X_HIDDEN XExtDisplayInfo *
287 XRRFindDisplay (Display *dpy)
289 XExtDisplayInfo *dpyinfo;
293 dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy);
295 dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy,
298 RRNumberEvents, NULL);
299 numscreens = ScreenCount(dpy);
300 xrri = Xmalloc (sizeof(XRandRInfo) +
301 sizeof(char *) * numscreens);
302 xrri->config = (XRRScreenConfiguration **)(xrri + 1);
303 for(i = 0; i < numscreens; i++)
304 xrri->config[i] = NULL;
305 xrri->major_version = -1;
306 dpyinfo->data = (char *) xrri;
312 XRRCloseDisplay (Display *dpy, XExtCodes *codes)
315 XRRScreenConfiguration **configs;
316 XExtDisplayInfo *info = XRRFindDisplay (dpy);
323 if (XextHasExtension(info)) {
324 xrri = (XRandRInfo *) info->data;
326 configs = xrri->config;
328 for (i = 0; i < ScreenCount(dpy); i++) {
329 if (configs[i] != NULL) XFree (configs[i]);
335 return XextRemoveDisplay (&XRRExtensionInfo, dpy);
338 int XRRRootToScreen(Display *dpy, Window root)
341 for (snum = 0; snum < ScreenCount(dpy); snum++) {
342 if (RootWindow(dpy, snum) == root) return snum;
348 Bool XRRQueryExtension (Display *dpy,
349 int *event_base_return,
350 int *error_base_return)
352 XExtDisplayInfo *info = XRRFindDisplay (dpy);
354 if (XextHasExtension(info)) {
355 *event_base_return = info->codes->first_event;
356 *error_base_return = info->codes->first_error;
364 _XRRHasRates (int major, int minor)
366 return major > 1 || (major == 1 && minor >= 1);
369 Status XRRQueryVersion (Display *dpy,
373 XExtDisplayInfo *info = XRRFindDisplay (dpy);
374 xRRQueryVersionReply rep;
375 xRRQueryVersionReq *req;
378 RRCheckExtension (dpy, info, 0);
380 xrri = (XRandRInfo *) info->data;
383 * only get the version information from the server if we don't have it already
385 if (xrri->major_version == -1) {
387 GetReq (RRQueryVersion, req);
388 req->reqType = info->codes->major_opcode;
389 req->randrReqType = X_RRQueryVersion;
390 req->majorVersion = RANDR_MAJOR;
391 req->minorVersion = RANDR_MINOR;
392 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
397 xrri->major_version = rep.majorVersion;
398 xrri->minor_version = rep.minorVersion;
399 xrri->has_rates = _XRRHasRates (xrri->major_version, xrri->minor_version);
403 *major_versionp = xrri->major_version;
404 *minor_versionp = xrri->minor_version;
409 _XRRVersionHandler (Display *dpy,
415 xRRQueryVersionReply replbuf;
416 xRRQueryVersionReply *repl;
417 _XRRVersionState *state = (_XRRVersionState *) data;
419 if (dpy->last_request_read != state->version_seq)
421 if (rep->generic.type == X_Error)
426 repl = (xRRQueryVersionReply *)
427 _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
428 (SIZEOF(xRRQueryVersionReply) - SIZEOF(xReply)) >> 2,
430 state->major_version = repl->majorVersion;
431 state->minor_version = repl->minorVersion;
436 * in protocol version 0.1, routine added to allow selecting for new events.
439 void XRRSelectInput (Display *dpy, Window window, int mask)
441 XExtDisplayInfo *info = XRRFindDisplay (dpy);
442 xRRSelectInputReq *req;
444 RRSimpleCheckExtension (dpy, info);
447 GetReq (RRSelectInput, req);
448 req->reqType = info->codes->major_opcode;
449 req->randrReqType = X_RRSelectInput;
450 req->window = window;
452 if (mask) req->enable = mask;
458 int XRRUpdateConfiguration(XEvent *event)
460 XRRScreenChangeNotifyEvent *scevent;
461 XConfigureEvent *rcevent;
462 Display *dpy = event->xany.display;
463 XExtDisplayInfo *info;
467 /* first, see if it is a vanilla configure notify event */
468 if (event->type == ConfigureNotify) {
469 rcevent = (XConfigureEvent *) event;
470 snum = XRRRootToScreen(dpy, rcevent->window);
472 dpy->screens[snum].width = rcevent->width;
473 dpy->screens[snum].height = rcevent->height;
478 info = XRRFindDisplay(dpy);
479 RRCheckExtension (dpy, info, 0);
481 switch (event->type - info->codes->first_event) {
482 case RRScreenChangeNotify:
483 scevent = (XRRScreenChangeNotifyEvent *) event;
484 snum = XRRRootToScreen(dpy,
485 ((XRRScreenChangeNotifyEvent *) event)->root);
486 if (scevent->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
487 dpy->screens[snum].width = scevent->height;
488 dpy->screens[snum].height = scevent->width;
489 dpy->screens[snum].mwidth = scevent->mheight;
490 dpy->screens[snum].mheight = scevent->mwidth;
492 dpy->screens[snum].width = scevent->width;
493 dpy->screens[snum].height = scevent->height;
494 dpy->screens[snum].mwidth = scevent->mwidth;
495 dpy->screens[snum].mheight = scevent->mheight;
497 XRenderSetSubpixelOrder (dpy, snum, scevent->subpixel_order);
502 xrri = (XRandRInfo *) info->data;
504 * so the next time someone wants some data, it will be fetched;
505 * it might be better to force the round trip immediately, but
506 * I dislike pounding the server simultaneously when not necessary
508 if (xrri->config[snum] != NULL) {
509 XFree (xrri->config[snum]);
510 xrri->config[snum] = NULL;