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
36 XRRMonitorInfo *
XRRGetMonitors(Display * dpy,Window window,Bool get_active,int * nmonitors)37 XRRGetMonitors(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
153 void
XRRSetMonitor(Display * dpy,Window window,XRRMonitorInfo * monitor)154 XRRSetMonitor(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
183 void
XRRDeleteMonitor(Display * dpy,Window window,Atom name)184 XRRDeleteMonitor(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
201 XRRMonitorInfo *
XRRAllocateMonitor(Display * dpy,int noutput)202 XRRAllocateMonitor(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
212 void
XRRFreeMonitors(XRRMonitorInfo * monitors)213 XRRFreeMonitors(XRRMonitorInfo *monitors)
214 {
215 Xfree(monitors);
216 }
217
218