XrrCrtc.c revision 8d0bc965
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
36XRRCrtcInfo *
37XRRGetCrtcInfo (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 = 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
122void
123XRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo)
124{
125    Xfree (crtcInfo);
126}
127
128Status
129XRRSetCrtcConfig (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
166int
167XRRGetCrtcGammaSize (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
188XRRCrtcGamma *
189XRRGetCrtcGamma (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
237out:
238    UnlockDisplay (dpy);
239    SyncHandle ();
240    return crtc_gamma;
241}
242
243XRRCrtcGamma *
244XRRAllocGamma (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
259void
260XRRSetCrtcGamma (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
284void
285XRRFreeGamma (XRRCrtcGamma *crtc_gamma)
286{
287    Xfree (crtc_gamma);
288}
289
290/* Version 1.3 additions */
291
292static void
293XTransform_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
309static void
310xRenderTransform_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
326void
327XRRSetCrtcTransform (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
359static const xRenderTransform identity = {
360    0x10000, 0, 0,
361    0, 0x10000, 0,
362    0, 0, 0x10000,
363};
364
365static Bool
366_XRRHasTransform (int major, int minor)
367{
368    return major > 1 || (major == 1 && minor >= 3);
369}
370
371Status
372XRRGetCrtcTransform (Display	*dpy,
373		     RRCrtc	crtc,
374		     XRRCrtcTransformAttributes **attributes)
375{
376    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
377    xRRGetCrtcTransformReply	rep;
378    int				major_version, minor_version;
379    XRRCrtcTransformAttributes	*attr;
380    char			*extra = NULL, *end = NULL, *e;
381
382    *attributes = NULL;
383
384    RRCheckExtension (dpy, info, False);
385
386    if (!XRRQueryVersion (dpy, &major_version, &minor_version) ||
387	!_XRRHasTransform (major_version, minor_version))
388    {
389	/* For pre-1.3 servers, just report identity matrices everywhere */
390	rep.pendingTransform = identity;
391	rep.pendingNbytesFilter = 0;
392	rep.pendingNparamsFilter = 0;
393	rep.currentTransform = identity;
394	rep.currentNbytesFilter = 0;
395	rep.currentNparamsFilter = 0;
396    }
397    else
398    {
399	xRRGetCrtcTransformReq	*req;
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 (unsigned int 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 (unsigned int 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
510XRRPanning *
511XRRGetPanning (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 = 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
559void
560XRRFreePanning (XRRPanning *panning)
561{
562    Xfree (panning);
563}
564
565Status
566XRRSetPanning (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