1 /* test-randr.c --- playing with the Resize And Rotate extension.
2 * xscreensaver, Copyright (c) 2004-2008 Jamie Zawinski <jwz@jwz.org>
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
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
10 * implied warranty.
11 */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <stdlib.h>
18 #ifdef HAVE_UNISTD_H
19 # include <unistd.h>
20 #endif
21
22 #include <stdio.h>
23 #include <time.h>
24 #include <sys/time.h>
25
26 #include <X11/Xlib.h>
27 #include <X11/Xatom.h>
28 #include <X11/Intrinsic.h>
29
30 #include <X11/Xproto.h>
31 #include <X11/extensions/Xrandr.h>
32
33 char *progname = 0;
34 char *progclass = "XScreenSaver";
35
36 static const char *
blurb(void)37 blurb (void)
38 {
39 static char buf[255];
40 time_t now = time ((time_t *) 0);
41 char *ct = (char *) ctime (&now);
42 int n = strlen(progname);
43 if (n > 100) n = 99;
44 strncpy(buf, progname, n);
45 buf[n++] = ':';
46 buf[n++] = ' ';
47 strncpy(buf+n, ct+11, 8);
48 strcpy(buf+n+9, ": ");
49 return buf;
50 }
51
52
53 static Bool error_handler_hit_p = False;
54
55 static int
ignore_all_errors_ehandler(Display * dpy,XErrorEvent * error)56 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
57 {
58 error_handler_hit_p = True;
59 return 0;
60 }
61
62
63 int
main(int argc,char ** argv)64 main (int argc, char **argv)
65 {
66 int event_number = -1, error_number = -1;
67 int major = -1, minor = -1;
68 int nscreens = 0;
69 int i;
70
71 XtAppContext app;
72 Widget toplevel_shell = XtAppInitialize (&app, progclass, 0, 0,
73 &argc, argv, 0, 0, 0);
74 Display *dpy = XtDisplay (toplevel_shell);
75 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
76
77 nscreens = ScreenCount(dpy);
78
79 if (!XRRQueryExtension(dpy, &event_number, &error_number))
80 {
81 fprintf(stderr, "%s: XRRQueryExtension(dpy, ...) ==> False\n",
82 blurb());
83 fprintf(stderr, "%s: server does not support the RANDR extension.\n",
84 blurb());
85 major = -1;
86 }
87 else
88 {
89 fprintf(stderr, "%s: XRRQueryExtension(dpy, ...) ==> %d, %d\n",
90 blurb(), event_number, error_number);
91
92 if (!XRRQueryVersion(dpy, &major, &minor))
93 {
94 fprintf(stderr, "%s: XRRQueryVersion(dpy, ...) ==> False\n",
95 blurb());
96 fprintf(stderr, "%s: server didn't report RANDR version numbers?\n",
97 blurb());
98 }
99 else
100 fprintf(stderr, "%s: XRRQueryVersion(dpy, ...) ==> %d, %d\n", blurb(),
101 major, minor);
102 }
103
104 for (i = 0; i < nscreens; i++)
105 {
106 XRRScreenConfiguration *rrc;
107 XErrorHandler old_handler;
108
109 XSync (dpy, False);
110 error_handler_hit_p = False;
111 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
112
113 rrc = (major >= 0 ? XRRGetScreenInfo (dpy, RootWindow (dpy, i)) : 0);
114
115 XSync (dpy, False);
116 XSetErrorHandler (old_handler);
117 XSync (dpy, False);
118
119 if (error_handler_hit_p)
120 {
121 fprintf(stderr, "%s: XRRGetScreenInfo(dpy, %d) ==> X error:\n",
122 blurb(), i);
123 /* do it again without the error handler to print the error */
124 rrc = XRRGetScreenInfo (dpy, RootWindow (dpy, i));
125 }
126 else if (rrc)
127 {
128 SizeID current_size = -1;
129 Rotation current_rotation = ~0;
130
131 fprintf (stderr, "\n%s: Screen %d\n", blurb(), i);
132
133 current_size =
134 XRRConfigCurrentConfiguration (rrc, ¤t_rotation);
135
136 /* Times */
137 # if 0 /* #### This is wrong -- I don't understand what these two
138 timestamp numbers represent, or how they correlate
139 to the wall clock or to each other. */
140 {
141 Time server_time, config_time;
142 server_time = XRRConfigTimes (rrc, &config_time);
143 if (config_time == 0 || server_time == 0)
144 fprintf (stderr, "%s: config has never been changed\n",
145 blurb());
146 else
147 fprintf (stderr, "%s: config changed %lu seconds ago\n",
148 blurb(), (unsigned long) (server_time - config_time));
149 }
150 # endif
151
152 /* Rotations */
153 {
154 Rotation available, current;
155 available = XRRConfigRotations (rrc, ¤t);
156
157 fprintf (stderr, "%s: Available Rotations:\t", blurb());
158 if (available & RR_Rotate_0) fprintf (stderr, " 0");
159 if (available & RR_Rotate_90) fprintf (stderr, " 90");
160 if (available & RR_Rotate_180) fprintf (stderr, " 180");
161 if (available & RR_Rotate_270) fprintf (stderr, " 270");
162 if (! (available & (RR_Rotate_0 | RR_Rotate_90 |
163 RR_Rotate_180 | RR_Rotate_270)))
164 fprintf (stderr, " none");
165 fprintf (stderr, "\n");
166
167 if (current_rotation != current)
168 fprintf (stderr,
169 "%s: WARNING: rotation inconsistency: 0x%X vs 0x%X\n",
170 blurb(), current_rotation, current);
171
172 fprintf (stderr, "%s: Current Rotation:\t", blurb());
173 if (current & RR_Rotate_0) fprintf (stderr, " 0");
174 if (current & RR_Rotate_90) fprintf (stderr, " 90");
175 if (current & RR_Rotate_180) fprintf (stderr, " 180");
176 if (current & RR_Rotate_270) fprintf (stderr, " 270");
177 if (! (current & (RR_Rotate_0 | RR_Rotate_90 |
178 RR_Rotate_180 | RR_Rotate_270)))
179 fprintf (stderr, " none");
180 fprintf (stderr, "\n");
181
182 fprintf (stderr, "%s: Available Reflections:\t", blurb());
183 if (available & RR_Reflect_X) fprintf (stderr, " X");
184 if (available & RR_Reflect_Y) fprintf (stderr, " Y");
185 if (! (available & (RR_Reflect_X | RR_Reflect_Y)))
186 fprintf (stderr, " none");
187 fprintf (stderr, "\n");
188
189 fprintf (stderr, "%s: Current Reflections:\t", blurb());
190 if (current & RR_Reflect_X) fprintf (stderr, " X");
191 if (current & RR_Reflect_Y) fprintf (stderr, " Y");
192 if (! (current & (RR_Reflect_X | RR_Reflect_Y)))
193 fprintf (stderr, " none");
194 fprintf (stderr, "\n");
195 }
196
197 /* Sizes */
198 {
199 int nsizes, j;
200 XRRScreenSize *rrsizes;
201
202 rrsizes = XRRConfigSizes (rrc, &nsizes);
203 if (nsizes <= 0)
204 fprintf (stderr, "%s: sizes:\t none\n", blurb());
205 else
206 for (j = 0; j < nsizes; j++)
207 {
208 short *rates;
209 int nrates, k;
210 fprintf (stderr,
211 "%s: %c size %d: %d x %d\t rates:",
212 blurb(),
213 (j == current_size ? '+' : ' '),
214 j,
215 rrsizes[j].width, rrsizes[j].height);
216
217 rates = XRRConfigRates (rrc, j, &nrates);
218 if (nrates == 0)
219 fprintf (stderr, " none?");
220 else
221 for (k = 0; k < nrates; k++)
222 fprintf (stderr, " %d", rates[k]);
223 fprintf (stderr, "\n");
224 /* don't free 'rates' */
225 }
226 /* don't free 'rrsizes' */
227 }
228
229 XRRFreeScreenConfigInfo (rrc);
230 }
231 else if (major >= 0)
232 {
233 fprintf(stderr, "%s: XRRGetScreenInfo(dpy, %d) ==> NULL\n",
234 blurb(), i);
235 }
236
237
238 # ifdef HAVE_RANDR_12
239 if (major > 1 || (major == 1 && minor >= 2))
240 {
241 int j;
242 XRRScreenResources *res =
243 XRRGetScreenResources (dpy, RootWindow (dpy, i));
244 fprintf (stderr, "\n");
245 for (j = 0; j < res->noutput; j++)
246 {
247 int k;
248 XRROutputInfo *rroi =
249 XRRGetOutputInfo (dpy, res, res->outputs[j]);
250 fprintf (stderr, "%s: Output %d: %s: %s (%d)\n", blurb(), j,
251 rroi->name,
252 (rroi->connection == RR_Disconnected ? "disconnected" :
253 rroi->connection == RR_UnknownConnection ? "unknown" :
254 "connected"),
255 (int) rroi->crtc);
256 for (k = 0; k < rroi->ncrtc; k++)
257 {
258 XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res,
259 rroi->crtcs[k]);
260 fprintf(stderr, "%s: %c CRTC %d (%d): %dx%d+%d+%d\n",
261 blurb(),
262 (rroi->crtc == rroi->crtcs[k] ? '+' : ' '),
263 k, (int) rroi->crtcs[k],
264 crtci->width, crtci->height, crtci->x, crtci->y);
265 XRRFreeCrtcInfo (crtci);
266 }
267 XRRFreeOutputInfo (rroi);
268 fprintf (stderr, "\n");
269 }
270 XRRFreeScreenResources (res);
271 }
272 # endif /* HAVE_RANDR_12 */
273 }
274
275 if (major > 0)
276 {
277 Window w[20];
278 XWindowAttributes xgwa[20];
279
280 for (i = 0; i < nscreens; i++)
281 {
282 XRRSelectInput (dpy, RootWindow (dpy, i), RRScreenChangeNotifyMask);
283 w[i] = RootWindow (dpy, i);
284 XGetWindowAttributes (dpy, w[i], &xgwa[i]);
285 }
286
287 XSync (dpy, False);
288
289 fprintf (stderr, "\n%s: awaiting events...\n\n"
290 "\t(If you resize the screen or add/remove monitors, this should\n"
291 "\tnotice that and print stuff. Otherwise, hit ^C.)\n\n",
292 progname);
293 while (1)
294 {
295 XEvent event;
296 XNextEvent (dpy, &event);
297
298 if (event.type == event_number + RRScreenChangeNotify)
299 {
300 XRRScreenChangeNotifyEvent *xrr_event =
301 (XRRScreenChangeNotifyEvent *) &event;
302 int screen = XRRRootToScreen (dpy, xrr_event->window);
303
304 fprintf (stderr, "%s: screen %d: RRScreenChangeNotify event\n",
305 progname, screen);
306
307 fprintf (stderr, "%s: screen %d: old size: \t%d x %d\n",
308 progname, screen,
309 DisplayWidth (dpy, screen),
310 DisplayHeight (dpy, screen));
311 fprintf (stderr, "%s: screen %d: old root 0x%lx:\t%d x %d\n",
312 progname, screen, (unsigned long) w[screen],
313 xgwa[screen].width, xgwa[screen].height);
314
315 XRRUpdateConfiguration (&event);
316 XSync (dpy, False);
317
318 fprintf (stderr, "%s: screen %d: new size: \t%d x %d\n",
319 progname, screen,
320 DisplayWidth (dpy, screen),
321 DisplayHeight (dpy, screen));
322
323 w[screen] = RootWindow (dpy, screen);
324 XGetWindowAttributes (dpy, w[screen], &xgwa[screen]);
325 fprintf (stderr, "%s: screen %d: new root 0x%lx:\t%d x %d\n",
326 progname, screen, (unsigned long) w[screen],
327 xgwa[screen].width, xgwa[screen].height);
328 fprintf (stderr, "\n");
329 }
330 else
331 {
332 fprintf (stderr, "%s: event %d\n", progname, event.type);
333 }
334 }
335 }
336
337 XSync (dpy, False);
338 exit (0);
339 }
340