XrrScreen.c revision b242714c
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/*
37 * this is cheating on the knowledge that the two requests are identical
38 * but for the request number.
39 */
40static XRRScreenResources *
41doGetScreenResources (Display *dpy, Window window, int poll)
42{
43    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
44    xRRGetScreenResourcesReply  rep;
45    xRRGetScreenResourcesReq	*req;
46    _XAsyncHandler		async;
47    _XRRVersionState		async_state;
48    int				nbytes, nbytesRead, rbytes;
49    int				i;
50    xRRQueryVersionReq		*vreq;
51    XRRScreenResources		*xrsr;
52    char			*names;
53    char			*wire_names, *wire_name;
54    Bool			getting_version = False;
55    XRandRInfo			*xrri;
56
57    RRCheckExtension (dpy, info, NULL);
58
59    LockDisplay (dpy);
60    xrri = (XRandRInfo *) info->data;
61
62    if (xrri->major_version == -1)
63    {
64	/* hide a version query in the request */
65	GetReq (RRQueryVersion, vreq);
66	vreq->reqType = info->codes->major_opcode;
67	vreq->randrReqType = X_RRQueryVersion;
68	vreq->majorVersion = RANDR_MAJOR;
69	vreq->minorVersion = RANDR_MINOR;
70
71	async_state.version_seq = dpy->request;
72	async_state.error = False;
73	async.next = dpy->async_handlers;
74	async.handler = _XRRVersionHandler;
75	async.data = (XPointer) &async_state;
76	dpy->async_handlers = &async;
77
78	getting_version = True;
79    }
80
81    GetReq (RRGetScreenResources, req);
82    req->reqType = info->codes->major_opcode;
83    req->randrReqType = poll ? X_RRGetScreenResources
84			     : X_RRGetScreenResourcesCurrent;
85    req->window = window;
86
87    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
88    {
89	if (getting_version)
90	    DeqAsyncHandler (dpy, &async);
91	UnlockDisplay (dpy);
92	SyncHandle ();
93	return NULL;
94    }
95    if (getting_version)
96    {
97	DeqAsyncHandler (dpy, &async);
98	if (async_state.error)
99	{
100	    UnlockDisplay (dpy);
101	    SyncHandle();
102	    LockDisplay (dpy);
103	}
104	xrri->major_version = async_state.major_version;
105	xrri->minor_version = async_state.minor_version;
106	xrri->has_rates = _XRRHasRates (xrri->minor_version, xrri->major_version);
107    }
108
109    if (rep.length < INT_MAX >> 2) {
110	nbytes = (long) rep.length << 2;
111
112	nbytesRead = (long) (rep.nCrtcs * 4 +
113			     rep.nOutputs * 4 +
114			     rep.nModes * SIZEOF (xRRModeInfo) +
115			     ((rep.nbytesNames + 3) & ~3));
116
117	/*
118	 * first we must compute how much space to allocate for
119	 * randr library's use; we'll allocate the structures in a single
120	 * allocation, on cleanlyness grounds.
121	 */
122
123	rbytes = (sizeof (XRRScreenResources) +
124		  rep.nCrtcs * sizeof (RRCrtc) +
125		  rep.nOutputs * sizeof (RROutput) +
126		  rep.nModes * sizeof (XRRModeInfo) +
127		  rep.nbytesNames + rep.nModes);    /* '\0' terminate names */
128
129	xrsr = (XRRScreenResources *) Xmalloc(rbytes);
130	wire_names = (char *) Xmalloc (rep.nbytesNames);
131    } else {
132	nbytes = 0;
133	nbytesRead = 0;
134	rbytes = 0;
135	xrsr = NULL;
136	wire_names = NULL;
137    }
138
139    if (xrsr == NULL || wire_names == NULL) {
140	Xfree (xrsr);
141	Xfree (wire_names);
142	_XEatDataWords (dpy, rep.length);
143	UnlockDisplay (dpy);
144	SyncHandle ();
145	return NULL;
146    }
147
148    xrsr->timestamp = rep.timestamp;
149    xrsr->configTimestamp = rep.configTimestamp;
150    xrsr->ncrtc = rep.nCrtcs;
151    xrsr->crtcs = (RRCrtc *) (xrsr + 1);
152    xrsr->noutput = rep.nOutputs;
153    xrsr->outputs = (RROutput *) (xrsr->crtcs + rep.nCrtcs);
154    xrsr->nmode = rep.nModes;
155    xrsr->modes = (XRRModeInfo *) (xrsr->outputs + rep.nOutputs);
156    names = (char *) (xrsr->modes + rep.nModes);
157
158    _XRead32 (dpy, (long *) xrsr->crtcs, rep.nCrtcs << 2);
159    _XRead32 (dpy, (long *) xrsr->outputs, rep.nOutputs << 2);
160
161    for (i = 0; i < rep.nModes; i++)  {
162	xRRModeInfo modeInfo;
163
164	_XReadPad (dpy, (char *) &modeInfo, SIZEOF (xRRModeInfo));
165	xrsr->modes[i].id = modeInfo.id;
166	xrsr->modes[i].width = modeInfo.width;
167	xrsr->modes[i].height = modeInfo.height;
168	xrsr->modes[i].dotClock = modeInfo.dotClock;
169	xrsr->modes[i].hSyncStart = modeInfo.hSyncStart;
170	xrsr->modes[i].hSyncEnd = modeInfo.hSyncEnd;
171	xrsr->modes[i].hTotal = modeInfo.hTotal;
172	xrsr->modes[i].hSkew = modeInfo.hSkew;
173	xrsr->modes[i].vSyncStart = modeInfo.vSyncStart;
174	xrsr->modes[i].vSyncEnd = modeInfo.vSyncEnd;
175	xrsr->modes[i].vTotal = modeInfo.vTotal;
176	xrsr->modes[i].nameLength = modeInfo.nameLength;
177	xrsr->modes[i].modeFlags = modeInfo.modeFlags;
178    }
179
180    /*
181     * Read names and '\0' pad each one
182     */
183    _XReadPad (dpy, wire_names, rep.nbytesNames);
184    wire_name = wire_names;
185    for (i = 0; i < rep.nModes; i++)  {
186	xrsr->modes[i].name = names;
187	if (xrsr->modes[i].nameLength > rep.nbytesNames) {
188	    Xfree (xrsr);
189	    Xfree (wire_names);
190	    UnlockDisplay (dpy);
191	    SyncHandle ();
192	    return NULL;
193	}
194	rep.nbytesNames -= xrsr->modes[i].nameLength;
195	memcpy (names, wire_name, xrsr->modes[i].nameLength);
196	names[xrsr->modes[i].nameLength] = '\0';
197	names += xrsr->modes[i].nameLength + 1;
198	wire_name += xrsr->modes[i].nameLength;
199    }
200    Xfree (wire_names);
201
202    /*
203     * Skip any extra data
204     */
205    if (nbytes > nbytesRead)
206	_XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
207
208    UnlockDisplay (dpy);
209    SyncHandle();
210    return (XRRScreenResources *) xrsr;
211}
212
213XRRScreenResources *
214XRRGetScreenResources(Display *dpy, Window window)
215{
216    return doGetScreenResources(dpy, window, 1);
217}
218
219XRRScreenResources *
220XRRGetScreenResourcesCurrent(Display *dpy, Window window)
221{
222    return doGetScreenResources(dpy, window, 0);
223}
224
225void
226XRRFreeScreenResources (XRRScreenResources *resources)
227{
228    Xfree (resources);
229}
230
231Status
232XRRGetScreenSizeRange (Display *dpy, Window window,
233		       int *minWidth, int *minHeight,
234		       int *maxWidth, int *maxHeight)
235{
236    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
237    xRRGetScreenSizeRangeReq	*req;
238    xRRGetScreenSizeRangeReply	rep;
239
240    RRCheckExtension (dpy, info, 0);
241    LockDisplay (dpy);
242    GetReq (RRGetScreenSizeRange, req);
243    req->reqType = info->codes->major_opcode;
244    req->randrReqType = X_RRGetScreenSizeRange;
245    req->window = window;
246    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
247    {
248	UnlockDisplay (dpy);
249	SyncHandle ();
250	return False;
251    }
252    UnlockDisplay (dpy);
253    SyncHandle ();
254    *minWidth = rep.minWidth;
255    *minHeight = rep.minHeight;
256    *maxWidth = rep.maxWidth;
257    *maxHeight = rep.maxHeight;
258   return True;
259}
260
261void
262XRRSetScreenSize (Display *dpy, Window window,
263		  int width, int height,
264		  int mmWidth, int mmHeight)
265{
266    XExtDisplayInfo		*info = XRRFindDisplay(dpy);
267    xRRSetScreenSizeReq		*req;
268
269    RRSimpleCheckExtension (dpy, info);
270    LockDisplay (dpy);
271    GetReq (RRSetScreenSize, req);
272    req->reqType = info->codes->major_opcode;
273    req->randrReqType = X_RRSetScreenSize;
274    req->window = window;
275    req->width = width;
276    req->height = height;
277    req->widthInMillimeters = mmWidth;
278    req->heightInMillimeters = mmHeight;
279    UnlockDisplay (dpy);
280    SyncHandle ();
281}
282