1 /*
2 * Copyright © 2000 Compaq Computer Corporation, Inc.
3 * Copyright © 2002 Hewlett Packard Company, Inc.
4 * Copyright © 2006 Keith Packard
5 *
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.
15 *
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
22 * OF THIS SOFTWARE.
23 *
24 * Author: Jim Gettys, HP Labs, HP.
25 * Author: Keith Packard, Intel Corporation
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include <limits.h>
33 #include <stdio.h>
34 #include <X11/Xlib.h>
35 /* we need to be able to manipulate the Display structure on events */
36 #include <X11/Xlibint.h>
37 #include <X11/extensions/render.h>
38 #include <X11/extensions/Xrender.h>
39 #include "Xrandrint.h"
40
41 static XRRScreenConfiguration *_XRRGetScreenInfo (Display *dpy,
42 XExtDisplayInfo *info,
43 Window window);
44
XRRConfigRotations(XRRScreenConfiguration * config,Rotation * current_rotation)45 Rotation XRRConfigRotations(XRRScreenConfiguration *config, Rotation *current_rotation)
46 {
47 *current_rotation = config->current_rotation;
48 return config->rotations;
49 }
50
XRRConfigSizes(XRRScreenConfiguration * config,int * nsizes)51 XRRScreenSize *XRRConfigSizes(XRRScreenConfiguration *config, int *nsizes)
52 {
53 *nsizes = config->nsizes;
54 return config->sizes;
55 }
56
XRRConfigRates(XRRScreenConfiguration * config,int sizeID,int * nrates)57 short *XRRConfigRates (XRRScreenConfiguration *config, int sizeID, int *nrates)
58 {
59 short *r = config->rates;
60 int nents = config->nrates;
61
62 /* Skip over the intervening rate lists */
63 while (sizeID > 0 && nents > 0)
64 {
65 int i = (*r + 1);
66 r += i;
67 nents -= i;
68 sizeID--;
69 }
70 if (!nents)
71 {
72 *nrates = 0;
73 return NULL;
74 }
75 *nrates = (int) *r;
76 return r + 1;
77 }
78
XRRConfigTimes(XRRScreenConfiguration * config,Time * config_timestamp)79 Time XRRConfigTimes (XRRScreenConfiguration *config, Time *config_timestamp)
80 {
81 *config_timestamp = config->config_timestamp;
82 return config->timestamp;
83 }
84
85
XRRConfigCurrentConfiguration(XRRScreenConfiguration * config,Rotation * rotation)86 SizeID XRRConfigCurrentConfiguration (XRRScreenConfiguration *config,
87 Rotation *rotation)
88 {
89 *rotation = (Rotation) config->current_rotation;
90 return (SizeID) config->current_size;
91 }
92
XRRConfigCurrentRate(XRRScreenConfiguration * config)93 short XRRConfigCurrentRate (XRRScreenConfiguration *config)
94 {
95 return config->current_rate;
96 }
97
98 /*
99 * Go get the screen configuration data and salt it away for future use;
100 * returns NULL if extension not supported
101 */
_XRRValidateCache(Display * dpy,XExtDisplayInfo * info,int screen)102 static XRRScreenConfiguration *_XRRValidateCache (Display *dpy,
103 XExtDisplayInfo *info,
104 int screen)
105 {
106 XRRScreenConfiguration **configs;
107 XRandRInfo *xrri;
108
109 if ((screen >= 0) && (screen < ScreenCount(dpy)) && XextHasExtension(info)) {
110 xrri = (XRandRInfo *) info->data;
111 configs = xrri->config;
112
113 if (configs[screen] == NULL)
114 configs[screen] = _XRRGetScreenInfo (dpy, info, RootWindow(dpy, screen));
115 return configs[screen];
116 } else {
117 return NULL;
118 }
119 }
120
121 /* given a screen, return the information from the (possibly) cached data */
XRRRotations(Display * dpy,int screen,Rotation * current_rotation)122 Rotation XRRRotations(Display *dpy, int screen, Rotation *current_rotation)
123 {
124 XRRScreenConfiguration *config;
125 XExtDisplayInfo *info = XRRFindDisplay(dpy);
126 Rotation cr;
127 LockDisplay(dpy);
128 if ((config = _XRRValidateCache(dpy, info, screen))) {
129 *current_rotation = config->current_rotation;
130 cr = config->rotations;
131 UnlockDisplay(dpy);
132 return cr;
133 }
134 else {
135 UnlockDisplay(dpy);
136 *current_rotation = RR_Rotate_0;
137 return 0; /* no rotations supported */
138 }
139 }
140
141 /* given a screen, return the information from the (possibly) cached data */
XRRSizes(Display * dpy,int screen,int * nsizes)142 XRRScreenSize *XRRSizes(Display *dpy, int screen, int *nsizes)
143 {
144 XRRScreenConfiguration *config;
145 XExtDisplayInfo *info = XRRFindDisplay(dpy);
146 XRRScreenSize *sizes;
147
148 LockDisplay(dpy);
149 if ((config = _XRRValidateCache(dpy, info, screen))) {
150 *nsizes = config->nsizes;
151 sizes = config->sizes;
152 UnlockDisplay(dpy);
153 return sizes;
154 }
155 else {
156 UnlockDisplay(dpy);
157 *nsizes = 0;
158 return NULL;
159 }
160 }
161
XRRRates(Display * dpy,int screen,int sizeID,int * nrates)162 short *XRRRates (Display *dpy, int screen, int sizeID, int *nrates)
163 {
164 XRRScreenConfiguration *config;
165 XExtDisplayInfo *info = XRRFindDisplay(dpy);
166 short *rates;
167
168 LockDisplay(dpy);
169 if ((config = _XRRValidateCache(dpy, info, screen))) {
170 rates = XRRConfigRates (config, sizeID, nrates);
171 UnlockDisplay(dpy);
172 return rates;
173 }
174 else {
175 UnlockDisplay(dpy);
176 *nrates = 0;
177 return NULL;
178 }
179 }
180
181 /* given a screen, return the information from the (possibly) cached data */
XRRTimes(Display * dpy,int screen,Time * config_timestamp)182 Time XRRTimes (Display *dpy, int screen, Time *config_timestamp)
183 {
184 XRRScreenConfiguration *config;
185 XExtDisplayInfo *info = XRRFindDisplay(dpy);
186 Time ts;
187
188 LockDisplay(dpy);
189 if ((config = _XRRValidateCache(dpy, info, screen))) {
190 *config_timestamp = config->config_timestamp;
191 ts = config->timestamp;
192 UnlockDisplay(dpy);
193 return ts;
194 } else {
195 UnlockDisplay(dpy);
196 return CurrentTime;
197 }
198 }
199
200 /* need a version that does not hold the display lock */
_XRRGetScreenInfo(Display * dpy,XExtDisplayInfo * info,Window window)201 static XRRScreenConfiguration *_XRRGetScreenInfo (Display *dpy,
202 XExtDisplayInfo *info,
203 Window window)
204 {
205 xRRGetScreenInfoReply rep;
206 xRRGetScreenInfoReq *req;
207 _XAsyncHandler async;
208 _XRRVersionState async_state;
209 int nbytes, nbytesRead, rbytes;
210 int i;
211 xScreenSizes size;
212 struct _XRRScreenConfiguration *scp;
213 XRRScreenSize *ssp;
214 short *rates;
215 xRRQueryVersionReq *vreq;
216 XRandRInfo *xrri;
217 Bool getting_version = False;
218
219 xrri = (XRandRInfo *) info->data;
220 if (!xrri)
221 return NULL;
222
223 if (xrri->major_version == -1)
224 {
225 /* hide a version query in the request */
226 GetReq (RRQueryVersion, vreq);
227 vreq->reqType = info->codes->major_opcode;
228 vreq->randrReqType = X_RRQueryVersion;
229 vreq->majorVersion = RANDR_MAJOR;
230 vreq->minorVersion = RANDR_MINOR;
231
232 async_state.version_seq = dpy->request;
233 async_state.error = False;
234 async.next = dpy->async_handlers;
235 async.handler = _XRRVersionHandler;
236 async.data = (XPointer) &async_state;
237 dpy->async_handlers = &async;
238
239 getting_version = True;
240 }
241
242 GetReq (RRGetScreenInfo, req);
243 req->reqType = info->codes->major_opcode;
244 req->randrReqType = X_RRGetScreenInfo;
245 req->window = window;
246
247 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
248 {
249 if (getting_version)
250 DeqAsyncHandler (dpy, &async);
251 SyncHandle ();
252 return NULL;
253 }
254 if (getting_version)
255 {
256 DeqAsyncHandler (dpy, &async);
257 if (async_state.error)
258 {
259 UnlockDisplay (dpy);
260 SyncHandle();
261 LockDisplay (dpy);
262 }
263 xrri->major_version = async_state.major_version;
264 xrri->minor_version = async_state.minor_version;
265 xrri->has_rates = _XRRHasRates (xrri->minor_version, xrri->major_version);
266 }
267
268 /*
269 * Make the reply compatible with v1.1
270 */
271 if (!xrri->has_rates)
272 {
273 rep.rate = 0;
274 rep.nrateEnts = 0;
275 }
276 if (rep.length < INT_MAX >> 2) {
277 nbytes = (long) rep.length << 2;
278
279 nbytesRead = (long) (rep.nSizes * SIZEOF (xScreenSizes) +
280 ((rep.nrateEnts + 1)& ~1) * 2 /* SIZEOF(CARD16) */);
281
282 /*
283 * first we must compute how much space to allocate for
284 * randr library's use; we'll allocate the structures in a single
285 * allocation, on cleanlyness grounds.
286 */
287
288 rbytes = sizeof (XRRScreenConfiguration) +
289 (rep.nSizes * sizeof (XRRScreenSize) +
290 rep.nrateEnts * sizeof (int));
291
292 scp = (struct _XRRScreenConfiguration *) Xmalloc(rbytes);
293 } else {
294 nbytes = 0;
295 nbytesRead = 0;
296 rbytes = 0;
297 scp = NULL;
298 }
299
300 if (scp == NULL) {
301 _XEatData (dpy, (unsigned long) nbytes);
302 return NULL;
303 }
304
305
306 ssp = (XRRScreenSize *)(scp + 1);
307 rates = (short *) (ssp + rep.nSizes);
308
309 /* set up the screen configuration structure */
310 scp->screen =
311 ScreenOfDisplay (dpy, XRRRootToScreen(dpy, rep.root));
312
313 scp->sizes = ssp;
314 scp->rates = rates;
315 scp->rotations = rep.setOfRotations;
316 scp->current_size = rep.sizeID;
317 scp->current_rate = rep.rate;
318 scp->current_rotation = rep.rotation;
319 scp->timestamp = rep.timestamp;
320 scp->config_timestamp = rep.configTimestamp;
321 scp->nsizes = rep.nSizes;
322 scp->nrates = rep.nrateEnts;
323
324 /*
325 * Time to unpack the data from the server.
326 */
327
328 /*
329 * First the size information
330 */
331 for (i = 0; i < rep.nSizes; i++) {
332 _XReadPad (dpy, (char *) &size, SIZEOF (xScreenSizes));
333
334 ssp[i].width = size.widthInPixels;
335 ssp[i].height = size.heightInPixels;
336 ssp[i].mwidth = size.widthInMillimeters;
337 ssp[i].mheight = size.heightInMillimeters;
338 }
339 /*
340 * And the rates
341 */
342 _XRead16Pad (dpy, rates, 2 /* SIZEOF (CARD16) */ * rep.nrateEnts);
343
344 /*
345 * Skip any extra data
346 */
347 if (nbytes > nbytesRead)
348 _XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
349
350 return (XRRScreenConfiguration *)(scp);
351 }
352
XRRGetScreenInfo(Display * dpy,Window window)353 XRRScreenConfiguration *XRRGetScreenInfo (Display *dpy, Window window)
354 {
355 XRRScreenConfiguration *config;
356 XExtDisplayInfo *info = XRRFindDisplay(dpy);
357 XRRFindDisplay(dpy);
358 LockDisplay (dpy);
359 config = _XRRGetScreenInfo(dpy, info, window);
360 UnlockDisplay (dpy);
361 SyncHandle ();
362 return config;
363 }
364
365
XRRFreeScreenConfigInfo(XRRScreenConfiguration * config)366 void XRRFreeScreenConfigInfo (XRRScreenConfiguration *config)
367 {
368 Xfree (config);
369 }
370
XRRSetScreenConfigAndRate(Display * dpy,XRRScreenConfiguration * config,Drawable draw,int size_index,Rotation rotation,short rate,Time timestamp)371 Status XRRSetScreenConfigAndRate (Display *dpy,
372 XRRScreenConfiguration *config,
373 Drawable draw,
374 int size_index,
375 Rotation rotation,
376 short rate,
377 Time timestamp)
378 {
379 XExtDisplayInfo *info = XRRFindDisplay (dpy);
380 xRRSetScreenConfigReply rep;
381 XRandRInfo *xrri;
382 int major, minor;
383
384 RRCheckExtension (dpy, info, 0);
385
386 /* Make sure has_rates is set */
387 if (!XRRQueryVersion (dpy, &major, &minor))
388 return 0;
389
390 LockDisplay (dpy);
391 xrri = (XRandRInfo *) info->data;
392 if (xrri->has_rates)
393 {
394 xRRSetScreenConfigReq *req;
395 GetReq (RRSetScreenConfig, req);
396 req->reqType = info->codes->major_opcode;
397 req->randrReqType = X_RRSetScreenConfig;
398 req->drawable = draw;
399 req->sizeID = size_index;
400 req->rotation = rotation;
401 req->timestamp = timestamp;
402 req->configTimestamp = config->config_timestamp;
403 req->rate = rate;
404 }
405 else
406 {
407 xRR1_0SetScreenConfigReq *req;
408 GetReq (RR1_0SetScreenConfig, req);
409 req->reqType = info->codes->major_opcode;
410 req->randrReqType = X_RRSetScreenConfig;
411 req->drawable = draw;
412 req->sizeID = size_index;
413 req->rotation = rotation;
414 req->timestamp = timestamp;
415 req->configTimestamp = config->config_timestamp;
416 }
417
418 (void) _XReply (dpy, (xReply *) &rep, 0, xTrue);
419
420 /* actually .errorCode in struct xError */
421 if (rep.status == RRSetConfigSuccess) {
422 /* if we succeed, set our view of reality to what we set it to */
423 config->config_timestamp = rep.newConfigTimestamp;
424 config->timestamp = rep.newTimestamp;
425 config->screen = ScreenOfDisplay (dpy, XRRRootToScreen(dpy, rep.root));
426 config->current_size = size_index;
427 config->current_rotation = rotation;
428 }
429 UnlockDisplay (dpy);
430 SyncHandle ();
431 return(rep.status);
432 }
433
XRRSetScreenConfig(Display * dpy,XRRScreenConfiguration * config,Drawable draw,int size_index,Rotation rotation,Time timestamp)434 Status XRRSetScreenConfig (Display *dpy,
435 XRRScreenConfiguration *config,
436 Drawable draw,
437 int size_index,
438 Rotation rotation, Time timestamp)
439 {
440 return XRRSetScreenConfigAndRate (dpy, config, draw, size_index,
441 rotation, 0, timestamp);
442 }
443