1 /* functions for grabbing information about xrandr screens
2 * Copyright (C) 2016 Mathieu OTHACEHE <m.othacehe@gmail.com>
3 *
4 * This file is part of ratpoison.
5 *
6 * ratpoison is free software; you can redistribute it and/or moify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * ratpoison is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this software; see the file COPYING. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307 USA
20 */
21
22 #include "ratpoison.h"
23
24 #include <X11/extensions/Xrandr.h>
25
26 static int xrandr_evbase;
27
28 #define XRANDR_MAJOR 1
29 #define XRANDR_MINOR 3
30
31 void
init_xrandr(void)32 init_xrandr (void)
33 {
34 int errbase, major, minor;
35
36 if (!XRRQueryExtension (dpy, &xrandr_evbase, &errbase)) {
37 return;
38 }
39
40 if (XRRQueryVersion (dpy, &major, &minor) == 0) {
41 return;
42 }
43
44 if (major != XRANDR_MAJOR ||
45 (major == XRANDR_MAJOR && minor < XRANDR_MINOR)) {
46 PRINT_ERROR (("Xrandr version %d.%d is not supported\n", major, minor));
47 return;
48 }
49
50 XRRSelectInput (dpy, RootWindow (dpy, DefaultScreen(dpy)),
51 RRCrtcChangeNotifyMask | RROutputChangeNotifyMask);
52
53 rp_have_xrandr = 1;
54 }
55
56 int *
xrandr_query_screen(int * screen_count)57 xrandr_query_screen (int *screen_count)
58 {
59 XRRScreenResources *res;
60 XRROutputInfo *outinfo;
61 int *output_array;
62 int count = 0;
63 int i;
64
65 res = XRRGetScreenResources (dpy, RootWindow (dpy, DefaultScreen (dpy)));
66 output_array = xmalloc (res->noutput * sizeof(int));
67
68 for (i = 0; i < res->noutput; i++) {
69 outinfo = XRRGetOutputInfo (dpy, res, res->outputs[i]);
70 if (!outinfo->crtc)
71 continue;
72
73 output_array[count] = res->outputs[i];
74 count++;
75
76 XRRFreeOutputInfo (outinfo);
77 }
78
79 *screen_count = count;
80 XRRFreeScreenResources (res);
81
82 return output_array;
83 }
84
85 static rp_screen *
xrandr_screen_output(int rr_output)86 xrandr_screen_output (int rr_output)
87 {
88 rp_screen *cur;
89
90 list_for_each_entry (cur, &rp_screens, node)
91 {
92 if (cur->xrandr.output == rr_output)
93 return cur;
94 }
95
96 return NULL;
97 }
98
99 static rp_screen *
xrandr_screen_crtc(int rr_crtc)100 xrandr_screen_crtc (int rr_crtc)
101 {
102 rp_screen *cur;
103
104 list_for_each_entry (cur, &rp_screens, node)
105 {
106 if (cur->xrandr.crtc == rr_crtc)
107 return cur;
108 }
109
110 return NULL;
111 }
112
113 int
xrandr_is_primary(rp_screen * screen)114 xrandr_is_primary (rp_screen *screen)
115 {
116 return screen->xrandr.primary;
117 }
118
119 void
xrandr_fill_screen(int rr_output,rp_screen * screen)120 xrandr_fill_screen (int rr_output, rp_screen *screen)
121 {
122 XRRScreenResources *res;
123 XRROutputInfo *outinfo;
124 XRRCrtcInfo *crtinfo;
125 RROutput primary;
126
127 res = XRRGetScreenResourcesCurrent (dpy, RootWindow (dpy, DefaultScreen (dpy)));
128 outinfo = XRRGetOutputInfo (dpy, res, rr_output);
129 if (!outinfo->crtc)
130 goto free_res;
131
132 crtinfo = XRRGetCrtcInfo (dpy, res, outinfo->crtc);
133 if (!crtinfo)
134 goto free_out;
135
136 primary = XRRGetOutputPrimary (dpy, RootWindow (dpy, DefaultScreen (dpy)));
137 if (rr_output == primary)
138 screen->xrandr.primary = 1;
139 else
140 screen->xrandr.primary = 0;
141
142 screen->xrandr.name = sbuf_new (0);
143 sbuf_concat (screen->xrandr.name, outinfo->name);
144
145 screen->xrandr.output = rr_output;
146 screen->xrandr.crtc = outinfo->crtc;
147
148 screen->left = crtinfo->x;
149 screen->top = crtinfo->y;
150 screen->width = crtinfo->width;
151 screen->height = crtinfo->height;
152
153 XRRFreeCrtcInfo (crtinfo);
154 free_out:
155 XRRFreeOutputInfo (outinfo);
156 free_res:
157 XRRFreeScreenResources (res);
158 }
159
160 static void
xrandr_output_change(XRROutputChangeNotifyEvent * ev)161 xrandr_output_change (XRROutputChangeNotifyEvent *ev)
162 {
163 XRRScreenResources *res;
164 XRROutputInfo *outinfo;
165 rp_screen *screen;
166
167 res = XRRGetScreenResourcesCurrent (dpy, RootWindow (dpy, DefaultScreen (dpy)));
168 outinfo = XRRGetOutputInfo (dpy, res, ev->output);
169
170 screen = xrandr_screen_output (ev->output);
171
172 if (!screen && outinfo->crtc) {
173 screen = screen_add (ev->output);
174 screen_sort ();
175 PRINT_DEBUG (("%s: Added screen %s with crtc %lu\n", __func__,
176 sbuf_get (screen->xrandr.name),
177 (unsigned long)outinfo->crtc));
178 } else if (screen && !outinfo->crtc) {
179 PRINT_DEBUG (("%s: Removing screen %s\n", __func__,
180 sbuf_get (screen->xrandr.name)));
181 screen_del (screen);
182 }
183
184 XRRFreeOutputInfo (outinfo);
185 XRRFreeScreenResources (res);
186 }
187
188 #ifdef DEBUG
189 static const char *
xrandr_rotation_string(Rotation r)190 xrandr_rotation_string (Rotation r)
191 {
192 static char buf[64];
193
194 #define CASE(c) case c : return #c
195 switch (r)
196 {
197 CASE(RR_Rotate_0);
198 CASE(RR_Rotate_90);
199 CASE(RR_Rotate_180);
200 CASE(RR_Rotate_270);
201 #undef CASE
202 default:
203 snprintf(buf, sizeof buf, "Unknown rotation %hu", (unsigned short)r);
204 return buf;
205 }
206 }
207 #endif
208
209 static void
xrandr_crtc_change(XRRCrtcChangeNotifyEvent * ev)210 xrandr_crtc_change (XRRCrtcChangeNotifyEvent *ev)
211 {
212 rp_screen *screen;
213
214 if (!ev->crtc || !ev->width || !ev->height)
215 return;
216
217 screen = xrandr_screen_crtc (ev->crtc);
218
219 PRINT_DEBUG (("%s: crtc %s, rotation %s "
220 "ev->x %d, ev->y %d, ev->width %d, ev->height %d\n",
221 __func__, screen ? "found" : "not found",
222 xrandr_rotation_string (ev->rotation),
223 ev->x, ev->y, ev->width, ev->height));
224
225 if (!screen)
226 return;
227
228 if (ev->rotation == RR_Rotate_90 || ev->rotation == RR_Rotate_270)
229 screen_update (screen, ev->x, ev->y, ev->height, ev->width);
230 else
231 screen_update (screen, ev->x, ev->y, ev->width, ev->height);
232 }
233
234 void
xrandr_notify(XEvent * ev)235 xrandr_notify (XEvent *ev)
236 {
237 XRRNotifyEvent *n_event;
238 XRROutputChangeNotifyEvent *o_event;
239 XRRCrtcChangeNotifyEvent *c_event;
240
241 if (ev->type != xrandr_evbase + RRNotify)
242 return;
243
244 PRINT_DEBUG (("--- Handling RRNotify ---\n"));
245
246 n_event = (XRRNotifyEvent *)ev;
247 switch (n_event->subtype) {
248 case RRNotify_OutputChange:
249 PRINT_DEBUG (("--- XRROutputChangeNotifyEvent ---\n"));
250 o_event = (XRROutputChangeNotifyEvent *)ev;
251 xrandr_output_change (o_event);
252 break;
253 case RRNotify_CrtcChange:
254 PRINT_DEBUG (("--- XRRCrtcChangeNotifyEvent ---\n"));
255 c_event = (XRRCrtcChangeNotifyEvent *)ev;
256 xrandr_crtc_change (c_event);
257 break;
258 case RRNotify_OutputProperty:
259 PRINT_DEBUG (("--- RRNotify_OutputProperty ---\n"));
260 break;
261 default:
262 PRINT_DEBUG (("--- Unknown subtype %d ---\n", n_event->subtype));
263 break;
264 }
265 }
266