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