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