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