2 * Copyright © 2000 Compaq Computer Corporation, Inc.
3 * Copyright © 2002 Hewlett Packard Company, Inc.
4 * Copyright © 2006 Keith Packard
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that copyright
9 * notice and this permission notice appear in supporting documentation, and
10 * that the name of the copyright holders not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. The copyright holders make no representations
13 * about the suitability of this software for any purpose. It is provided "as
14 * is" without express or implied warranty.
16 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * Author: Jim Gettys, HP Labs, HP.
25 * Author: Keith Packard, Intel Corporation
34 /* we need to be able to manipulate the Display structure on events */
35 #include <X11/Xlibint.h>
36 #include <X11/extensions/render.h>
37 #include <X11/extensions/Xrender.h>
38 #include "Xrandrint.h"
40 static XRRScreenConfiguration *_XRRGetScreenInfo (Display *dpy,
41 XExtDisplayInfo *info,
44 Rotation XRRConfigRotations(XRRScreenConfiguration *config, Rotation *current_rotation)
46 *current_rotation = config->current_rotation;
47 return config->rotations;
50 XRRScreenSize *XRRConfigSizes(XRRScreenConfiguration *config, int *nsizes)
52 *nsizes = config->nsizes;
56 short *XRRConfigRates (XRRScreenConfiguration *config, int sizeID, int *nrates)
58 short *r = config->rates;
59 int nents = config->nrates;
61 /* Skip over the intervening rate lists */
62 while (sizeID > 0 && nents > 0)
78 Time XRRConfigTimes (XRRScreenConfiguration *config, Time *config_timestamp)
80 *config_timestamp = config->config_timestamp;
81 return config->timestamp;
85 SizeID XRRConfigCurrentConfiguration (XRRScreenConfiguration *config,
88 *rotation = (Rotation) config->current_rotation;
89 return (SizeID) config->current_size;
92 short XRRConfigCurrentRate (XRRScreenConfiguration *config)
94 return config->current_rate;
98 * Go get the screen configuration data and salt it away for future use;
99 * returns NULL if extension not supported
101 static XRRScreenConfiguration *_XRRValidateCache (Display *dpy,
102 XExtDisplayInfo *info,
105 XRRScreenConfiguration **configs;
108 if ((screen >= 0) && (screen < ScreenCount(dpy)) && XextHasExtension(info)) {
109 xrri = (XRandRInfo *) info->data;
110 configs = xrri->config;
112 if (configs[screen] == NULL)
113 configs[screen] = _XRRGetScreenInfo (dpy, info, RootWindow(dpy, screen));
114 return configs[screen];
120 /* given a screen, return the information from the (possibly) cached data */
121 Rotation XRRRotations(Display *dpy, int screen, Rotation *current_rotation)
123 XRRScreenConfiguration *config;
124 XExtDisplayInfo *info = XRRFindDisplay(dpy);
127 if ((config = _XRRValidateCache(dpy, info, screen))) {
128 *current_rotation = config->current_rotation;
129 cr = config->rotations;
135 *current_rotation = RR_Rotate_0;
136 return 0; /* no rotations supported */
140 /* given a screen, return the information from the (possibly) cached data */
141 XRRScreenSize *XRRSizes(Display *dpy, int screen, int *nsizes)
143 XRRScreenConfiguration *config;
144 XExtDisplayInfo *info = XRRFindDisplay(dpy);
145 XRRScreenSize *sizes;
148 if ((config = _XRRValidateCache(dpy, info, screen))) {
149 *nsizes = config->nsizes;
150 sizes = config->sizes;
161 short *XRRRates (Display *dpy, int screen, int sizeID, int *nrates)
163 XRRScreenConfiguration *config;
164 XExtDisplayInfo *info = XRRFindDisplay(dpy);
168 if ((config = _XRRValidateCache(dpy, info, screen))) {
169 rates = XRRConfigRates (config, sizeID, nrates);
180 /* given a screen, return the information from the (possibly) cached data */
181 Time XRRTimes (Display *dpy, int screen, Time *config_timestamp)
183 XRRScreenConfiguration *config;
184 XExtDisplayInfo *info = XRRFindDisplay(dpy);
188 if ((config = _XRRValidateCache(dpy, info, screen))) {
189 *config_timestamp = config->config_timestamp;
190 ts = config->timestamp;
199 /* need a version that does not hold the display lock */
200 static XRRScreenConfiguration *_XRRGetScreenInfo (Display *dpy,
201 XExtDisplayInfo *info,
204 xRRGetScreenInfoReply rep;
205 xRRGetScreenInfoReq *req;
206 _XAsyncHandler async;
207 _XRRVersionState async_state;
208 int nbytes, nbytesRead, rbytes;
211 struct _XRRScreenConfiguration *scp;
214 xRRQueryVersionReq *vreq;
216 Bool getting_version = False;
218 xrri = (XRandRInfo *) info->data;
222 if (xrri->major_version == -1)
224 /* hide a version query in the request */
225 GetReq (RRQueryVersion, vreq);
226 vreq->reqType = info->codes->major_opcode;
227 vreq->randrReqType = X_RRQueryVersion;
228 vreq->majorVersion = RANDR_MAJOR;
229 vreq->minorVersion = RANDR_MINOR;
231 async_state.version_seq = dpy->request;
232 async_state.error = False;
233 async.next = dpy->async_handlers;
234 async.handler = _XRRVersionHandler;
235 async.data = (XPointer) &async_state;
236 dpy->async_handlers = &async;
238 getting_version = True;
241 GetReq (RRGetScreenInfo, req);
242 req->reqType = info->codes->major_opcode;
243 req->randrReqType = X_RRGetScreenInfo;
244 req->window = window;
246 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
249 DeqAsyncHandler (dpy, &async);
255 DeqAsyncHandler (dpy, &async);
256 if (async_state.error)
262 xrri->major_version = async_state.major_version;
263 xrri->minor_version = async_state.minor_version;
264 xrri->has_rates = _XRRHasRates (xrri->minor_version, xrri->major_version);
268 * Make the reply compatible with v1.1
270 if (!xrri->has_rates)
276 nbytes = (long) rep.length << 2;
278 nbytesRead = (long) (rep.nSizes * SIZEOF (xScreenSizes) +
279 ((rep.nrateEnts + 1)& ~1) * 2 /* SIZEOF (CARD16) */);
282 * first we must compute how much space to allocate for
283 * randr library's use; we'll allocate the structures in a single
284 * allocation, on cleanlyness grounds.
287 rbytes = sizeof (XRRScreenConfiguration) +
288 (rep.nSizes * sizeof (XRRScreenSize) +
289 rep.nrateEnts * sizeof (int));
291 scp = (struct _XRRScreenConfiguration *) Xmalloc(rbytes);
293 _XEatData (dpy, (unsigned long) nbytes);
298 ssp = (XRRScreenSize *)(scp + 1);
299 rates = (short *) (ssp + rep.nSizes);
301 /* set up the screen configuration structure */
303 ScreenOfDisplay (dpy, XRRRootToScreen(dpy, rep.root));
307 scp->rotations = rep.setOfRotations;
308 scp->current_size = rep.sizeID;
309 scp->current_rate = rep.rate;
310 scp->current_rotation = rep.rotation;
311 scp->timestamp = rep.timestamp;
312 scp->config_timestamp = rep.configTimestamp;
313 scp->nsizes = rep.nSizes;
314 scp->nrates = rep.nrateEnts;
317 * Time to unpack the data from the server.
321 * First the size information
323 for (i = 0; i < rep.nSizes; i++) {
324 _XReadPad (dpy, (char *) &size, SIZEOF (xScreenSizes));
326 ssp[i].width = size.widthInPixels;
327 ssp[i].height = size.heightInPixels;
328 ssp[i].mwidth = size.widthInMillimeters;
329 ssp[i].mheight = size.heightInMillimeters;
334 _XRead16Pad (dpy, rates, 2 /* SIZEOF (CARD16) */ * rep.nrateEnts);
337 * Skip any extra data
339 if (nbytes > nbytesRead)
340 _XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
342 return (XRRScreenConfiguration *)(scp);
345 XRRScreenConfiguration *XRRGetScreenInfo (Display *dpy, Window window)
347 XRRScreenConfiguration *config;
348 XExtDisplayInfo *info = XRRFindDisplay(dpy);
351 config = _XRRGetScreenInfo(dpy, info, window);
358 void XRRFreeScreenConfigInfo (XRRScreenConfiguration *config)
363 Status XRRSetScreenConfigAndRate (Display *dpy,
364 XRRScreenConfiguration *config,
371 XExtDisplayInfo *info = XRRFindDisplay (dpy);
372 xRRSetScreenConfigReply rep;
376 RRCheckExtension (dpy, info, 0);
378 /* Make sure has_rates is set */
379 if (!XRRQueryVersion (dpy, &major, &minor))
383 xrri = (XRandRInfo *) info->data;
386 xRRSetScreenConfigReq *req;
387 GetReq (RRSetScreenConfig, req);
388 req->reqType = info->codes->major_opcode;
389 req->randrReqType = X_RRSetScreenConfig;
390 req->drawable = draw;
391 req->sizeID = size_index;
392 req->rotation = rotation;
393 req->timestamp = timestamp;
394 req->configTimestamp = config->config_timestamp;
399 xRR1_0SetScreenConfigReq *req;
400 GetReq (RR1_0SetScreenConfig, req);
401 req->reqType = info->codes->major_opcode;
402 req->randrReqType = X_RRSetScreenConfig;
403 req->drawable = draw;
404 req->sizeID = size_index;
405 req->rotation = rotation;
406 req->timestamp = timestamp;
407 req->configTimestamp = config->config_timestamp;
410 (void) _XReply (dpy, (xReply *) &rep, 0, xTrue);
412 /* actually .errorCode in struct xError */
413 if (rep.status == RRSetConfigSuccess) {
414 /* if we succeed, set our view of reality to what we set it to */
415 config->config_timestamp = rep.newConfigTimestamp;
416 config->timestamp = rep.newTimestamp;
417 config->screen = ScreenOfDisplay (dpy, XRRRootToScreen(dpy, rep.root));
418 config->current_size = size_index;
419 config->current_rotation = rotation;
426 Status XRRSetScreenConfig (Display *dpy,
427 XRRScreenConfiguration *config,
430 Rotation rotation, Time timestamp)
432 return XRRSetScreenConfigAndRate (dpy, config, draw, size_index,
433 rotation, 0, timestamp);