1b042e37fSmrg/*
2b042e37fSmrg * Copyright © 2006 Keith Packard
3b042e37fSmrg *
4b042e37fSmrg * Permission to use, copy, modify, distribute, and sell this software and its
5b042e37fSmrg * documentation for any purpose is hereby granted without fee, provided that
6b042e37fSmrg * the above copyright notice appear in all copies and that both that copyright
7b042e37fSmrg * notice and this permission notice appear in supporting documentation, and
8b042e37fSmrg * that the name of the copyright holders not be used in advertising or
9b042e37fSmrg * publicity pertaining to distribution of the software without specific,
10b042e37fSmrg * written prior permission.  The copyright holders make no representations
11b042e37fSmrg * about the suitability of this software for any purpose.  It is provided "as
12b042e37fSmrg * is" without express or implied warranty.
13b042e37fSmrg *
14b042e37fSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15b042e37fSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16b042e37fSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17b042e37fSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18b042e37fSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19b042e37fSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20b042e37fSmrg * OF THIS SOFTWARE.
21b042e37fSmrg */
22b042e37fSmrg
23b042e37fSmrg#ifdef HAVE_CONFIG_H
24b042e37fSmrg#include <config.h>
25b042e37fSmrg#endif
26b042e37fSmrg
27b242714cSmrg#include <limits.h>
28b042e37fSmrg#include <stdio.h>
29b042e37fSmrg#include <X11/Xlib.h>
30b042e37fSmrg/* we need to be able to manipulate the Display structure on events */
31b042e37fSmrg#include <X11/Xlibint.h>
32b042e37fSmrg#include <X11/extensions/render.h>
33b042e37fSmrg#include <X11/extensions/Xrender.h>
34b042e37fSmrg#include "Xrandrint.h"
35b042e37fSmrg
36b042e37fSmrgXRRCrtcInfo *
37b042e37fSmrgXRRGetCrtcInfo (Display *dpy, XRRScreenResources *resources, RRCrtc crtc)
38b042e37fSmrg{
39b042e37fSmrg    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
40b042e37fSmrg    xRRGetCrtcInfoReply	    rep;
41b042e37fSmrg    xRRGetCrtcInfoReq	    *req;
42b042e37fSmrg    int			    nbytes, nbytesRead, rbytes;
43b042e37fSmrg    XRRCrtcInfo		    *xci;
44b042e37fSmrg
458c4a8e55Smrg    RRCheckExtension (dpy, info, NULL);
46b042e37fSmrg
47b042e37fSmrg    LockDisplay (dpy);
48b042e37fSmrg    GetReq (RRGetCrtcInfo, req);
49b042e37fSmrg    req->reqType = info->codes->major_opcode;
50b042e37fSmrg    req->randrReqType = X_RRGetCrtcInfo;
51b042e37fSmrg    req->crtc = crtc;
52b042e37fSmrg    req->configTimestamp = resources->configTimestamp;
53b042e37fSmrg
54b042e37fSmrg    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
55b042e37fSmrg    {
56b042e37fSmrg	UnlockDisplay (dpy);
57b042e37fSmrg	SyncHandle ();
58b042e37fSmrg	return NULL;
59b042e37fSmrg    }
60b042e37fSmrg
61b242714cSmrg    if (rep.length < INT_MAX >> 2)
62b242714cSmrg    {
63b242714cSmrg	nbytes = (long) rep.length << 2;
64b042e37fSmrg
65b242714cSmrg	nbytesRead = (long) (rep.nOutput * 4 +
66b242714cSmrg			     rep.nPossibleOutput * 4);
67b042e37fSmrg
68b242714cSmrg	/*
69b242714cSmrg	 * first we must compute how much space to allocate for
70b242714cSmrg	 * randr library's use; we'll allocate the structures in a single
71b242714cSmrg	 * allocation, on cleanlyness grounds.
72b242714cSmrg	 */
73b042e37fSmrg
74b242714cSmrg	rbytes = (sizeof (XRRCrtcInfo) +
75b242714cSmrg		  rep.nOutput * sizeof (RROutput) +
76b242714cSmrg		  rep.nPossibleOutput * sizeof (RROutput));
77b242714cSmrg
788d0bc965Smrg	xci = Xmalloc(rbytes);
79b242714cSmrg    }
80b242714cSmrg    else
81b242714cSmrg    {
82b242714cSmrg	nbytes = 0;
83b242714cSmrg	nbytesRead = 0;
84b242714cSmrg	rbytes = 0;
85b242714cSmrg	xci = NULL;
86b242714cSmrg    }
87b042e37fSmrg
88b042e37fSmrg    if (xci == NULL) {
898bd17e5fSmrg	_XEatDataWords (dpy, rep.length);
90b042e37fSmrg	UnlockDisplay (dpy);
91b042e37fSmrg	SyncHandle ();
92b042e37fSmrg	return NULL;
93b042e37fSmrg    }
94b042e37fSmrg
95b042e37fSmrg    xci->timestamp = rep.timestamp;
96b042e37fSmrg    xci->x = rep.x;
97b042e37fSmrg    xci->y = rep.y;
98b042e37fSmrg    xci->width = rep.width;
99b042e37fSmrg    xci->height = rep.height;
100b042e37fSmrg    xci->mode = rep.mode;
101b042e37fSmrg    xci->rotation = rep.rotation;
102b042e37fSmrg    xci->noutput = rep.nOutput;
103b042e37fSmrg    xci->outputs = (RROutput *) (xci + 1);
104b042e37fSmrg    xci->rotations = rep.rotations;
105b042e37fSmrg    xci->npossible = rep.nPossibleOutput;
106b042e37fSmrg    xci->possible = (RROutput *) (xci->outputs + rep.nOutput);
107b042e37fSmrg
10867594505Smrg    _XRead32 (dpy, (long *) xci->outputs, rep.nOutput << 2);
10967594505Smrg    _XRead32 (dpy, (long *) xci->possible, rep.nPossibleOutput << 2);
1100597fb56Smrg
111b042e37fSmrg    /*
112b042e37fSmrg     * Skip any extra data
113b042e37fSmrg     */
114b042e37fSmrg    if (nbytes > nbytesRead)
115b042e37fSmrg	_XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
1160597fb56Smrg
117b042e37fSmrg    UnlockDisplay (dpy);
118b042e37fSmrg    SyncHandle ();
119b042e37fSmrg    return (XRRCrtcInfo *) xci;
120b042e37fSmrg}
121b042e37fSmrg
122b042e37fSmrgvoid
123b042e37fSmrgXRRFreeCrtcInfo (XRRCrtcInfo *crtcInfo)
124b042e37fSmrg{
125b042e37fSmrg    Xfree (crtcInfo);
126b042e37fSmrg}
127b042e37fSmrg
128b042e37fSmrgStatus
129b042e37fSmrgXRRSetCrtcConfig (Display *dpy,
130b042e37fSmrg		  XRRScreenResources *resources,
131b042e37fSmrg		  RRCrtc crtc,
132b042e37fSmrg		  Time timestamp,
133b042e37fSmrg		  int x, int y,
134b042e37fSmrg		  RRMode mode,
135b042e37fSmrg		  Rotation rotation,
136b042e37fSmrg		  RROutput *outputs,
137b042e37fSmrg		  int noutputs)
138b042e37fSmrg{
139b042e37fSmrg    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
140b042e37fSmrg    xRRSetCrtcConfigReply   rep;
141b042e37fSmrg    xRRSetCrtcConfigReq	    *req;
142b042e37fSmrg
143b042e37fSmrg    RRCheckExtension (dpy, info, 0);
144b042e37fSmrg
145b042e37fSmrg    LockDisplay(dpy);
146b042e37fSmrg    GetReq (RRSetCrtcConfig, req);
147b042e37fSmrg    req->reqType = info->codes->major_opcode;
148b042e37fSmrg    req->randrReqType = X_RRSetCrtcConfig;
149b042e37fSmrg    req->length += noutputs;
150b042e37fSmrg    req->crtc = crtc;
151b042e37fSmrg    req->timestamp = timestamp;
152b042e37fSmrg    req->configTimestamp = resources->configTimestamp;
153b042e37fSmrg    req->x = x;
154b042e37fSmrg    req->y = y;
155b042e37fSmrg    req->mode = mode;
156b042e37fSmrg    req->rotation = rotation;
157b042e37fSmrg    Data32 (dpy, outputs, noutputs << 2);
158b042e37fSmrg
159b042e37fSmrg    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
160b042e37fSmrg	rep.status = RRSetConfigFailed;
161b042e37fSmrg    UnlockDisplay (dpy);
162b042e37fSmrg    SyncHandle ();
163b042e37fSmrg    return rep.status;
164b042e37fSmrg}
165b042e37fSmrg
166b042e37fSmrgint
167b042e37fSmrgXRRGetCrtcGammaSize (Display *dpy, RRCrtc crtc)
168b042e37fSmrg{
169b042e37fSmrg    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
170b042e37fSmrg    xRRGetCrtcGammaSizeReply	rep;
171b042e37fSmrg    xRRGetCrtcGammaSizeReq	*req;
172b042e37fSmrg
173b042e37fSmrg    RRCheckExtension (dpy, info, 0);
174b042e37fSmrg
175b042e37fSmrg    LockDisplay(dpy);
176b042e37fSmrg    GetReq (RRGetCrtcGammaSize, req);
177b042e37fSmrg    req->reqType = info->codes->major_opcode;
178b042e37fSmrg    req->randrReqType = X_RRGetCrtcGammaSize;
179b042e37fSmrg    req->crtc = crtc;
180b042e37fSmrg
181b042e37fSmrg    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
182706b6b52Smrg	rep.size = 0;
183b042e37fSmrg    UnlockDisplay (dpy);
184b042e37fSmrg    SyncHandle ();
185b042e37fSmrg    return rep.size;
186b042e37fSmrg}
187b042e37fSmrg
188b042e37fSmrgXRRCrtcGamma *
189b042e37fSmrgXRRGetCrtcGamma (Display *dpy, RRCrtc crtc)
190b042e37fSmrg{
191b042e37fSmrg    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
192b042e37fSmrg    xRRGetCrtcGammaReply    rep;
193b042e37fSmrg    xRRGetCrtcGammaReq	    *req;
194706b6b52Smrg    XRRCrtcGamma	    *crtc_gamma = NULL;
195b042e37fSmrg    long    		    nbytes;
196b042e37fSmrg    long    		    nbytesRead;
197b042e37fSmrg
1988c4a8e55Smrg    RRCheckExtension (dpy, info, NULL);
199b042e37fSmrg
200b042e37fSmrg    LockDisplay(dpy);
201b042e37fSmrg    GetReq (RRGetCrtcGamma, req);
202b042e37fSmrg    req->reqType = info->codes->major_opcode;
203b042e37fSmrg    req->randrReqType = X_RRGetCrtcGamma;
204b042e37fSmrg    req->crtc = crtc;
205b042e37fSmrg
206b042e37fSmrg    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
207706b6b52Smrg	goto out;
208b042e37fSmrg
209b242714cSmrg    if (rep.length < INT_MAX >> 2)
210b242714cSmrg    {
211b242714cSmrg	nbytes = (long) rep.length << 2;
2120597fb56Smrg
213b242714cSmrg	/* three channels of CARD16 data */
214b242714cSmrg	nbytesRead = (rep.size * 2 * 3);
215b042e37fSmrg
216b242714cSmrg	crtc_gamma = XRRAllocGamma (rep.size);
217b242714cSmrg    }
218b242714cSmrg    else
219b242714cSmrg    {
220b242714cSmrg	nbytes = 0;
221b242714cSmrg	nbytesRead = 0;
222b242714cSmrg	crtc_gamma = NULL;
223b242714cSmrg    }
2240597fb56Smrg
225b042e37fSmrg    if (!crtc_gamma)
226b042e37fSmrg    {
2278bd17e5fSmrg	_XEatDataWords (dpy, rep.length);
228706b6b52Smrg	goto out;
229b042e37fSmrg    }
230b042e37fSmrg    _XRead16 (dpy, crtc_gamma->red, rep.size * 2);
231b042e37fSmrg    _XRead16 (dpy, crtc_gamma->green, rep.size * 2);
232b042e37fSmrg    _XRead16 (dpy, crtc_gamma->blue, rep.size * 2);
2330597fb56Smrg
234b042e37fSmrg    if (nbytes > nbytesRead)
235b042e37fSmrg	_XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
236706b6b52Smrg
237706b6b52Smrgout:
238b042e37fSmrg    UnlockDisplay (dpy);
239b042e37fSmrg    SyncHandle ();
240b042e37fSmrg    return crtc_gamma;
241b042e37fSmrg}
242b042e37fSmrg
243b042e37fSmrgXRRCrtcGamma *
244b042e37fSmrgXRRAllocGamma (int size)
245b042e37fSmrg{
246b042e37fSmrg    XRRCrtcGamma    *crtc_gamma;
247b042e37fSmrg
248b042e37fSmrg    crtc_gamma = Xmalloc (sizeof (XRRCrtcGamma) +
249b042e37fSmrg			  sizeof (crtc_gamma->red[0]) * size * 3);
250b042e37fSmrg    if (!crtc_gamma)
251b042e37fSmrg	return NULL;
252b042e37fSmrg    crtc_gamma->size = size;
253b042e37fSmrg    crtc_gamma->red = (unsigned short *) (crtc_gamma + 1);
254b042e37fSmrg    crtc_gamma->green = crtc_gamma->red + size;
255b042e37fSmrg    crtc_gamma->blue = crtc_gamma->green + size;
256b042e37fSmrg    return crtc_gamma;
257b042e37fSmrg}
258b042e37fSmrg
259b042e37fSmrgvoid
260b042e37fSmrgXRRSetCrtcGamma (Display *dpy, RRCrtc crtc, XRRCrtcGamma *crtc_gamma)
261b042e37fSmrg{
262b042e37fSmrg    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
263b042e37fSmrg    xRRSetCrtcGammaReq	    *req;
264b042e37fSmrg
265b042e37fSmrg    RRSimpleCheckExtension (dpy, info);
266b042e37fSmrg
267b042e37fSmrg    LockDisplay(dpy);
268b042e37fSmrg    GetReq (RRSetCrtcGamma, req);
269b042e37fSmrg    req->reqType = info->codes->major_opcode;
270b042e37fSmrg    req->randrReqType = X_RRSetCrtcGamma;
271b042e37fSmrg    req->crtc = crtc;
272b042e37fSmrg    req->size = crtc_gamma->size;
273b042e37fSmrg    req->length += (crtc_gamma->size * 2 * 3 + 3) >> 2;
274b042e37fSmrg    /*
275b042e37fSmrg     * Note this assumes the structure was allocated with XRRAllocGamma,
276b042e37fSmrg     * otherwise the channels might not be contiguous
277b042e37fSmrg     */
278b042e37fSmrg    Data16 (dpy, crtc_gamma->red, crtc_gamma->size * 2 * 3);
2790597fb56Smrg
280b042e37fSmrg    UnlockDisplay (dpy);
281b042e37fSmrg    SyncHandle ();
282b042e37fSmrg}
283b042e37fSmrg
284b042e37fSmrgvoid
285b042e37fSmrgXRRFreeGamma (XRRCrtcGamma *crtc_gamma)
286b042e37fSmrg{
287b042e37fSmrg    Xfree (crtc_gamma);
288b042e37fSmrg}
2898c4a8e55Smrg
2908c4a8e55Smrg/* Version 1.3 additions */
2918c4a8e55Smrg
2928c4a8e55Smrgstatic void
2938c4a8e55SmrgXTransform_from_xRenderTransform (XTransform *x,
2948c4a8e55Smrg				  xRenderTransform *render)
2958c4a8e55Smrg{
2968c4a8e55Smrg    x->matrix[0][0] = render->matrix11;
2978c4a8e55Smrg    x->matrix[0][1] = render->matrix12;
2988c4a8e55Smrg    x->matrix[0][2] = render->matrix13;
2998c4a8e55Smrg
3008c4a8e55Smrg    x->matrix[1][0] = render->matrix21;
3018c4a8e55Smrg    x->matrix[1][1] = render->matrix22;
3028c4a8e55Smrg    x->matrix[1][2] = render->matrix23;
3038c4a8e55Smrg
3048c4a8e55Smrg    x->matrix[2][0] = render->matrix31;
3058c4a8e55Smrg    x->matrix[2][1] = render->matrix32;
3068c4a8e55Smrg    x->matrix[2][2] = render->matrix33;
3078c4a8e55Smrg}
3088c4a8e55Smrg
3098c4a8e55Smrgstatic void
3108c4a8e55SmrgxRenderTransform_from_XTransform (xRenderTransform *render,
3118c4a8e55Smrg				  XTransform *x)
3128c4a8e55Smrg{
3138c4a8e55Smrg    render->matrix11 = x->matrix[0][0];
3148c4a8e55Smrg    render->matrix12 = x->matrix[0][1];
3158c4a8e55Smrg    render->matrix13 = x->matrix[0][2];
3168c4a8e55Smrg
3178c4a8e55Smrg    render->matrix21 = x->matrix[1][0];
3188c4a8e55Smrg    render->matrix22 = x->matrix[1][1];
3198c4a8e55Smrg    render->matrix23 = x->matrix[1][2];
3208c4a8e55Smrg
3218c4a8e55Smrg    render->matrix31 = x->matrix[2][0];
3228c4a8e55Smrg    render->matrix32 = x->matrix[2][1];
3238c4a8e55Smrg    render->matrix33 = x->matrix[2][2];
3248c4a8e55Smrg}
3258c4a8e55Smrg
3268c4a8e55Smrgvoid
3278c4a8e55SmrgXRRSetCrtcTransform (Display	*dpy,
3280597fb56Smrg		     RRCrtc	crtc,
3298c4a8e55Smrg		     XTransform	*transform,
3308bd17e5fSmrg		     _Xconst char *filter,
3318c4a8e55Smrg		     XFixed	*params,
3328c4a8e55Smrg		     int	nparams)
3338c4a8e55Smrg{
3348c4a8e55Smrg    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
3358c4a8e55Smrg    xRRSetCrtcTransformReq  *req;
3368c4a8e55Smrg    int			    nbytes = strlen (filter);
3378c4a8e55Smrg
3388c4a8e55Smrg    RRSimpleCheckExtension (dpy, info);
3398c4a8e55Smrg
3408c4a8e55Smrg    LockDisplay(dpy);
3418c4a8e55Smrg    GetReq (RRSetCrtcTransform, req);
3428c4a8e55Smrg    req->reqType = info->codes->major_opcode;
3438c4a8e55Smrg    req->randrReqType = X_RRSetCrtcTransform;
3448c4a8e55Smrg    req->crtc = crtc;
3458c4a8e55Smrg
3468c4a8e55Smrg    xRenderTransform_from_XTransform (&req->transform, transform);
3478c4a8e55Smrg
3488c4a8e55Smrg    req->nbytesFilter = nbytes;
3498c4a8e55Smrg    req->length += ((nbytes + 3) >> 2) + nparams;
3508c4a8e55Smrg    Data (dpy, filter, nbytes);
3518c4a8e55Smrg    Data32 (dpy, params, nparams << 2);
3528c4a8e55Smrg
3538c4a8e55Smrg    UnlockDisplay (dpy);
3548c4a8e55Smrg    SyncHandle ();
3558c4a8e55Smrg}
3568c4a8e55Smrg
3578c4a8e55Smrg#define CrtcTransformExtra	(SIZEOF(xRRGetCrtcTransformReply) - 32)
3580597fb56Smrg
3598c4a8e55Smrgstatic const xRenderTransform identity = {
3608c4a8e55Smrg    0x10000, 0, 0,
3618c4a8e55Smrg    0, 0x10000, 0,
3628c4a8e55Smrg    0, 0, 0x10000,
3638c4a8e55Smrg};
3648c4a8e55Smrg
3658c4a8e55Smrgstatic Bool
3668c4a8e55Smrg_XRRHasTransform (int major, int minor)
3678c4a8e55Smrg{
3688c4a8e55Smrg    return major > 1 || (major == 1 && minor >= 3);
3698c4a8e55Smrg}
3708c4a8e55Smrg
3718c4a8e55SmrgStatus
3728c4a8e55SmrgXRRGetCrtcTransform (Display	*dpy,
3738c4a8e55Smrg		     RRCrtc	crtc,
3748c4a8e55Smrg		     XRRCrtcTransformAttributes **attributes)
3758c4a8e55Smrg{
3768c4a8e55Smrg    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
3778c4a8e55Smrg    xRRGetCrtcTransformReply	rep;
3788c4a8e55Smrg    int				major_version, minor_version;
3798c4a8e55Smrg    XRRCrtcTransformAttributes	*attr;
380b242714cSmrg    char			*extra = NULL, *end = NULL, *e;
3818c4a8e55Smrg
3828c4a8e55Smrg    *attributes = NULL;
3838c4a8e55Smrg
3848c4a8e55Smrg    RRCheckExtension (dpy, info, False);
3858c4a8e55Smrg
3860597fb56Smrg    if (!XRRQueryVersion (dpy, &major_version, &minor_version) ||
3878c4a8e55Smrg	!_XRRHasTransform (major_version, minor_version))
3888c4a8e55Smrg    {
3898c4a8e55Smrg	/* For pre-1.3 servers, just report identity matrices everywhere */
3908c4a8e55Smrg	rep.pendingTransform = identity;
3918c4a8e55Smrg	rep.pendingNbytesFilter = 0;
3928c4a8e55Smrg	rep.pendingNparamsFilter = 0;
3938c4a8e55Smrg	rep.currentTransform = identity;
3948c4a8e55Smrg	rep.currentNbytesFilter = 0;
3958c4a8e55Smrg	rep.currentNparamsFilter = 0;
3968c4a8e55Smrg    }
3978c4a8e55Smrg    else
3988c4a8e55Smrg    {
3998d0bc965Smrg	xRRGetCrtcTransformReq	*req;
4008d0bc965Smrg
4018c4a8e55Smrg	LockDisplay (dpy);
4028c4a8e55Smrg	GetReq (RRGetCrtcTransform, req);
4038c4a8e55Smrg	req->reqType = info->codes->major_opcode;
4048c4a8e55Smrg	req->randrReqType = X_RRGetCrtcTransform;
4058c4a8e55Smrg	req->crtc = crtc;
4060597fb56Smrg
4078c4a8e55Smrg	if (!_XReply (dpy, (xReply *) &rep, CrtcTransformExtra >> 2, xFalse))
4088c4a8e55Smrg	{
4098c4a8e55Smrg	    rep.pendingTransform = identity;
4108c4a8e55Smrg	    rep.pendingNbytesFilter = 0;
4118c4a8e55Smrg	    rep.pendingNparamsFilter = 0;
4128c4a8e55Smrg	    rep.currentTransform = identity;
4138c4a8e55Smrg	    rep.currentNbytesFilter = 0;
4148c4a8e55Smrg	    rep.currentNparamsFilter = 0;
4158c4a8e55Smrg	}
4168c4a8e55Smrg	else
4178c4a8e55Smrg	{
4188c4a8e55Smrg	    int extraBytes = rep.length * 4 - CrtcTransformExtra;
419b242714cSmrg	    if (rep.length < INT_MAX / 4 &&
420b242714cSmrg		rep.length * 4 >= CrtcTransformExtra) {
421b242714cSmrg		extra = Xmalloc (extraBytes);
422b242714cSmrg		end = extra + extraBytes;
423b242714cSmrg	    } else
424b242714cSmrg		extra = NULL;
4258c4a8e55Smrg	    if (!extra) {
426b242714cSmrg		if (rep.length > (CrtcTransformExtra >> 2))
427b242714cSmrg		    _XEatDataWords (dpy, rep.length - (CrtcTransformExtra >> 2));
428b242714cSmrg		else
429b242714cSmrg		    _XEatDataWords (dpy, rep.length);
4308c4a8e55Smrg		UnlockDisplay (dpy);
4318c4a8e55Smrg		SyncHandle ();
4328c4a8e55Smrg		return False;
4338c4a8e55Smrg	    }
4348c4a8e55Smrg	    _XRead (dpy, extra, extraBytes);
4358c4a8e55Smrg	}
4368c4a8e55Smrg
4378c4a8e55Smrg	UnlockDisplay (dpy);
4388c4a8e55Smrg	SyncHandle ();
4398c4a8e55Smrg    }
4408c4a8e55Smrg
4418c4a8e55Smrg    attr = Xmalloc (sizeof (XRRCrtcTransformAttributes) +
4428c4a8e55Smrg		    rep.pendingNparamsFilter * sizeof (XFixed) +
4438c4a8e55Smrg		    rep.currentNparamsFilter * sizeof (XFixed) +
4448c4a8e55Smrg		    rep.pendingNbytesFilter + 1 +
4458c4a8e55Smrg		    rep.currentNbytesFilter + 1);
4468c4a8e55Smrg
4478c4a8e55Smrg    if (!attr) {
4488c4a8e55Smrg	XFree (extra);
4498c4a8e55Smrg	return False;
4508c4a8e55Smrg    }
4518c4a8e55Smrg    XTransform_from_xRenderTransform (&attr->pendingTransform, &rep.pendingTransform);
4528c4a8e55Smrg    XTransform_from_xRenderTransform (&attr->currentTransform, &rep.currentTransform);
4538c4a8e55Smrg
4548c4a8e55Smrg    attr->pendingParams = (XFixed *) (attr + 1);
4558c4a8e55Smrg    attr->currentParams = attr->pendingParams + rep.pendingNparamsFilter;
4568c4a8e55Smrg    attr->pendingFilter = (char *) (attr->currentParams + rep.currentNparamsFilter);
4578c4a8e55Smrg    attr->currentFilter = attr->pendingFilter + rep.pendingNbytesFilter + 1;
4588c4a8e55Smrg
4598c4a8e55Smrg    e = extra;
4608c4a8e55Smrg
461b242714cSmrg    if (e + rep.pendingNbytesFilter > end) {
4623169be4bSmrg	XFree (attr);
463b242714cSmrg	XFree (extra);
464b242714cSmrg	return False;
465b242714cSmrg    }
4668c4a8e55Smrg    memcpy (attr->pendingFilter, e, rep.pendingNbytesFilter);
4678c4a8e55Smrg    attr->pendingFilter[rep.pendingNbytesFilter] = '\0';
4688c4a8e55Smrg    e += (rep.pendingNbytesFilter + 3) & ~3;
4698d0bc965Smrg    for (unsigned int p = 0; p < rep.pendingNparamsFilter; p++) {
4708c4a8e55Smrg	INT32	f;
471b242714cSmrg	if (e + 4 > end) {
4723169be4bSmrg	    XFree (attr);
473b242714cSmrg	    XFree (extra);
474b242714cSmrg	    return False;
475b242714cSmrg	}
4768c4a8e55Smrg	memcpy (&f, e, 4);
4778c4a8e55Smrg	e += 4;
4788c4a8e55Smrg	attr->pendingParams[p] = (XFixed) f;
4798c4a8e55Smrg    }
4808c4a8e55Smrg    attr->pendingNparams = rep.pendingNparamsFilter;
4818c4a8e55Smrg
482b242714cSmrg    if (e + rep.currentNbytesFilter > end) {
4833169be4bSmrg	XFree (attr);
484b242714cSmrg	XFree (extra);
485b242714cSmrg	return False;
486b242714cSmrg    }
4878c4a8e55Smrg    memcpy (attr->currentFilter, e, rep.currentNbytesFilter);
4888c4a8e55Smrg    attr->currentFilter[rep.currentNbytesFilter] = '\0';
4898c4a8e55Smrg    e += (rep.currentNbytesFilter + 3) & ~3;
4908d0bc965Smrg    for (unsigned int p = 0; p < rep.currentNparamsFilter; p++) {
4918c4a8e55Smrg	INT32	f;
492b242714cSmrg	if (e + 4 > end) {
4933169be4bSmrg	    XFree (attr);
494b242714cSmrg	    XFree (extra);
495b242714cSmrg	    return False;
496b242714cSmrg	}
4978c4a8e55Smrg	memcpy (&f, e, 4);
4988c4a8e55Smrg	e += 4;
4998c4a8e55Smrg	attr->currentParams[p] = (XFixed) f;
5008c4a8e55Smrg    }
5018c4a8e55Smrg    attr->currentNparams = rep.currentNparamsFilter;
5028c4a8e55Smrg
5038c4a8e55Smrg    if (extra)
5048c4a8e55Smrg	XFree (extra);
5058c4a8e55Smrg    *attributes = attr;
5068c4a8e55Smrg
5078c4a8e55Smrg    return True;
5088c4a8e55Smrg}
5098c4a8e55Smrg
5108c4a8e55SmrgXRRPanning *
5118c4a8e55SmrgXRRGetPanning (Display *dpy, XRRScreenResources *resources, RRCrtc crtc)
5128c4a8e55Smrg{
5138c4a8e55Smrg    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
5148c4a8e55Smrg    xRRGetPanningReply	    rep;
5158c4a8e55Smrg    xRRGetPanningReq	    *req;
5168c4a8e55Smrg    XRRPanning		    *xp;
5178c4a8e55Smrg
5188c4a8e55Smrg    RRCheckExtension (dpy, info, NULL);
5198c4a8e55Smrg
5208c4a8e55Smrg    LockDisplay (dpy);
5218c4a8e55Smrg    GetReq (RRGetPanning, req);
5228c4a8e55Smrg    req->reqType         = info->codes->major_opcode;
5238c4a8e55Smrg    req->randrReqType    = X_RRGetPanning;
5248c4a8e55Smrg    req->crtc            = crtc;
5258c4a8e55Smrg
5268c4a8e55Smrg    if (!_XReply (dpy, (xReply *) &rep, 1, xFalse))
5278c4a8e55Smrg    {
5288c4a8e55Smrg	UnlockDisplay (dpy);
5298c4a8e55Smrg	SyncHandle ();
5308c4a8e55Smrg	return NULL;
5318c4a8e55Smrg    }
5328c4a8e55Smrg
5338d0bc965Smrg    if (! (xp = Xmalloc(sizeof(XRRPanning))) ) {
5348c4a8e55Smrg	_XEatData (dpy, sizeof(XRRPanning));
5358c4a8e55Smrg	UnlockDisplay (dpy);
5368c4a8e55Smrg	SyncHandle ();
5378c4a8e55Smrg	return NULL;
5388c4a8e55Smrg    }
5398c4a8e55Smrg
5408c4a8e55Smrg    xp->timestamp     = rep.timestamp;
5418c4a8e55Smrg    xp->left          = rep.left;
5428c4a8e55Smrg    xp->top           = rep.top;
5438c4a8e55Smrg    xp->width         = rep.width;
5448c4a8e55Smrg    xp->height        = rep.height;
5458c4a8e55Smrg    xp->track_left    = rep.track_left;
5468c4a8e55Smrg    xp->track_top     = rep.track_top;
5478c4a8e55Smrg    xp->track_width   = rep.track_width;
5488c4a8e55Smrg    xp->track_height  = rep.track_height;
5498c4a8e55Smrg    xp->border_left   = rep.border_left;
5508c4a8e55Smrg    xp->border_top    = rep.border_top;
5518c4a8e55Smrg    xp->border_right  = rep.border_right;
5528c4a8e55Smrg    xp->border_bottom = rep.border_bottom;
5538c4a8e55Smrg
5548c4a8e55Smrg    UnlockDisplay (dpy);
5558c4a8e55Smrg    SyncHandle ();
5568c4a8e55Smrg    return (XRRPanning *) xp;
5578c4a8e55Smrg}
5588c4a8e55Smrg
5598c4a8e55Smrgvoid
5608c4a8e55SmrgXRRFreePanning (XRRPanning *panning)
5618c4a8e55Smrg{
5628c4a8e55Smrg    Xfree (panning);
5638c4a8e55Smrg}
5648c4a8e55Smrg
5658c4a8e55SmrgStatus
5668c4a8e55SmrgXRRSetPanning (Display *dpy,
5678c4a8e55Smrg               XRRScreenResources *resources,
5688c4a8e55Smrg               RRCrtc crtc,
5698c4a8e55Smrg               XRRPanning *panning)
5708c4a8e55Smrg{
5718c4a8e55Smrg    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
5728c4a8e55Smrg    xRRSetPanningReply      rep;
5738c4a8e55Smrg    xRRSetPanningReq	    *req;
5748c4a8e55Smrg
5758c4a8e55Smrg    RRCheckExtension (dpy, info, 0);
5768c4a8e55Smrg
5778c4a8e55Smrg    LockDisplay(dpy);
5788c4a8e55Smrg    GetReq (RRSetPanning, req);
5798c4a8e55Smrg    req->reqType       = info->codes->major_opcode;
5808c4a8e55Smrg    req->randrReqType  = X_RRSetPanning;
5818c4a8e55Smrg    req->crtc          = crtc;
5828c4a8e55Smrg    req->timestamp     = panning->timestamp;
5838c4a8e55Smrg    req->left          = panning->left;
5848c4a8e55Smrg    req->top           = panning->top;
5858c4a8e55Smrg    req->width         = panning->width;
5868c4a8e55Smrg    req->height        = panning->height;
5878c4a8e55Smrg    req->track_left    = panning->track_left;
5888c4a8e55Smrg    req->track_top     = panning->track_top;
5898c4a8e55Smrg    req->track_width   = panning->track_width;
5908c4a8e55Smrg    req->track_height  = panning->track_height;
5918c4a8e55Smrg    req->border_left   = panning->border_left;
5928c4a8e55Smrg    req->border_top    = panning->border_top;
5938c4a8e55Smrg    req->border_right  = panning->border_right;
5948c4a8e55Smrg    req->border_bottom = panning->border_bottom;
5958c4a8e55Smrg
5968c4a8e55Smrg    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
5978c4a8e55Smrg	rep.status = RRSetConfigFailed;
5988c4a8e55Smrg    UnlockDisplay (dpy);
5998c4a8e55Smrg    SyncHandle ();
6008c4a8e55Smrg    return rep.status;
6018c4a8e55Smrg}
6028c4a8e55Smrg
603