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