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