upgrade for xorg-server 1.12.99.905 (for 1.13 RC)
[framework/uifw/xorg/lib/libxrandr.git] / src / Xrandr.c
1 /*
2  * Copyright © 2000 Compaq Computer Corporation, Inc.
3  * Copyright © 2002 Hewlett Packard Company, Inc.
4  *
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.
14  *
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.
21  *
22  * Author:  Jim Gettys, HP Labs, HP.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <X11/Xlib.h>
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"
36
37 static XExtensionInfo XRRExtensionInfo;
38 _X_HIDDEN char XRRExtensionName[] = RANDR_NAME;
39
40 static Bool     XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
41 static Status   XRREventToWire(Display *dpy, XEvent *event, xEvent *wire);
42
43 static int
44 XRRCloseDisplay (Display *dpy, XExtCodes *codes);
45
46 static /* const */ XExtensionHooks rr_extension_hooks = {
47     NULL,                               /* create_gc */
48     NULL,                               /* copy_gc */
49     NULL,                               /* flush_gc */
50     NULL,                               /* free_gc */
51     NULL,                               /* create_font */
52     NULL,                               /* free_font */
53     XRRCloseDisplay,                    /* close_display */
54     XRRWireToEvent,                     /* wire_to_event */
55     XRREventToWire,                     /* event_to_wire */
56     NULL,                               /* error */
57     NULL,                               /* error_string */
58 };
59
60 static Bool XRRWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
61 {
62     XExtDisplayInfo *info = XRRFindDisplay(dpy);
63
64     RRCheckExtension(dpy, info, False);
65
66     switch ((wire->u.u.type & 0x7F) - info->codes->first_event)
67     {
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;
86         return True;
87       }
88       case RRNotify: {
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;
105             return True;
106         }
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;
123             return True;
124         }
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;
138             return True;
139         }
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;
151             return True;
152         }
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;
166             return True;
167         }
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;
178             return True;
179         }
180             break;
181         }
182       }
183     }
184
185     return False;
186 }
187
188 static Status XRREventToWire(Display *dpy, XEvent *event, xEvent *wire)
189 {
190     XExtDisplayInfo *info = XRRFindDisplay(dpy);
191
192     RRCheckExtension(dpy, info, False);
193
194     switch ((event->type & 0x7F) - info->codes->first_event)
195     {
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;
212         return True;
213       }
214       case RRNotify: {
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;
231             return True;
232         }
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;
244             return True;
245         }
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;
254             return True;
255         }
256         case RRNotify_ProviderChange: {
257             xRRProviderChangeNotifyEvent *awire = (xRRProviderChangeNotifyEvent *) wire;
258             XRRProviderChangeNotifyEvent *aevent = (XRRProviderChangeNotifyEvent *) event;
259             awire->window = aevent->window;
260             awire->provider = aevent->provider;
261             return True;
262         }
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;
271             return True;
272         }
273         case RRNotify_ResourceChange: {
274             xRRResourceChangeNotifyEvent *awire = (xRRResourceChangeNotifyEvent *) wire;
275             XRRResourceChangeNotifyEvent *aevent = (XRRResourceChangeNotifyEvent *) event;
276             awire->window = aevent->window;
277             awire->timestamp = aevent->timestamp;
278             return True;
279         }
280         }
281       }
282     }
283     return False;
284 }
285
286 _X_HIDDEN XExtDisplayInfo *
287 XRRFindDisplay (Display *dpy)
288 {
289     XExtDisplayInfo *dpyinfo;
290     XRandRInfo *xrri;
291     int i, numscreens;
292
293     dpyinfo = XextFindDisplay (&XRRExtensionInfo, dpy);
294     if (!dpyinfo) {
295         dpyinfo = XextAddDisplay (&XRRExtensionInfo, dpy,
296                                   XRRExtensionName,
297                                   &rr_extension_hooks,
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;
307     }
308     return dpyinfo;
309 }
310
311 static int
312 XRRCloseDisplay (Display *dpy, XExtCodes *codes)
313 {
314     int i;
315     XRRScreenConfiguration **configs;
316     XExtDisplayInfo *info = XRRFindDisplay (dpy);
317     XRandRInfo *xrri;
318
319     LockDisplay(dpy);
320     /*
321      * free cached data
322      */
323     if (XextHasExtension(info)) {
324         xrri = (XRandRInfo *) info->data;
325         if (xrri) {
326             configs = xrri->config;
327
328             for (i = 0; i < ScreenCount(dpy); i++) {
329                 if (configs[i] != NULL) XFree (configs[i]);
330             }
331             XFree (xrri);
332         }
333     }
334     UnlockDisplay(dpy);
335     return XextRemoveDisplay (&XRRExtensionInfo, dpy);
336 }
337
338 int XRRRootToScreen(Display *dpy, Window root)
339 {
340   int snum;
341   for (snum = 0; snum < ScreenCount(dpy); snum++) {
342     if (RootWindow(dpy, snum) == root) return snum;
343   }
344   return -1;
345 }
346
347
348 Bool XRRQueryExtension (Display *dpy,
349                         int *event_base_return,
350                         int *error_base_return)
351 {
352   XExtDisplayInfo *info = XRRFindDisplay (dpy);
353
354     if (XextHasExtension(info)) {
355         *event_base_return = info->codes->first_event;
356         *error_base_return = info->codes->first_error;
357         return True;
358     } else {
359         return False;
360     }
361 }
362
363 _X_HIDDEN Bool
364 _XRRHasRates (int major, int minor)
365 {
366     return major > 1 || (major == 1 && minor >= 1);
367 }
368
369 Status XRRQueryVersion (Display *dpy,
370                             int     *major_versionp,
371                             int     *minor_versionp)
372 {
373     XExtDisplayInfo *info = XRRFindDisplay (dpy);
374     xRRQueryVersionReply rep;
375     xRRQueryVersionReq  *req;
376     XRandRInfo *xrri;
377
378     RRCheckExtension (dpy, info, 0);
379
380     xrri = (XRandRInfo *) info->data;
381
382     /*
383      * only get the version information from the server if we don't have it already
384      */
385     if (xrri->major_version == -1) {
386       LockDisplay (dpy);
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)) {
393         UnlockDisplay (dpy);
394         SyncHandle ();
395         return 0;
396       }
397       xrri->major_version = rep.majorVersion;
398       xrri->minor_version = rep.minorVersion;
399       xrri->has_rates = _XRRHasRates (xrri->major_version, xrri->minor_version);
400       UnlockDisplay (dpy);
401       SyncHandle ();
402     }
403     *major_versionp = xrri->major_version;
404     *minor_versionp = xrri->minor_version;
405     return 1;
406 }
407
408 _X_HIDDEN Bool
409 _XRRVersionHandler (Display         *dpy,
410                         xReply      *rep,
411                         char        *buf,
412                         int         len,
413                         XPointer    data)
414 {
415     xRRQueryVersionReply        replbuf;
416     xRRQueryVersionReply        *repl;
417     _XRRVersionState    *state = (_XRRVersionState *) data;
418
419     if (dpy->last_request_read != state->version_seq)
420         return False;
421     if (rep->generic.type == X_Error)
422     {
423         state->error = True;
424         return False;
425     }
426     repl = (xRRQueryVersionReply *)
427         _XGetAsyncReply(dpy, (char *)&replbuf, rep, buf, len,
428                      (SIZEOF(xRRQueryVersionReply) - SIZEOF(xReply)) >> 2,
429                         True);
430     state->major_version = repl->majorVersion;
431     state->minor_version = repl->minorVersion;
432     return True;
433 }
434
435 /*
436  * in protocol version 0.1, routine added to allow selecting for new events.
437  */
438
439 void XRRSelectInput (Display *dpy, Window window, int mask)
440 {
441     XExtDisplayInfo *info = XRRFindDisplay (dpy);
442     xRRSelectInputReq  *req;
443
444     RRSimpleCheckExtension (dpy, info);
445
446     LockDisplay (dpy);
447     GetReq (RRSelectInput, req);
448     req->reqType = info->codes->major_opcode;
449     req->randrReqType = X_RRSelectInput;
450     req->window = window;
451     req->enable = 0;
452     if (mask) req->enable = mask;
453     UnlockDisplay (dpy);
454     SyncHandle ();
455     return;
456 }
457
458 int XRRUpdateConfiguration(XEvent *event)
459 {
460     XRRScreenChangeNotifyEvent *scevent;
461     XConfigureEvent *rcevent;
462     Display *dpy = event->xany.display;
463     XExtDisplayInfo *info;
464     XRandRInfo *xrri;
465     int snum;
466
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);
471         if (snum != -1) {
472             dpy->screens[snum].width   = rcevent->width;
473             dpy->screens[snum].height  = rcevent->height;
474             return 1;
475         }
476     }
477
478     info = XRRFindDisplay(dpy);
479     RRCheckExtension (dpy, info, 0);
480
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;
491         } else {
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;
496         }
497         XRenderSetSubpixelOrder (dpy, snum, scevent->subpixel_order);
498         break;
499     default:
500         return 0;
501     }
502     xrri = (XRandRInfo *) info->data;
503     /*
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
507      */
508     if (xrri->config[snum] != NULL) {
509         XFree (xrri->config[snum]);
510         xrri->config[snum] = NULL;
511     }
512     return 1;
513 }