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