From http://www.jwz.org/xscreensaver/xscreensaver-5.16.tar.gz
[xscreensaver] / driver / test-randr.c
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 *
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
56 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
57 {
58   error_handler_hit_p = True;
59   return 0;
60 }
61
62
63 int
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, &current_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, &current);
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 }