X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=driver%2Fxscreensaver.c;h=92b28625c1a6337be6cdfbc178832116194e5861;hp=058dd86c091b9c52b84387046785b4778cc9122e;hb=6b1c86cf395f59389e4ece4ea8f4bea2c332745b;hpb=3f438031d610c7e15fd33876a879b97e290e05fb diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index 058dd86c..92b28625 100644 --- a/driver/xscreensaver.c +++ b/driver/xscreensaver.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1991-2005 Jamie Zawinski +/* xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -152,6 +152,8 @@ #include #include #include /* for gethostbyname() */ +#include +#include #ifdef HAVE_XMU # ifndef VMS # include @@ -176,6 +178,7 @@ #include "resources.h" #include "visual.h" #include "usleep.h" +#include "auth.h" saver_info *global_si_kludge = 0; /* I hate C so much... */ @@ -202,36 +205,6 @@ static XrmOptionDescRec options [] = { /* useful for debugging */ { "-no-capture-stderr", ".captureStderr", XrmoptionNoArg, "off" }, - - /* There's really no reason to have these command-line args; they just - lead to confusion when the .xscreensaver file has conflicting values. - */ -#if 0 - { "-splash", ".splash", XrmoptionNoArg, "on" }, - { "-capture-stderr", ".captureStderr", XrmoptionNoArg, "on" }, - { "-timeout", ".timeout", XrmoptionSepArg, 0 }, - { "-cycle", ".cycle", XrmoptionSepArg, 0 }, - { "-lock-mode", ".lock", XrmoptionNoArg, "on" }, - { "-no-lock-mode", ".lock", XrmoptionNoArg, "off" }, - { "-no-lock", ".lock", XrmoptionNoArg, "off" }, - { "-lock-timeout", ".lockTimeout", XrmoptionSepArg, 0 }, - { "-lock-vts", ".lockVTs", XrmoptionNoArg, "on" }, - { "-no-lock-vts", ".lockVTs", XrmoptionNoArg, "off" }, - { "-visual", ".visualID", XrmoptionSepArg, 0 }, - { "-install", ".installColormap", XrmoptionNoArg, "on" }, - { "-no-install", ".installColormap", XrmoptionNoArg, "off" }, - { "-timestamp", ".timestamp", XrmoptionNoArg, "on" }, - { "-xidle-extension", ".xidleExtension", XrmoptionNoArg, "on" }, - { "-no-xidle-extension", ".xidleExtension", XrmoptionNoArg, "off" }, - { "-mit-extension", ".mitSaverExtension",XrmoptionNoArg, "on" }, - { "-no-mit-extension", ".mitSaverExtension",XrmoptionNoArg, "off" }, - { "-sgi-extension", ".sgiSaverExtension",XrmoptionNoArg, "on" }, - { "-no-sgi-extension", ".sgiSaverExtension",XrmoptionNoArg, "off" }, - { "-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "on" }, - { "-no-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "off" }, - { "-idelay", ".initialDelay", XrmoptionSepArg, 0 }, - { "-nice", ".nice", XrmoptionSepArg, 0 }, -#endif /* 0 */ }; #ifdef __GNUC__ @@ -255,7 +228,7 @@ do_help (saver_info *si) fflush (stdout); fflush (stderr); fprintf (stdout, "\ -xscreensaver %s, copyright (c) 1991-2005 by Jamie Zawinski \n\ +xscreensaver %s, copyright (c) 1991-2008 by Jamie Zawinski \n\ \n\ All xscreensaver configuration is via the `~/.xscreensaver' file.\n\ Rather than editing that file by hand, just run `xscreensaver-demo':\n\ @@ -712,14 +685,15 @@ print_banner (saver_info *si) whether to print the banner (and so that the banner gets printed before any resource-database-related error messages.) */ - p->verbose_p = (p->debug_p || get_boolean_resource ("verbose", "Boolean")); + p->verbose_p = (p->debug_p || + get_boolean_resource (si->dpy, "verbose", "Boolean")); /* Ditto, for the locking_disabled_p message. */ - p->lock_p = get_boolean_resource ("lock", "Boolean"); + p->lock_p = get_boolean_resource (si->dpy, "lock", "Boolean"); if (p->verbose_p) fprintf (stderr, - "%s %s, copyright (c) 1991-2005 " + "%s %s, copyright (c) 1991-2008 " "by Jamie Zawinski .\n", progname, si->version); @@ -781,6 +755,111 @@ print_lock_failure_banner (saver_info *si) } +#ifdef HAVE_XINERAMA + +static Bool +screens_overlap_p (XineramaScreenInfo *a, XineramaScreenInfo *b) +{ + /* Two rectangles overlap if the max of the tops is less than the + min of the bottoms and the max of the lefts is less than the min + of the rights. + */ +# undef MAX +# undef MIN +# define MAX(A,B) ((A)>(B)?(A):(B)) +# define MIN(A,B) ((A)<(B)?(A):(B)) + + int maxleft = MAX(a->x_org, b->x_org); + int maxtop = MAX(a->y_org, b->y_org); + int minright = MIN(a->x_org + a->width - 1, b->x_org + b->width); + int minbot = MIN(a->y_org + a->height - 1, b->y_org + b->height); + return (maxtop < minbot && maxleft < minright); +} + + +/* Go through the list of Xinerama screen descriptions, and mark the + ones that appear to be insane, so that we don't use them. + */ +static void +check_xinerama_sanity (int count, Bool verbose_p, XineramaScreenInfo *xsi) +{ + static Bool printed_p = False; + int i, j; + char err[1024]; + *err = 0; + +# define X1 xsi[i].x_org +# define X2 xsi[j].x_org +# define Y1 xsi[i].y_org +# define Y2 xsi[j].y_org +# define W1 xsi[i].width +# define W2 xsi[j].width +# define H1 xsi[i].height +# define H2 xsi[j].height + +# define WHINE() do { \ + if (verbose_p) { \ + if (! printed_p) { \ + fprintf (stderr, "%s: compensating for Xinerama braindamage:\n", \ + blurb()); \ + printed_p = True; \ + } \ + fprintf (stderr, "%s: %d: %s\n", blurb(), xsi[i].screen_number,err); \ + } \ + xsi[i].screen_number = -1; \ + } while(0) + + /* If a screen is enclosed by any other screen, that's insane. + */ + for (i = 0; i < count; i++) + for (j = 0; j < count; j++) + if (i != j && + xsi[i].screen_number >= 0 && + xsi[j].screen_number >= 0 && + X1 >= X2 && Y1 >= Y2 && (X1+W1) <= (X2+W2) && (X1+H1) <= (X2+H2)) + { + sprintf (err, "%dx%d+%d+%d enclosed by %dx%d+%d+%d", + W1, H1, X1, Y1, + W2, H2, X2, Y2); + WHINE(); + continue; + } + + /* After checking for enclosure, check for other lossage against earlier + screens. We do enclosure first so that we make sure to pick the + larger one. + */ + for (i = 0; i < count; i++) + for (j = 0; j < i; j++) + { + if (xsi[i].screen_number < 0) continue; /* already marked */ + + *err = 0; + if (X1 == X2 && Y1 == Y2 && W1 == W2 && H1 == H2) + sprintf (err, "%dx%d+%d+%d duplicated", W1, H1, X1, Y1); + + else if (screens_overlap_p (&xsi[i], &xsi[j])) + sprintf (err, "%dx%d+%d+%d overlaps %dx%d+%d+%d", + W1, H1, X1, Y1, + W2, H2, X2, Y2); + + if (*err) WHINE(); + } + +# undef X1 +# undef X2 +# undef Y1 +# undef Y2 +# undef W1 +# undef W2 +# undef H1 +# undef H2 +} + +#endif /* HAVE_XINERAMA */ + + + /* Examine all of the display's screens, and populate the `saver_screen_info' structures. Make sure this is called after hack_environment() sets $PATH. */ @@ -808,20 +887,27 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell) if (si->xinerama_p) { - XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &si->nscreens); + int nscreens = 0; + XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens); if (!xsi) si->xinerama_p = False; else { + int j = 0; si->screens = (saver_screen_info *) - calloc(sizeof(saver_screen_info), si->nscreens); - for (i = 0; i < si->nscreens; i++) + calloc(sizeof(saver_screen_info), nscreens); + check_xinerama_sanity (nscreens, si->prefs.verbose_p, xsi); + for (i = 0; i < nscreens; i++) { - si->screens[i].x = xsi[i].x_org; - si->screens[i].y = xsi[i].y_org; - si->screens[i].width = xsi[i].width; - si->screens[i].height = xsi[i].height; + if (xsi[i].screen_number < 0) /* deemed insane */ + continue; + si->screens[j].x = xsi[i].x_org; + si->screens[j].y = xsi[i].y_org; + si->screens[j].width = xsi[i].width; + si->screens[j].height = xsi[i].height; + j++; } + si->nscreens = j; XFree (xsi); } si->default_screen = &si->screens[0]; @@ -847,6 +933,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell) } +# ifdef QUAD_MODE /* In "quad mode", we use the Xinerama code to pretend that there are 4 screens for every physical screen, and run four times as many hacks... */ @@ -894,6 +981,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell) si->default_screen = &si->screens[DefaultScreen(si->dpy) * 4]; si->xinerama_p = True; } +# endif /* QUAD_MODE */ /* finish initializing the screens. */ @@ -1126,7 +1214,7 @@ maybe_reload_init_file (saver_info *si) fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n", blurb(), init_file_name()); - load_init_file (p); + load_init_file (si->dpy, p); /* If a server extension is in use, and p->timeout has changed, we need to inform the server of the new timeout. */ @@ -1410,6 +1498,7 @@ main (int argc, char **argv) saver_info the_si; saver_info *si = &the_si; saver_preferences *p = &si->prefs; + struct passwd *spasswd; int i; memset(si, 0, sizeof(*si)); @@ -1425,11 +1514,25 @@ main (int argc, char **argv) privileged_initialization (si, &argc, argv); hack_environment (si); + spasswd = getpwuid(getuid()); + if (!spasswd) + { + fprintf(stderr, "Could not figure out who the current user is!\n"); + return 1; + } + + si->user = strdup(spasswd->pw_name ? spasswd->pw_name : "(unknown)"); + +# ifndef NO_LOCKING + si->unlock_cb = gui_auth_conv; + si->auth_finished_cb = auth_finished_cb; +# endif /* !NO_LOCKING */ + shell = connect_to_server (si, &argc, argv); process_command_line (si, &argc, argv); print_banner (si); - load_init_file (p); /* must be before initialize_per_screen_info() */ + load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */ blurb_timestamp_p = p->timestamp_p; /* kludge */ initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */ @@ -1598,10 +1701,23 @@ clientmessage_response (saver_info *si, Window w, Bool error, static void bogus_clientmessage_warning (saver_info *si, XEvent *event) { +#if 0 /* Oh, fuck it. GNOME likes to spew random ClientMessages at us + all the time. This is presumably indicative of an error in + the sender of that ClientMessage: if we're getting it and + ignoring it, then it's not reaching the intended recipient. + But people complain to me about this all the time ("waaah! + xscreensaver is printing to it's stderr and that gets my + panties all in a bunch!") And I'm sick of hearing about it. + So we'll just ignore these messages and let GNOME go right + ahead and continue to stumble along in its malfunction. + */ + + saver_preferences *p = &si->prefs; char *str = XGetAtomName_safe (si->dpy, event->xclient.message_type); Window w = event->xclient.window; char wdesc[255]; int screen = 0; + Bool root_p = False; *wdesc = 0; for (screen = 0; screen < si->nscreens; screen++) @@ -1613,9 +1729,19 @@ bogus_clientmessage_warning (saver_info *si, XEvent *event) else if (w == RootWindow (si->dpy, screen)) { strcpy (wdesc, "root"); + root_p = True; break; } + /* If this ClientMessage was sent to the real root window instead of to the + xscreensaver window, then it might be intended for someone else who is + listening on the root window (e.g., the window manager). So only print + the warning if: we are in debug mode; or if the bogus message was + actually sent to one of the xscreensaver-created windows. + */ + if (root_p && !p->debug_p) + return; + if (!*wdesc) { XErrorHandler old_handler; @@ -1646,8 +1772,11 @@ bogus_clientmessage_warning (saver_info *si, XEvent *event) fprintf (stderr, "%s: %d: for window 0x%lx (%s)\n", blurb(), screen, (unsigned long) w, wdesc); if (str) XFree (str); + +#endif /* 0 */ } + Bool handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) { @@ -1861,7 +1990,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) else if (type == XA_DEMO) { long arg = event->xclient.data.l[1]; - Bool demo_one_hack_p = (arg == 300); + Bool demo_one_hack_p = (arg == 5000); if (demo_one_hack_p) { @@ -2151,11 +2280,7 @@ analyze_display (saver_info *si) j = strlen (buf); strcat (buf, exts[i].desc); if (!exts[i].useful_p) - { - int k = j + 18; - while (strlen (buf) < k) strcat (buf, " "); - strcat (buf, "<-- not supported at compile time!"); - } + strcat (buf, " (disabled at compile time)"); fprintf (stderr, "%s\n", buf); } @@ -2233,6 +2358,8 @@ display_is_on_console_p (saver_info *si) not_on_console = False; else if (gethostname (localname, sizeof (localname))) not_on_console = True; /* can't find hostname? */ + else if (!strncmp (dpyname, "/tmp/launch-", 12)) /* MacOS X launchd */ + not_on_console = False; else { /* We have to call gethostbyname() on the result of gethostname()