XrrMonitor.c revision b242714c
1/*
2 * Copyright © 2014 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
36XRRMonitorInfo *
37XRRGetMonitors(Display *dpy, Window window, Bool get_active, int *nmonitors)
38{
39    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
40    xRRGetMonitorsReply	    rep;
41    xRRGetMonitorsReq	    *req;
42    int			    nbytes, nbytesRead, rbytes;
43    int			    nmon, noutput;
44    int			    m, o;
45    char		    *buf, *buf_head;
46    xRRMonitorInfo	    *xmon;
47    CARD32		    *xoutput;
48    XRRMonitorInfo	    *mon = NULL;
49    RROutput		    *output;
50
51    RRCheckExtension (dpy, info, NULL);
52
53    *nmonitors = -1;
54
55    LockDisplay (dpy);
56    GetReq (RRGetMonitors, req);
57    req->reqType = info->codes->major_opcode;
58    req->randrReqType = X_RRGetMonitors;
59    req->window = window;
60    req->get_active = get_active;
61
62    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse))
63    {
64	UnlockDisplay (dpy);
65	SyncHandle ();
66	return NULL;
67    }
68
69    if (rep.length > INT_MAX >> 2 ||
70	rep.nmonitors > INT_MAX / SIZEOF(xRRMonitorInfo) ||
71	rep.noutputs > INT_MAX / 4 ||
72	rep.nmonitors * SIZEOF(xRRMonitorInfo) > INT_MAX - rep.noutputs * 4) {
73	_XEatData (dpy, rep.length);
74	UnlockDisplay (dpy);
75	SyncHandle ();
76	return NULL;
77    }
78    nbytes = (long) rep.length << 2;
79    nmon = rep.nmonitors;
80    noutput = rep.noutputs;
81    nbytesRead = nmon * SIZEOF(xRRMonitorInfo) + noutput * 4;
82
83    if (nmon > 0) {
84
85	/*
86	 * first we must compute how much space to allocate for
87	 * randr library's use; we'll allocate the structures in a single
88	 * allocation, on cleanlyness grounds.
89	 */
90
91	rbytes = nmon * sizeof (XRRMonitorInfo) + noutput * sizeof(RROutput);
92
93	buf = buf_head = Xmalloc (nbytesRead);
94	mon = Xmalloc (rbytes);
95
96	if (buf == NULL || mon == NULL) {
97	    Xfree(buf);
98	    Xfree(mon);
99	    _XEatDataWords (dpy, rep.length);
100	    UnlockDisplay (dpy);
101	    SyncHandle ();
102	    return NULL;
103	}
104
105	_XReadPad(dpy, buf, nbytesRead);
106
107	output = (RROutput *) (mon + nmon);
108
109	for (m = 0; m < nmon; m++) {
110	    xmon = (xRRMonitorInfo *) buf;
111	    mon[m].name = xmon->name;
112	    mon[m].primary = xmon->primary;
113	    mon[m].automatic = xmon->automatic;
114	    mon[m].noutput = xmon->noutput;
115	    mon[m].x = xmon->x;
116	    mon[m].y = xmon->y;
117	    mon[m].width = xmon->width;
118	    mon[m].height = xmon->height;
119	    mon[m].mwidth = xmon->widthInMillimeters;
120	    mon[m].mheight = xmon->heightInMillimeters;
121	    mon[m].outputs = output;
122	    buf += SIZEOF (xRRMonitorInfo);
123	    xoutput = (CARD32 *) buf;
124	    if (xmon->noutput > rep.noutputs) {
125	        Xfree(buf);
126	        Xfree(mon);
127	        UnlockDisplay (dpy);
128	        SyncHandle ();
129	        return NULL;
130	    }
131	    rep.noutputs -= xmon->noutput;
132	    for (o = 0; o < xmon->noutput; o++)
133		output[o] = xoutput[o];
134	    output += xmon->noutput;
135	    buf += xmon->noutput * 4;
136	}
137	Xfree(buf_head);
138    }
139
140    /*
141     * Skip any extra data
142     */
143    if (nbytes > nbytesRead)
144	_XEatData (dpy, (unsigned long) (nbytes - nbytesRead));
145
146    UnlockDisplay (dpy);
147    SyncHandle ();
148
149    *nmonitors = nmon;
150    return mon;
151}
152
153void
154XRRSetMonitor(Display *dpy, Window window, XRRMonitorInfo *monitor)
155{
156    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
157    xRRSetMonitorReq	    *req;
158
159    RRSimpleCheckExtension (dpy, info);
160
161    LockDisplay(dpy);
162    GetReq (RRSetMonitor, req);
163    req->reqType = info->codes->major_opcode;
164    req->randrReqType = X_RRSetMonitor;
165    req->length += monitor->noutput;
166    req->window = window;
167    req->monitor.name = monitor->name;
168    req->monitor.primary = monitor->primary;
169    req->monitor.automatic = False;
170    req->monitor.noutput = monitor->noutput;
171    req->monitor.x = monitor->x;
172    req->monitor.y = monitor->y;
173    req->monitor.width = monitor->width;
174    req->monitor.height = monitor->height;
175    req->monitor.widthInMillimeters = monitor->mwidth;
176    req->monitor.heightInMillimeters = monitor->mheight;
177    Data32 (dpy, monitor->outputs, monitor->noutput * 4);
178
179    UnlockDisplay (dpy);
180    SyncHandle ();
181}
182
183void
184XRRDeleteMonitor(Display *dpy, Window window, Atom name)
185{
186    XExtDisplayInfo	    *info = XRRFindDisplay(dpy);
187    xRRDeleteMonitorReq	    *req;
188
189    RRSimpleCheckExtension (dpy, info);
190
191    LockDisplay(dpy);
192    GetReq (RRDeleteMonitor, req);
193    req->reqType = info->codes->major_opcode;
194    req->randrReqType = X_RRDeleteMonitor;
195    req->window = window;
196    req->name = name;
197    UnlockDisplay (dpy);
198    SyncHandle ();
199}
200
201XRRMonitorInfo *
202XRRAllocateMonitor(Display *dpy, int noutput)
203{
204    XRRMonitorInfo *monitor = calloc(1, sizeof (XRRMonitorInfo) + noutput * sizeof (RROutput));
205    if (!monitor)
206	return NULL;
207    monitor->outputs = (RROutput *) (monitor + 1);
208    monitor->noutput = noutput;
209    return monitor;
210}
211
212void
213XRRFreeMonitors(XRRMonitorInfo *monitors)
214{
215    Xfree(monitors);
216}
217
218