/* test-randr.c --- playing with the Resize And Rotate extension.
* xscreensaver, Copyright (c) 2004-2008 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. No representations are made about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Intrinsic.h>
#include <X11/Xproto.h>
#include <X11/extensions/Xrandr.h>
char *progname = 0;
char *progclass = "XScreenSaver";
static const char *
blurb (void)
{
static char buf[255];
time_t now = time ((time_t *) 0);
char *ct = (char *) ctime (&now);
int n = strlen(progname);
if (n > 100) n = 99;
strncpy(buf, progname, n);
buf[n++] = ':';
buf[n++] = ' ';
strncpy(buf+n, ct+11, 8);
strcpy(buf+n+9, ": ");
return buf;
}
static Bool error_handler_hit_p = False;
static int
ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
{
error_handler_hit_p = True;
return 0;
}
int
main (int argc, char **argv)
{
int event_number = -1, error_number = -1;
int major = -1, minor = -1;
int nscreens = 0;
int i;
XtAppContext app;
Widget toplevel_shell = XtAppInitialize (&app, progclass, 0, 0,
&argc, argv, 0, 0, 0);
Display *dpy = XtDisplay (toplevel_shell);
XtGetApplicationNameAndClass (dpy, &progname, &progclass);
nscreens = ScreenCount(dpy);
if (!XRRQueryExtension(dpy, &event_number, &error_number))
{
fprintf(stderr, "%s: XRRQueryExtension(dpy, ...) ==> False\n",
blurb());
fprintf(stderr, "%s: server does not support the RANDR extension.\n",
blurb());
major = -1;
}
else
{
fprintf(stderr, "%s: XRRQueryExtension(dpy, ...) ==> %d, %d\n",
blurb(), event_number, error_number);
if (!XRRQueryVersion(dpy, &major, &minor))
{
fprintf(stderr, "%s: XRRQueryVersion(dpy, ...) ==> False\n",
blurb());
fprintf(stderr, "%s: server didn't report RANDR version numbers?\n",
blurb());
}
else
fprintf(stderr, "%s: XRRQueryVersion(dpy, ...) ==> %d, %d\n", blurb(),
major, minor);
}
for (i = 0; i < nscreens; i++)
{
XRRScreenConfiguration *rrc;
XErrorHandler old_handler;
XSync (dpy, False);
error_handler_hit_p = False;
old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
rrc = (major >= 0 ? XRRGetScreenInfo (dpy, RootWindow (dpy, i)) : 0);
XSync (dpy, False);
XSetErrorHandler (old_handler);
XSync (dpy, False);
if (error_handler_hit_p)
{
fprintf(stderr, "%s: XRRGetScreenInfo(dpy, %d) ==> X error:\n",
blurb(), i);
/* do it again without the error handler to print the error */
rrc = XRRGetScreenInfo (dpy, RootWindow (dpy, i));
}
else if (rrc)
{
SizeID current_size = -1;
Rotation current_rotation = ~0;
fprintf (stderr, "\n%s: Screen %d\n", blurb(), i);
current_size =
XRRConfigCurrentConfiguration (rrc, ¤t_rotation);
/* Times */
# if 0 /* #### This is wrong -- I don't understand what these two
timestamp numbers represent, or how they correlate
to the wall clock or to each other. */
{
Time server_time, config_time;
server_time = XRRConfigTimes (rrc, &config_time);
if (config_time == 0 || server_time == 0)
fprintf (stderr, "%s: config has never been changed\n",
blurb());
else
fprintf (stderr, "%s: config changed %lu seconds ago\n",
blurb(), (unsigned long) (server_time - config_time));
}
# endif
/* Rotations */
{
Rotation available, current;
available = XRRConfigRotations (rrc, ¤t);
fprintf (stderr, "%s: Available Rotations:\t", blurb());
if (available & RR_Rotate_0) fprintf (stderr, " 0");
if (available & RR_Rotate_90) fprintf (stderr, " 90");
if (available & RR_Rotate_180) fprintf (stderr, " 180");
if (available & RR_Rotate_270) fprintf (stderr, " 270");
if (! (available & (RR_Rotate_0 | RR_Rotate_90 |
RR_Rotate_180 | RR_Rotate_270)))
fprintf (stderr, " none");
fprintf (stderr, "\n");
if (current_rotation != current)
fprintf (stderr,
"%s: WARNING: rotation inconsistency: 0x%X vs 0x%X\n",
blurb(), current_rotation, current);
fprintf (stderr, "%s: Current Rotation:\t", blurb());
if (current & RR_Rotate_0) fprintf (stderr, " 0");
if (current & RR_Rotate_90) fprintf (stderr, " 90");
if (current & RR_Rotate_180) fprintf (stderr, " 180");
if (current & RR_Rotate_270) fprintf (stderr, " 270");
if (! (current & (RR_Rotate_0 | RR_Rotate_90 |
RR_Rotate_180 | RR_Rotate_270)))
fprintf (stderr, " none");
fprintf (stderr, "\n");
fprintf (stderr, "%s: Available Reflections:\t", blurb());
if (available & RR_Reflect_X) fprintf (stderr, " X");
if (available & RR_Reflect_Y) fprintf (stderr, " Y");
if (! (available & (RR_Reflect_X | RR_Reflect_Y)))
fprintf (stderr, " none");
fprintf (stderr, "\n");
fprintf (stderr, "%s: Current Reflections:\t", blurb());
if (current & RR_Reflect_X) fprintf (stderr, " X");
if (current & RR_Reflect_Y) fprintf (stderr, " Y");
if (! (current & (RR_Reflect_X | RR_Reflect_Y)))
fprintf (stderr, " none");
fprintf (stderr, "\n");
}
/* Sizes */
{
int nsizes, j;
XRRScreenSize *rrsizes;
rrsizes = XRRConfigSizes (rrc, &nsizes);
if (nsizes <= 0)
fprintf (stderr, "%s: sizes:\t none\n", blurb());
else
for (j = 0; j < nsizes; j++)
{
short *rates;
int nrates, k;
fprintf (stderr,
"%s: %c size %d: %d x %d\t rates:",
blurb(),
(j == current_size ? '+' : ' '),
j,
rrsizes[j].width, rrsizes[j].height);
rates = XRRConfigRates (rrc, j, &nrates);
if (nrates == 0)
fprintf (stderr, " none?");
else
for (k = 0; k < nrates; k++)
fprintf (stderr, " %d", rates[k]);
fprintf (stderr, "\n");
/* don't free 'rates' */
}
/* don't free 'rrsizes' */
}
XRRFreeScreenConfigInfo (rrc);
}
else if (major >= 0)
{
fprintf(stderr, "%s: XRRGetScreenInfo(dpy, %d) ==> NULL\n",
blurb(), i);
}
# ifdef HAVE_RANDR_12
if (major > 1 || (major == 1 && minor >= 2))
{
int j;
XRRScreenResources *res =
XRRGetScreenResources (dpy, RootWindow (dpy, i));
fprintf (stderr, "\n");
for (j = 0; j < res->noutput; j++)
{
int k;
XRROutputInfo *rroi =
XRRGetOutputInfo (dpy, res, res->outputs[j]);
fprintf (stderr, "%s: Output %d: %s: %s (%d)\n", blurb(), j,
rroi->name,
(rroi->connection == RR_Disconnected ? "disconnected" :
rroi->connection == RR_UnknownConnection ? "unknown" :
"connected"),
(int) rroi->crtc);
for (k = 0; k < rroi->ncrtc; k++)
{
XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res,
rroi->crtcs[k]);
fprintf(stderr, "%s: %c CRTC %d (%d): %dx%d+%d+%d\n",
blurb(),
(rroi->crtc == rroi->crtcs[k] ? '+' : ' '),
k, (int) rroi->crtcs[k],
crtci->width, crtci->height, crtci->x, crtci->y);
XRRFreeCrtcInfo (crtci);
}
XRRFreeOutputInfo (rroi);
fprintf (stderr, "\n");
}
XRRFreeScreenResources (res);
}
# endif /* HAVE_RANDR_12 */
}
if (major > 0)
{
Window w[20];
XWindowAttributes xgwa[20];
for (i = 0; i < nscreens; i++)
{
XRRSelectInput (dpy, RootWindow (dpy, i), RRScreenChangeNotifyMask);
w[i] = RootWindow (dpy, i);
XGetWindowAttributes (dpy, w[i], &xgwa[i]);
}
XSync (dpy, False);
fprintf (stderr, "\n%s: awaiting events...\n\n"
"\t(If you resize the screen or add/remove monitors, this should\n"
"\tnotice that and print stuff. Otherwise, hit ^C.)\n\n",
progname);
while (1)
{
XEvent event;
XNextEvent (dpy, &event);
if (event.type == event_number + RRScreenChangeNotify)
{
XRRScreenChangeNotifyEvent *xrr_event =
(XRRScreenChangeNotifyEvent *) &event;
int screen = XRRRootToScreen (dpy, xrr_event->window);
fprintf (stderr, "%s: screen %d: RRScreenChangeNotify event\n",
progname, screen);
fprintf (stderr, "%s: screen %d: old size: \t%d x %d\n",
progname, screen,
DisplayWidth (dpy, screen),
DisplayHeight (dpy, screen));
fprintf (stderr, "%s: screen %d: old root 0x%lx:\t%d x %d\n",
progname, screen, (unsigned long) w[screen],
xgwa[screen].width, xgwa[screen].height);
XRRUpdateConfiguration (&event);
XSync (dpy, False);
fprintf (stderr, "%s: screen %d: new size: \t%d x %d\n",
progname, screen,
DisplayWidth (dpy, screen),
DisplayHeight (dpy, screen));
w[screen] = RootWindow (dpy, screen);
XGetWindowAttributes (dpy, w[screen], &xgwa[screen]);
fprintf (stderr, "%s: screen %d: new root 0x%lx:\t%d x %d\n",
progname, screen, (unsigned long) w[screen],
xgwa[screen].width, xgwa[screen].height);
fprintf (stderr, "\n");
}
else
{
fprintf (stderr, "%s: event %d\n", progname, event.type);
}
}
}
XSync (dpy, False);
exit (0);
}