1 /*
2 * Copyright © 2006 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <limits.h>
28 #include <stdio.h>
29 #include <X11/Xlib.h>
30 /* we need to be able to manipulate the Display structure on events */
31 #include <X11/Xlibint.h>
32 #include <X11/extensions/render.h>
33 #include <X11/extensions/Xrender.h>
34 #include "Xrandrint.h"
35
36 XRRCrtcInfo *
XRRGetCrtcInfo(Display * dpy,XRRScreenResources * resources,RRCrtc crtc)37 XRRGetCrtcInfo (Display *dpy, XRRScreenResources *resources, RRCrtc crtc)
38 {
39 XExtDisplayInfo *info = XRRFindDisplay(dpy);
40 xRRGetCrtcInfoReply rep;
41 xRRGetCrtcInfoReq *req;
42 int nbytes, nbytesRead, rbytes;
43 XRRCrtcInfo *xci;
44
45 RRCheckExtension (dpy, info, NULL);
46
47 LockDisplay (dpy);
48 GetReq (RRGetCrtcInfo, req);
49 req->reqType = info->codes->major_opcode;
50 req->randrReqType = X_RRGetCrtcInfo;
51 req->crtc = crtc;
52 req->configTimestamp = resources->configTimestamp;
53
54 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
55 {
56 UnlockDisplay (dpy);
57 SyncHandle ();
58 return NULL;
59 }
60
61 if (rep.length < INT_MAX >> 2)
62 {
63 nbytes = (long) rep.length << 2;
64
65 nbytesRead = (long) (rep.nOutput * 4 +
66 rep.nPossibleOutput * 4);
67
68 /*
69 * first we must compute how much space to allocate for
70 * randr library's use; we'll allocate the structures in a single
71 * allocation, on cleanlyness grounds.
72 */
73
74 rbytes = (sizeof (XRRCrtcInfo) +
75 rep.nOutput * sizeof (RROutput) +
76 rep.nPossibleOutput * sizeof (RROutput));
77
78 xci = (XRRCrtcInfo *) Xmalloc(rbytes);
79 }
80 else
81 {
82 nbytes = 0;
83 nbytesRead = 0;
84 rbytes = 0;
85 xci = NULL;
86 }
87
88 if (xci == NULL) {
89 _XEatDataWords (dpy, rep.length);
90 UnlockDisplay (dpy);
91 SyncHandle ();
92 return NULL;
93 }
94
95 xci->timestamp = rep.timestamp;
96 xci->x = rep.x;
97 xci->y = rep.y;
98 xci->width = rep.width;
99 xci->height = rep.height;
100 xci->mode = rep.mode;
101 xci->rotation = rep.rotation;
102 xci->noutput = rep.nOutput;
103 xci->outputs = (RROutput *) (xci + 1);
104 xci->rotations = rep.rotations;
105 xci->npossible = rep.nPossibleOutput;
106 xci->possible = (RROutput *) (xci->outputs + rep.nOutput);
107
108 _XRead32 (dpy, (long *) xci->outputs, rep.nOutput << 2);
109 _XRead32 (dpy, (long *) xci->possible, rep.nPossibleOutput << 2);
110
111 /*
112 * Skip any extra data
113 */
114 if (nbytes > nbytesRead)
115 _XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
116
117 UnlockDisplay (dpy);
118 SyncHandle ();
119 return (XRRCrtcInfo *) xci;
120 }
121
122 void
XRRFreeCrtcInfo(XRRCrtcInfo * crtcInfo)123 XRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo)
124 {
125 Xfree (crtcInfo);
126 }
127
128 Status
XRRSetCrtcConfig(Display * dpy,XRRScreenResources * resources,RRCrtc crtc,Time timestamp,int x,int y,RRMode mode,Rotation rotation,RROutput * outputs,int noutputs)129 XRRSetCrtcConfig (Display *dpy,
130 XRRScreenResources *resources,
131 RRCrtc crtc,
132 Time timestamp,
133 int x, int y,
134 RRMode mode,
135 Rotation rotation,
136 RROutput *outputs,
137 int noutputs)
138 {
139 XExtDisplayInfo *info = XRRFindDisplay(dpy);
140 xRRSetCrtcConfigReply rep;
141 xRRSetCrtcConfigReq *req;
142
143 RRCheckExtension (dpy, info, 0);
144
145 LockDisplay(dpy);
146 GetReq (RRSetCrtcConfig, req);
147 req->reqType = info->codes->major_opcode;
148 req->randrReqType = X_RRSetCrtcConfig;
149 req->length += noutputs;
150 req->crtc = crtc;
151 req->timestamp = timestamp;
152 req->configTimestamp = resources->configTimestamp;
153 req->x = x;
154 req->y = y;
155 req->mode = mode;
156 req->rotation = rotation;
157 Data32 (dpy, outputs, noutputs << 2);
158
159 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
160 rep.status = RRSetConfigFailed;
161 UnlockDisplay (dpy);
162 SyncHandle ();
163 return rep.status;
164 }
165
166 int
XRRGetCrtcGammaSize(Display * dpy,RRCrtc crtc)167 XRRGetCrtcGammaSize (Display *dpy, RRCrtc crtc)
168 {
169 XExtDisplayInfo *info = XRRFindDisplay(dpy);
170 xRRGetCrtcGammaSizeReply rep;
171 xRRGetCrtcGammaSizeReq *req;
172
173 RRCheckExtension (dpy, info, 0);
174
175 LockDisplay(dpy);
176 GetReq (RRGetCrtcGammaSize, req);
177 req->reqType = info->codes->major_opcode;
178 req->randrReqType = X_RRGetCrtcGammaSize;
179 req->crtc = crtc;
180
181 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
182 rep.size = 0;
183 UnlockDisplay (dpy);
184 SyncHandle ();
185 return rep.size;
186 }
187
188 XRRCrtcGamma *
XRRGetCrtcGamma(Display * dpy,RRCrtc crtc)189 XRRGetCrtcGamma (Display *dpy, RRCrtc crtc)
190 {
191 XExtDisplayInfo *info = XRRFindDisplay(dpy);
192 xRRGetCrtcGammaReply rep;
193 xRRGetCrtcGammaReq *req;
194 XRRCrtcGamma *crtc_gamma = NULL;
195 long nbytes;
196 long nbytesRead;
197
198 RRCheckExtension (dpy, info, NULL);
199
200 LockDisplay(dpy);
201 GetReq (RRGetCrtcGamma, req);
202 req->reqType = info->codes->major_opcode;
203 req->randrReqType = X_RRGetCrtcGamma;
204 req->crtc = crtc;
205
206 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
207 goto out;
208
209 if (rep.length < INT_MAX >> 2)
210 {
211 nbytes = (long) rep.length << 2;
212
213 /* three channels of CARD16 data */
214 nbytesRead = (rep.size * 2 * 3);
215
216 crtc_gamma = XRRAllocGamma (rep.size);
217 }
218 else
219 {
220 nbytes = 0;
221 nbytesRead = 0;
222 crtc_gamma = NULL;
223 }
224
225 if (!crtc_gamma)
226 {
227 _XEatDataWords (dpy, rep.length);
228 goto out;
229 }
230 _XRead16 (dpy, crtc_gamma->red, rep.size * 2);
231 _XRead16 (dpy, crtc_gamma->green, rep.size * 2);
232 _XRead16 (dpy, crtc_gamma->blue, rep.size * 2);
233
234 if (nbytes > nbytesRead)
235 _XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
236
237 out:
238 UnlockDisplay (dpy);
239 SyncHandle ();
240 return crtc_gamma;
241 }
242
243 XRRCrtcGamma *
XRRAllocGamma(int size)244 XRRAllocGamma (int size)
245 {
246 XRRCrtcGamma *crtc_gamma;
247
248 crtc_gamma = Xmalloc (sizeof (XRRCrtcGamma) +
249 sizeof (crtc_gamma->red[0]) * size * 3);
250 if (!crtc_gamma)
251 return NULL;
252 crtc_gamma->size = size;
253 crtc_gamma->red = (unsigned short *) (crtc_gamma + 1);
254 crtc_gamma->green = crtc_gamma->red + size;
255 crtc_gamma->blue = crtc_gamma->green + size;
256 return crtc_gamma;
257 }
258
259 void
XRRSetCrtcGamma(Display * dpy,RRCrtc crtc,XRRCrtcGamma * crtc_gamma)260 XRRSetCrtcGamma (Display *dpy, RRCrtc crtc, XRRCrtcGamma *crtc_gamma)
261 {
262 XExtDisplayInfo *info = XRRFindDisplay(dpy);
263 xRRSetCrtcGammaReq *req;
264
265 RRSimpleCheckExtension (dpy, info);
266
267 LockDisplay(dpy);
268 GetReq (RRSetCrtcGamma, req);
269 req->reqType = info->codes->major_opcode;
270 req->randrReqType = X_RRSetCrtcGamma;
271 req->crtc = crtc;
272 req->size = crtc_gamma->size;
273 req->length += (crtc_gamma->size * 2 * 3 + 3) >> 2;
274 /*
275 * Note this assumes the structure was allocated with XRRAllocGamma,
276 * otherwise the channels might not be contiguous
277 */
278 Data16 (dpy, crtc_gamma->red, crtc_gamma->size * 2 * 3);
279
280 UnlockDisplay (dpy);
281 SyncHandle ();
282 }
283
284 void
XRRFreeGamma(XRRCrtcGamma * crtc_gamma)285 XRRFreeGamma (XRRCrtcGamma *crtc_gamma)
286 {
287 Xfree (crtc_gamma);
288 }
289
290 /* Version 1.3 additions */
291
292 static void
XTransform_from_xRenderTransform(XTransform * x,xRenderTransform * render)293 XTransform_from_xRenderTransform (XTransform *x,
294 xRenderTransform *render)
295 {
296 x->matrix[0][0] = render->matrix11;
297 x->matrix[0][1] = render->matrix12;
298 x->matrix[0][2] = render->matrix13;
299
300 x->matrix[1][0] = render->matrix21;
301 x->matrix[1][1] = render->matrix22;
302 x->matrix[1][2] = render->matrix23;
303
304 x->matrix[2][0] = render->matrix31;
305 x->matrix[2][1] = render->matrix32;
306 x->matrix[2][2] = render->matrix33;
307 }
308
309 static void
xRenderTransform_from_XTransform(xRenderTransform * render,XTransform * x)310 xRenderTransform_from_XTransform (xRenderTransform *render,
311 XTransform *x)
312 {
313 render->matrix11 = x->matrix[0][0];
314 render->matrix12 = x->matrix[0][1];
315 render->matrix13 = x->matrix[0][2];
316
317 render->matrix21 = x->matrix[1][0];
318 render->matrix22 = x->matrix[1][1];
319 render->matrix23 = x->matrix[1][2];
320
321 render->matrix31 = x->matrix[2][0];
322 render->matrix32 = x->matrix[2][1];
323 render->matrix33 = x->matrix[2][2];
324 }
325
326 void
XRRSetCrtcTransform(Display * dpy,RRCrtc crtc,XTransform * transform,_Xconst char * filter,XFixed * params,int nparams)327 XRRSetCrtcTransform (Display *dpy,
328 RRCrtc crtc,
329 XTransform *transform,
330 _Xconst char *filter,
331 XFixed *params,
332 int nparams)
333 {
334 XExtDisplayInfo *info = XRRFindDisplay(dpy);
335 xRRSetCrtcTransformReq *req;
336 int nbytes = strlen (filter);
337
338 RRSimpleCheckExtension (dpy, info);
339
340 LockDisplay(dpy);
341 GetReq (RRSetCrtcTransform, req);
342 req->reqType = info->codes->major_opcode;
343 req->randrReqType = X_RRSetCrtcTransform;
344 req->crtc = crtc;
345
346 xRenderTransform_from_XTransform (&req->transform, transform);
347
348 req->nbytesFilter = nbytes;
349 req->length += ((nbytes + 3) >> 2) + nparams;
350 Data (dpy, filter, nbytes);
351 Data32 (dpy, params, nparams << 2);
352
353 UnlockDisplay (dpy);
354 SyncHandle ();
355 }
356
357 #define CrtcTransformExtra (SIZEOF(xRRGetCrtcTransformReply) - 32)
358
359 static const xRenderTransform identity = {
360 0x10000, 0, 0,
361 0, 0x10000, 0,
362 0, 0, 0x10000,
363 };
364
365 static Bool
_XRRHasTransform(int major,int minor)366 _XRRHasTransform (int major, int minor)
367 {
368 return major > 1 || (major == 1 && minor >= 3);
369 }
370
371 Status
XRRGetCrtcTransform(Display * dpy,RRCrtc crtc,XRRCrtcTransformAttributes ** attributes)372 XRRGetCrtcTransform (Display *dpy,
373 RRCrtc crtc,
374 XRRCrtcTransformAttributes **attributes)
375 {
376 XExtDisplayInfo *info = XRRFindDisplay(dpy);
377 xRRGetCrtcTransformReply rep;
378 xRRGetCrtcTransformReq *req;
379 int major_version, minor_version;
380 XRRCrtcTransformAttributes *attr;
381 char *extra = NULL, *end = NULL, *e;
382 int p;
383
384 *attributes = NULL;
385
386 RRCheckExtension (dpy, info, False);
387
388 if (!XRRQueryVersion (dpy, &major_version, &minor_version) ||
389 !_XRRHasTransform (major_version, minor_version))
390 {
391 /* For pre-1.3 servers, just report identity matrices everywhere */
392 rep.pendingTransform = identity;
393 rep.pendingNbytesFilter = 0;
394 rep.pendingNparamsFilter = 0;
395 rep.currentTransform = identity;
396 rep.currentNbytesFilter = 0;
397 rep.currentNparamsFilter = 0;
398 }
399 else
400 {
401 LockDisplay (dpy);
402 GetReq (RRGetCrtcTransform, req);
403 req->reqType = info->codes->major_opcode;
404 req->randrReqType = X_RRGetCrtcTransform;
405 req->crtc = crtc;
406
407 if (!_XReply (dpy, (xReply *) &rep, CrtcTransformExtra >> 2, xFalse))
408 {
409 rep.pendingTransform = identity;
410 rep.pendingNbytesFilter = 0;
411 rep.pendingNparamsFilter = 0;
412 rep.currentTransform = identity;
413 rep.currentNbytesFilter = 0;
414 rep.currentNparamsFilter = 0;
415 }
416 else
417 {
418 int extraBytes = rep.length * 4 - CrtcTransformExtra;
419 if (rep.length < INT_MAX / 4 &&
420 rep.length * 4 >= CrtcTransformExtra) {
421 extra = Xmalloc (extraBytes);
422 end = extra + extraBytes;
423 } else
424 extra = NULL;
425 if (!extra) {
426 if (rep.length > (CrtcTransformExtra >> 2))
427 _XEatDataWords (dpy, rep.length - (CrtcTransformExtra >> 2));
428 else
429 _XEatDataWords (dpy, rep.length);
430 UnlockDisplay (dpy);
431 SyncHandle ();
432 return False;
433 }
434 _XRead (dpy, extra, extraBytes);
435 }
436
437 UnlockDisplay (dpy);
438 SyncHandle ();
439 }
440
441 attr = Xmalloc (sizeof (XRRCrtcTransformAttributes) +
442 rep.pendingNparamsFilter * sizeof (XFixed) +
443 rep.currentNparamsFilter * sizeof (XFixed) +
444 rep.pendingNbytesFilter + 1 +
445 rep.currentNbytesFilter + 1);
446
447 if (!attr) {
448 XFree (extra);
449 return False;
450 }
451 XTransform_from_xRenderTransform (&attr->pendingTransform, &rep.pendingTransform);
452 XTransform_from_xRenderTransform (&attr->currentTransform, &rep.currentTransform);
453
454 attr->pendingParams = (XFixed *) (attr + 1);
455 attr->currentParams = attr->pendingParams + rep.pendingNparamsFilter;
456 attr->pendingFilter = (char *) (attr->currentParams + rep.currentNparamsFilter);
457 attr->currentFilter = attr->pendingFilter + rep.pendingNbytesFilter + 1;
458
459 e = extra;
460
461 if (e + rep.pendingNbytesFilter > end) {
462 XFree (attr);
463 XFree (extra);
464 return False;
465 }
466 memcpy (attr->pendingFilter, e, rep.pendingNbytesFilter);
467 attr->pendingFilter[rep.pendingNbytesFilter] = '\0';
468 e += (rep.pendingNbytesFilter + 3) & ~3;
469 for (p = 0; p < rep.pendingNparamsFilter; p++) {
470 INT32 f;
471 if (e + 4 > end) {
472 XFree (attr);
473 XFree (extra);
474 return False;
475 }
476 memcpy (&f, e, 4);
477 e += 4;
478 attr->pendingParams[p] = (XFixed) f;
479 }
480 attr->pendingNparams = rep.pendingNparamsFilter;
481
482 if (e + rep.currentNbytesFilter > end) {
483 XFree (attr);
484 XFree (extra);
485 return False;
486 }
487 memcpy (attr->currentFilter, e, rep.currentNbytesFilter);
488 attr->currentFilter[rep.currentNbytesFilter] = '\0';
489 e += (rep.currentNbytesFilter + 3) & ~3;
490 for (p = 0; p < rep.currentNparamsFilter; p++) {
491 INT32 f;
492 if (e + 4 > end) {
493 XFree (attr);
494 XFree (extra);
495 return False;
496 }
497 memcpy (&f, e, 4);
498 e += 4;
499 attr->currentParams[p] = (XFixed) f;
500 }
501 attr->currentNparams = rep.currentNparamsFilter;
502
503 if (extra)
504 XFree (extra);
505 *attributes = attr;
506
507 return True;
508 }
509
510 XRRPanning *
XRRGetPanning(Display * dpy,XRRScreenResources * resources,RRCrtc crtc)511 XRRGetPanning (Display *dpy, XRRScreenResources *resources, RRCrtc crtc)
512 {
513 XExtDisplayInfo *info = XRRFindDisplay(dpy);
514 xRRGetPanningReply rep;
515 xRRGetPanningReq *req;
516 XRRPanning *xp;
517
518 RRCheckExtension (dpy, info, NULL);
519
520 LockDisplay (dpy);
521 GetReq (RRGetPanning, req);
522 req->reqType = info->codes->major_opcode;
523 req->randrReqType = X_RRGetPanning;
524 req->crtc = crtc;
525
526 if (!_XReply (dpy, (xReply *) &rep, 1, xFalse))
527 {
528 UnlockDisplay (dpy);
529 SyncHandle ();
530 return NULL;
531 }
532
533 if (! (xp = (XRRPanning *) Xmalloc(sizeof(XRRPanning))) ) {
534 _XEatData (dpy, sizeof(XRRPanning));
535 UnlockDisplay (dpy);
536 SyncHandle ();
537 return NULL;
538 }
539
540 xp->timestamp = rep.timestamp;
541 xp->left = rep.left;
542 xp->top = rep.top;
543 xp->width = rep.width;
544 xp->height = rep.height;
545 xp->track_left = rep.track_left;
546 xp->track_top = rep.track_top;
547 xp->track_width = rep.track_width;
548 xp->track_height = rep.track_height;
549 xp->border_left = rep.border_left;
550 xp->border_top = rep.border_top;
551 xp->border_right = rep.border_right;
552 xp->border_bottom = rep.border_bottom;
553
554 UnlockDisplay (dpy);
555 SyncHandle ();
556 return (XRRPanning *) xp;
557 }
558
559 void
XRRFreePanning(XRRPanning * panning)560 XRRFreePanning (XRRPanning *panning)
561 {
562 Xfree (panning);
563 }
564
565 Status
XRRSetPanning(Display * dpy,XRRScreenResources * resources,RRCrtc crtc,XRRPanning * panning)566 XRRSetPanning (Display *dpy,
567 XRRScreenResources *resources,
568 RRCrtc crtc,
569 XRRPanning *panning)
570 {
571 XExtDisplayInfo *info = XRRFindDisplay(dpy);
572 xRRSetPanningReply rep;
573 xRRSetPanningReq *req;
574
575 RRCheckExtension (dpy, info, 0);
576
577 LockDisplay(dpy);
578 GetReq (RRSetPanning, req);
579 req->reqType = info->codes->major_opcode;
580 req->randrReqType = X_RRSetPanning;
581 req->crtc = crtc;
582 req->timestamp = panning->timestamp;
583 req->left = panning->left;
584 req->top = panning->top;
585 req->width = panning->width;
586 req->height = panning->height;
587 req->track_left = panning->track_left;
588 req->track_top = panning->track_top;
589 req->track_width = panning->track_width;
590 req->track_height = panning->track_height;
591 req->border_left = panning->border_left;
592 req->border_top = panning->border_top;
593 req->border_right = panning->border_right;
594 req->border_bottom = panning->border_bottom;
595
596 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
597 rep.status = RRSetConfigFailed;
598 UnlockDisplay (dpy);
599 SyncHandle ();
600 return rep.status;
601 }
602
603