076237376168c6100c44ef37d1a13d558fdb72b7
[framework/uifw/xorg/lib/libxrandr.git] / src / XrrCrtc.c
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
35 XRRCrtcInfo *
36 XRRGetCrtcInfo (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
110 void
111 XRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo)
112 {
113     Xfree (crtcInfo);
114 }
115
116 Status
117 XRRSetCrtcConfig (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
154 int
155 XRRGetCrtcGammaSize (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.size = 0;
171     UnlockDisplay (dpy);
172     SyncHandle ();
173     return rep.size;
174 }
175
176 XRRCrtcGamma *
177 XRRGetCrtcGamma (Display *dpy, RRCrtc crtc)
178 {
179     XExtDisplayInfo         *info = XRRFindDisplay(dpy);
180     xRRGetCrtcGammaReply    rep;
181     xRRGetCrtcGammaReq      *req;
182     XRRCrtcGamma            *crtc_gamma = NULL;
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         goto out;
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         goto out;
208     }
209     _XRead16 (dpy, crtc_gamma->red, rep.size * 2);
210     _XRead16 (dpy, crtc_gamma->green, rep.size * 2);
211     _XRead16 (dpy, crtc_gamma->blue, rep.size * 2);
212
213     if (nbytes > nbytesRead)
214         _XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
215
216 out:
217     UnlockDisplay (dpy);
218     SyncHandle ();
219     return crtc_gamma;
220 }
221
222 XRRCrtcGamma *
223 XRRAllocGamma (int size)
224 {
225     XRRCrtcGamma    *crtc_gamma;
226
227     crtc_gamma = Xmalloc (sizeof (XRRCrtcGamma) +
228                           sizeof (crtc_gamma->red[0]) * size * 3);
229     if (!crtc_gamma)
230         return NULL;
231     crtc_gamma->size = size;
232     crtc_gamma->red = (unsigned short *) (crtc_gamma + 1);
233     crtc_gamma->green = crtc_gamma->red + size;
234     crtc_gamma->blue = crtc_gamma->green + size;
235     return crtc_gamma;
236 }
237
238 void
239 XRRSetCrtcGamma (Display *dpy, RRCrtc crtc, XRRCrtcGamma *crtc_gamma)
240 {
241     XExtDisplayInfo         *info = XRRFindDisplay(dpy);
242     xRRSetCrtcGammaReq      *req;
243
244     RRSimpleCheckExtension (dpy, info);
245
246     LockDisplay(dpy);
247     GetReq (RRSetCrtcGamma, req);
248     req->reqType = info->codes->major_opcode;
249     req->randrReqType = X_RRSetCrtcGamma;
250     req->crtc = crtc;
251     req->size = crtc_gamma->size;
252     req->length += (crtc_gamma->size * 2 * 3 + 3) >> 2;
253     /*
254      * Note this assumes the structure was allocated with XRRAllocGamma,
255      * otherwise the channels might not be contiguous
256      */
257     Data16 (dpy, crtc_gamma->red, crtc_gamma->size * 2 * 3);
258
259     UnlockDisplay (dpy);
260     SyncHandle ();
261 }
262
263 void
264 XRRFreeGamma (XRRCrtcGamma *crtc_gamma)
265 {
266     Xfree (crtc_gamma);
267 }
268
269 /* Version 1.3 additions */
270
271 static void
272 XTransform_from_xRenderTransform (XTransform *x,
273                                   xRenderTransform *render)
274 {
275     x->matrix[0][0] = render->matrix11;
276     x->matrix[0][1] = render->matrix12;
277     x->matrix[0][2] = render->matrix13;
278
279     x->matrix[1][0] = render->matrix21;
280     x->matrix[1][1] = render->matrix22;
281     x->matrix[1][2] = render->matrix23;
282
283     x->matrix[2][0] = render->matrix31;
284     x->matrix[2][1] = render->matrix32;
285     x->matrix[2][2] = render->matrix33;
286 }
287
288 static void
289 xRenderTransform_from_XTransform (xRenderTransform *render,
290                                   XTransform *x)
291 {
292     render->matrix11 = x->matrix[0][0];
293     render->matrix12 = x->matrix[0][1];
294     render->matrix13 = x->matrix[0][2];
295
296     render->matrix21 = x->matrix[1][0];
297     render->matrix22 = x->matrix[1][1];
298     render->matrix23 = x->matrix[1][2];
299
300     render->matrix31 = x->matrix[2][0];
301     render->matrix32 = x->matrix[2][1];
302     render->matrix33 = x->matrix[2][2];
303 }
304
305 void
306 XRRSetCrtcTransform (Display    *dpy,
307                      RRCrtc     crtc,
308                      XTransform *transform,
309                      char       *filter,
310                      XFixed     *params,
311                      int        nparams)
312 {
313     XExtDisplayInfo         *info = XRRFindDisplay(dpy);
314     xRRSetCrtcTransformReq  *req;
315     int                     nbytes = strlen (filter);
316
317     RRSimpleCheckExtension (dpy, info);
318
319     LockDisplay(dpy);
320     GetReq (RRSetCrtcTransform, req);
321     req->reqType = info->codes->major_opcode;
322     req->randrReqType = X_RRSetCrtcTransform;
323     req->crtc = crtc;
324
325     xRenderTransform_from_XTransform (&req->transform, transform);
326
327     req->nbytesFilter = nbytes;
328     req->length += ((nbytes + 3) >> 2) + nparams;
329     Data (dpy, filter, nbytes);
330     Data32 (dpy, params, nparams << 2);
331
332     UnlockDisplay (dpy);
333     SyncHandle ();
334 }
335
336 #define CrtcTransformExtra      (SIZEOF(xRRGetCrtcTransformReply) - 32)
337
338 static const xRenderTransform identity = {
339     0x10000, 0, 0,
340     0, 0x10000, 0,
341     0, 0, 0x10000,
342 };
343
344 static Bool
345 _XRRHasTransform (int major, int minor)
346 {
347     return major > 1 || (major == 1 && minor >= 3);
348 }
349
350 Status
351 XRRGetCrtcTransform (Display    *dpy,
352                      RRCrtc     crtc,
353                      XRRCrtcTransformAttributes **attributes)
354 {
355     XExtDisplayInfo             *info = XRRFindDisplay(dpy);
356     xRRGetCrtcTransformReply    rep;
357     xRRGetCrtcTransformReq      *req;
358     int                         major_version, minor_version;
359     XRRCrtcTransformAttributes  *attr;
360     char                        *extra = NULL, *e;
361     int                         p;
362
363     *attributes = NULL;
364
365     RRCheckExtension (dpy, info, False);
366
367     if (!XRRQueryVersion (dpy, &major_version, &minor_version) ||
368         !_XRRHasTransform (major_version, minor_version))
369     {
370         /* For pre-1.3 servers, just report identity matrices everywhere */
371         rep.pendingTransform = identity;
372         rep.pendingNbytesFilter = 0;
373         rep.pendingNparamsFilter = 0;
374         rep.currentTransform = identity;
375         rep.currentNbytesFilter = 0;
376         rep.currentNparamsFilter = 0;
377     }
378     else
379     {
380         LockDisplay (dpy);
381         GetReq (RRGetCrtcTransform, req);
382         req->reqType = info->codes->major_opcode;
383         req->randrReqType = X_RRGetCrtcTransform;
384         req->crtc = crtc;
385
386         if (!_XReply (dpy, (xReply *) &rep, CrtcTransformExtra >> 2, xFalse))
387         {
388             rep.pendingTransform = identity;
389             rep.pendingNbytesFilter = 0;
390             rep.pendingNparamsFilter = 0;
391             rep.currentTransform = identity;
392             rep.currentNbytesFilter = 0;
393             rep.currentNparamsFilter = 0;
394         }
395         else
396         {
397             int extraBytes = rep.length * 4 - CrtcTransformExtra;
398             extra = Xmalloc (extraBytes);
399             if (!extra) {
400                 _XEatData (dpy, extraBytes);
401                 UnlockDisplay (dpy);
402                 SyncHandle ();
403                 return False;
404             }
405             _XRead (dpy, extra, extraBytes);
406         }
407
408         UnlockDisplay (dpy);
409         SyncHandle ();
410     }
411
412     attr = Xmalloc (sizeof (XRRCrtcTransformAttributes) +
413                     rep.pendingNparamsFilter * sizeof (XFixed) +
414                     rep.currentNparamsFilter * sizeof (XFixed) +
415                     rep.pendingNbytesFilter + 1 +
416                     rep.currentNbytesFilter + 1);
417
418     if (!attr) {
419         XFree (extra);
420         return False;
421     }
422     XTransform_from_xRenderTransform (&attr->pendingTransform, &rep.pendingTransform);
423     XTransform_from_xRenderTransform (&attr->currentTransform, &rep.currentTransform);
424
425     attr->pendingParams = (XFixed *) (attr + 1);
426     attr->currentParams = attr->pendingParams + rep.pendingNparamsFilter;
427     attr->pendingFilter = (char *) (attr->currentParams + rep.currentNparamsFilter);
428     attr->currentFilter = attr->pendingFilter + rep.pendingNbytesFilter + 1;
429
430     e = extra;
431
432     memcpy (attr->pendingFilter, e, rep.pendingNbytesFilter);
433     attr->pendingFilter[rep.pendingNbytesFilter] = '\0';
434     e += (rep.pendingNbytesFilter + 3) & ~3;
435     for (p = 0; p < rep.pendingNparamsFilter; p++) {
436         INT32   f;
437         memcpy (&f, e, 4);
438         e += 4;
439         attr->pendingParams[p] = (XFixed) f;
440     }
441     attr->pendingNparams = rep.pendingNparamsFilter;
442
443     memcpy (attr->currentFilter, e, rep.currentNbytesFilter);
444     attr->currentFilter[rep.currentNbytesFilter] = '\0';
445     e += (rep.currentNbytesFilter + 3) & ~3;
446     for (p = 0; p < rep.currentNparamsFilter; p++) {
447         INT32   f;
448         memcpy (&f, e, 4);
449         e += 4;
450         attr->currentParams[p] = (XFixed) f;
451     }
452     attr->currentNparams = rep.currentNparamsFilter;
453
454     if (extra)
455         XFree (extra);
456     *attributes = attr;
457
458     return True;
459 }
460
461 XRRPanning *
462 XRRGetPanning (Display *dpy, XRRScreenResources *resources, RRCrtc crtc)
463 {
464     XExtDisplayInfo         *info = XRRFindDisplay(dpy);
465     xRRGetPanningReply      rep;
466     xRRGetPanningReq        *req;
467     XRRPanning              *xp;
468
469     RRCheckExtension (dpy, info, NULL);
470
471     LockDisplay (dpy);
472     GetReq (RRGetPanning, req);
473     req->reqType         = info->codes->major_opcode;
474     req->randrReqType    = X_RRGetPanning;
475     req->crtc            = crtc;
476
477     if (!_XReply (dpy, (xReply *) &rep, 1, xFalse))
478     {
479         UnlockDisplay (dpy);
480         SyncHandle ();
481         return NULL;
482     }
483
484     if (! (xp = (XRRPanning *) Xmalloc(sizeof(XRRPanning))) ) {
485         _XEatData (dpy, sizeof(XRRPanning));
486         UnlockDisplay (dpy);
487         SyncHandle ();
488         return NULL;
489     }
490
491     xp->timestamp     = rep.timestamp;
492     xp->left          = rep.left;
493     xp->top           = rep.top;
494     xp->width         = rep.width;
495     xp->height        = rep.height;
496     xp->track_left    = rep.track_left;
497     xp->track_top     = rep.track_top;
498     xp->track_width   = rep.track_width;
499     xp->track_height  = rep.track_height;
500     xp->border_left   = rep.border_left;
501     xp->border_top    = rep.border_top;
502     xp->border_right  = rep.border_right;
503     xp->border_bottom = rep.border_bottom;
504
505     UnlockDisplay (dpy);
506     SyncHandle ();
507     return (XRRPanning *) xp;
508 }
509
510 void
511 XRRFreePanning (XRRPanning *panning)
512 {
513     Xfree (panning);
514 }
515
516 Status
517 XRRSetPanning (Display *dpy,
518                XRRScreenResources *resources,
519                RRCrtc crtc,
520                XRRPanning *panning)
521 {
522     XExtDisplayInfo         *info = XRRFindDisplay(dpy);
523     xRRSetPanningReply      rep;
524     xRRSetPanningReq        *req;
525
526     RRCheckExtension (dpy, info, 0);
527
528     LockDisplay(dpy);
529     GetReq (RRSetPanning, req);
530     req->reqType       = info->codes->major_opcode;
531     req->randrReqType  = X_RRSetPanning;
532     req->crtc          = crtc;
533     req->timestamp     = panning->timestamp;
534     req->left          = panning->left;
535     req->top           = panning->top;
536     req->width         = panning->width;
537     req->height        = panning->height;
538     req->track_left    = panning->track_left;
539     req->track_top     = panning->track_top;
540     req->track_width   = panning->track_width;
541     req->track_height  = panning->track_height;
542     req->border_left   = panning->border_left;
543     req->border_top    = panning->border_top;
544     req->border_right  = panning->border_right;
545     req->border_bottom = panning->border_bottom;
546
547     if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
548         rep.status = RRSetConfigFailed;
549     UnlockDisplay (dpy);
550     SyncHandle ();
551     return rep.status;
552 }
553