X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fxscreensaver.c;h=628bcf1d442b4090899e397bed66979fbddf7de6;hb=a94197e76a5dea5cb60542840809d6c20d0abbf3;hp=641ccddace6851da837c3e13e478a7aaaaf9a165;hpb=a445bdd3e3ba4abbee441844b6665b4c3c13d48c;p=xscreensaver diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index 641ccdda..628bcf1d 100644 --- a/driver/xscreensaver.c +++ b/driver/xscreensaver.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1991-2001 Jamie Zawinski +/* xscreensaver, Copyright (c) 1991-2002 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 @@ -132,6 +132,8 @@ #include #include #include +#include +#include #include /* for gethostbyname() */ #ifdef HAVE_XMU # ifndef VMS @@ -169,6 +171,23 @@ Atom XA_DEMO, XA_PREFS, XA_EXIT, XA_LOCK, XA_BLANK; static XrmOptionDescRec options [] = { + + { "-verbose", ".verbose", XrmoptionNoArg, "on" }, + { "-silent", ".verbose", XrmoptionNoArg, "off" }, + + /* xscreensaver-demo uses this one */ + { "-nosplash", ".splash", XrmoptionNoArg, "off" }, + { "-no-splash", ".splash", XrmoptionNoArg, "off" }, + + /* 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" }, @@ -180,11 +199,7 @@ static XrmOptionDescRec options [] = { { "-visual", ".visualID", XrmoptionSepArg, 0 }, { "-install", ".installColormap", XrmoptionNoArg, "on" }, { "-no-install", ".installColormap", XrmoptionNoArg, "off" }, - { "-verbose", ".verbose", XrmoptionNoArg, "on" }, - { "-silent", ".verbose", XrmoptionNoArg, "off" }, { "-timestamp", ".timestamp", XrmoptionNoArg, "on" }, - { "-capture-stderr", ".captureStderr", XrmoptionNoArg, "on" }, - { "-no-capture-stderr", ".captureStderr", XrmoptionNoArg, "off" }, { "-xidle-extension", ".xidleExtension", XrmoptionNoArg, "on" }, { "-no-xidle-extension", ".xidleExtension", XrmoptionNoArg, "off" }, { "-mit-extension", ".mitSaverExtension",XrmoptionNoArg, "on" }, @@ -193,15 +208,9 @@ static XrmOptionDescRec options [] = { { "-no-sgi-extension", ".sgiSaverExtension",XrmoptionNoArg, "off" }, { "-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "on" }, { "-no-proc-interrupts", ".procInterrupts", XrmoptionNoArg, "off" }, - { "-splash", ".splash", XrmoptionNoArg, "on" }, - { "-no-splash", ".splash", XrmoptionNoArg, "off" }, - { "-nosplash", ".splash", XrmoptionNoArg, "off" }, { "-idelay", ".initialDelay", XrmoptionSepArg, 0 }, { "-nice", ".nice", XrmoptionSepArg, 0 }, - - /* Actually these are built in to Xt, but just to be sure... */ - { "-synchronous", ".synchronous", XrmoptionNoArg, "on" }, - { "-xrm", NULL, XrmoptionResArg, NULL } +#endif /* 0 */ }; static char *defaults[] = { @@ -219,34 +228,21 @@ do_help (saver_info *si) fflush (stdout); fflush (stderr); fprintf (stdout, "\ -xscreensaver %s, copyright (c) 1991-2001 by Jamie Zawinski \n\ -The standard Xt command-line options are accepted; other options include:\n\ -\n\ - -timeout When the screensaver should activate.\n\ - -cycle How long to let each hack run before switching.\n\ - -lock-mode Require a password before deactivating.\n\ - -lock-timeout Grace period before locking; default 0.\n\ - -visual Which X visual to run on.\n\ - -install Install a private colormap.\n\ - -verbose Be loud.\n\ - -no-splash Don't display a splash-screen at startup.\n\ - -help This message.\n\ -\n\ -See the manual for other options and X resources.\n\ +xscreensaver %s, copyright (c) 1991-2002 by Jamie Zawinski \n\ \n\ -The `xscreensaver' program should be left running in the background.\n\ -Use the `xscreensaver-demo' and `xscreensaver-command' programs to\n\ -manipulate a running xscreensaver.\n\ + All xscreensaver configuration is via the `~/.xscreensaver' file.\n\ + Rather than editing that file by hand, just run `xscreensaver-demo':\n\ + that program lets you configure the screen saver graphically,\n\ + including timeouts, locking, and display modes.\n\ \n\ -The `*programs' resource controls which graphics demos will be launched by\n\ -the screensaver. See `man xscreensaver' or the web page for more details.\n\ -\n\ -Just getting started? Try this:\n\ + Just getting started? Try this:\n\ \n\ xscreensaver &\n\ xscreensaver-demo\n\ \n\ -For updates, check http://www.jwz.org/xscreensaver/\n\ + For updates, online manual, and FAQ, please see the web page:\n\ +\n\ + http://www.jwz.org/xscreensaver/\n\ \n", si->version); fflush (stdout); @@ -292,16 +288,27 @@ int saver_ehandler (Display *dpy, XErrorEvent *error) { saver_info *si = global_si_kludge; /* I hate C so much... */ + int i; if (!real_stderr) real_stderr = stderr; fprintf (real_stderr, "\n" "#######################################" "#######################################\n\n" - "%s: X Error! PLEASE REPORT THIS BUG.\n\n" - "#######################################" - "#######################################\n\n", + "%s: X Error! PLEASE REPORT THIS BUG.\n", blurb()); + + for (i = 0; i < si->nscreens; i++) + fprintf (real_stderr, "%s: screen %d: 0x%x, 0x%x, 0x%x\n", + blurb(), i, + RootWindowOfScreen (si->screens[i].screen), + si->screens[i].real_vroot, + si->screens[i].screensaver_window); + + fprintf (real_stderr, "\n" + "#######################################" + "#######################################\n\n"); + if (XmuPrintDefaultErrorMessage (dpy, error, real_stderr)) { fprintf (real_stderr, "\n"); @@ -466,6 +473,16 @@ lock_initialization (saver_info *si, int *argc, char **argv) si->locking_disabled_p = True; si->nolock_reason = "error getting password"; } + + /* If locking is currently enabled, but the environment indicates that + we have been launched as GDM's "Background" program, then disable + locking just in case. + */ + if (!si->locking_disabled_p && getenv ("RUNNING_UNDER_GDM")) + { + si->locking_disabled_p = True; + si->nolock_reason = "running under GDM"; + } #endif /* NO_LOCKING */ hack_uid (si); @@ -518,6 +535,8 @@ connect_to_server (saver_info *si, int *argc, char **argv) XA_SCREENSAVER_RESPONSE = XInternAtom (si->dpy, "_SCREENSAVER_RESPONSE", False); XA_XSETROOT_ID = XInternAtom (si->dpy, "_XSETROOT_ID", False); + XA_ESETROOT_PMAP_ID = XInternAtom (si->dpy, "ESETROOT_PMAP_ID", False); + XA_XROOTPMAP_ID = XInternAtom (si->dpy, "_XROOTPMAP_ID", False); XA_ACTIVATE = XInternAtom (si->dpy, "ACTIVATE", False); XA_DEACTIVATE = XInternAtom (si->dpy, "DEACTIVATE", False); XA_RESTART = XInternAtom (si->dpy, "RESTART", False); @@ -624,7 +643,7 @@ print_banner (saver_info *si) if (p->verbose_p) fprintf (stderr, - "%s %s, copyright (c) 1991-2001 " + "%s %s, copyright (c) 1991-2002 " "by Jamie Zawinski .\n", progname, si->version); @@ -699,6 +718,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell) saver_screen_info *ssi = &si->screens[i]; ssi->global = si; ssi->screen = ScreenOfDisplay (si->dpy, i); + ssi->number = i; /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */ ssi->default_visual = @@ -740,6 +760,10 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell) } si->fading_possible_p = found_any_writable_cells; + +#ifdef HAVE_XF86VMODE_GAMMA + si->fading_possible_p = True; /* if we can gamma fade, go for it */ +#endif } @@ -900,7 +924,9 @@ maybe_reload_init_file (saver_info *si) /* If the DPMS settings in the init file have changed, change the settings on the server to match. */ - sync_server_dpms_settings (si->dpy, p->dpms_enabled_p, + sync_server_dpms_settings (si->dpy, + (p->dpms_enabled_p && + p->mode != DONT_BLANK), p->dpms_standby / 1000, p->dpms_suspend / 1000, p->dpms_off / 1000, @@ -935,13 +961,25 @@ main_loop (saver_info *si) fprintf (stderr, "%s: demoing %d at %s.\n", blurb(), si->selection_mode, timestring()); else - if (p->verbose_p) - fprintf (stderr, "%s: blanking screen at %s.\n", blurb(), - timestring()); + fprintf (stderr, "%s: blanking screen at %s.\n", blurb(), + timestring()); } maybe_reload_init_file (si); + if (p->mode == DONT_BLANK) + { + if (p->verbose_p) + fprintf (stderr, "%s: idle with blanking disabled at %s.\n", + blurb(), timestring()); + + /* Go around the loop and wait for the next bout of idleness, + or for the init file to change, or for a remote command to + come in, or something. + */ + continue; + } + if (! blank_screen (si)) { /* We were unable to grab either the keyboard or mouse. @@ -980,6 +1018,8 @@ main_loop (saver_info *si) #ifndef NO_LOCKING + /* Maybe start locking the screen. + */ { Time lock_timeout = p->lock_timeout; @@ -1023,6 +1063,8 @@ main_loop (saver_info *si) maybe_reload_init_file (si); #ifndef NO_LOCKING + /* Maybe unlock the screen. + */ if (si->locked_p) { saver_screen_info *ssi = si->default_screen; @@ -1093,6 +1135,53 @@ main_loop (saver_info *si) si->lock_id = 0; } + /* It's possible that a race condition could have led to the saver + window being unexpectedly still mapped. This can happen like so: + + - screen is blanked + - hack is launched + - that hack tries to grab a screen image( it does this by + first unmapping the saver window, then remapping it.) + - hack unmaps window + - hack waits + - user becomes active + - hack re-maps window (*) + - driver kills subprocess + - driver unmaps window (**) + + The race is that (*) might have been sent to the server before + the client process was killed, but, due to scheduling randomness, + might not have been received by the server until after (**). + In other words, (*) and (**) might happen out of order, meaning + the driver will unmap the window, and then after that, the + recently-dead client will re-map it. This leaves the user + locked out (it looks like a desktop, but it's not!) + + To avoid this: after un-blanking the screen, sleep for a second, + and then really make sure the window is unmapped. + */ + { + int i; + XSync (si->dpy, False); + sleep (1); + for (i = 0; i < si->nscreens; i++) + { + saver_screen_info *ssi = &si->screens[i]; + Window w = ssi->screensaver_window; + XWindowAttributes xgwa; + XGetWindowAttributes (si->dpy, w, &xgwa); + if (xgwa.map_state != IsUnmapped) + { + if (p->verbose_p) + fprintf (stderr, + "%s: %d: client race! emergency unmap 0x%lx.\n", + blurb(), i, (unsigned long) w); + XUnmapWindow (si->dpy, w); + } + } + XSync (si->dpy, False); + } + if (p->verbose_p) fprintf (stderr, "%s: awaiting idleness.\n", blurb()); } @@ -1125,6 +1214,7 @@ main (int argc, char **argv) print_banner (si); load_init_file (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 */ /* We can only issue this warnings now. */ @@ -1141,7 +1231,6 @@ main (int argc, char **argv) lock_initialization (si, &argc, argv); if (p->xsync_p) XSynchronize (si->dpy, True); - blurb_timestamp_p = p->timestamp_p; /* kludge */ if (p->verbose_p) analyze_display (si); initialize_server_extensions (si); @@ -1153,13 +1242,16 @@ main (int argc, char **argv) init_sigchld (); disable_builtin_screensaver (si, True); - sync_server_dpms_settings (si->dpy, p->dpms_enabled_p, + sync_server_dpms_settings (si->dpy, + (p->dpms_enabled_p && + p->mode != DONT_BLANK), p->dpms_standby / 1000, p->dpms_suspend / 1000, p->dpms_off / 1000, False); initialize_stderr (si); + handle_signals (si); make_splash_dialog (si); @@ -1172,9 +1264,12 @@ main (int argc, char **argv) */ +static Bool error_handler_hit_p = False; + static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error) { + error_handler_hit_p = True; return 0; } @@ -1190,11 +1285,13 @@ XGetAtomName_safe (Display *dpy, Atom atom) if (!atom) return 0; XSync (dpy, False); + error_handler_hit_p = False; old_handler = XSetErrorHandler (ignore_all_errors_ehandler); result = XGetAtomName (dpy, atom); XSync (dpy, False); XSetErrorHandler (old_handler); XSync (dpy, False); + if (error_handler_hit_p) result = 0; if (result) return result; @@ -1215,6 +1312,8 @@ clientmessage_response (saver_info *si, Window w, Bool error, char *proto; int L; saver_preferences *p = &si->prefs; + XErrorHandler old_handler; + if (error || p->verbose_p) fprintf (stderr, "%s: %s\n", blurb(), stderr_msg); @@ -1224,12 +1323,80 @@ clientmessage_response (saver_info *si, Window w, Bool error, strcpy (proto+1, protocol_msg); L++; + /* Ignore all X errors while sending a response to a ClientMessage. + Pretty much the only way we could get an error here is if the + window we're trying to send the reply on has been deleted, in + which case, the sender of the ClientMessage won't see our response + anyway. + */ + XSync (si->dpy, False); + error_handler_hit_p = False; + old_handler = XSetErrorHandler (ignore_all_errors_ehandler); + XChangeProperty (si->dpy, w, XA_SCREENSAVER_RESPONSE, XA_STRING, 8, PropModeReplace, (unsigned char *) proto, L); + + XSync (si->dpy, False); + XSetErrorHandler (old_handler); XSync (si->dpy, False); + free (proto); } + +static void +bogus_clientmessage_warning (saver_info *si, XEvent *event) +{ + char *str = XGetAtomName_safe (si->dpy, event->xclient.message_type); + Window w = event->xclient.window; + char wdesc[255]; + int screen = 0; + + *wdesc = 0; + for (screen = 0; screen < si->nscreens; screen++) + if (w == si->screens[screen].screensaver_window) + { + strcpy (wdesc, "xscreensaver"); + break; + } + else if (w == RootWindow (si->dpy, screen)) + { + strcpy (wdesc, "root"); + break; + } + + if (!*wdesc) + { + XErrorHandler old_handler; + XClassHint hint; + XWindowAttributes xgwa; + memset (&hint, 0, sizeof(hint)); + memset (&xgwa, 0, sizeof(xgwa)); + + XSync (si->dpy, False); + old_handler = XSetErrorHandler (ignore_all_errors_ehandler); + XGetClassHint (si->dpy, w, &hint); + XGetWindowAttributes (si->dpy, w, &xgwa); + XSync (si->dpy, False); + XSetErrorHandler (old_handler); + XSync (si->dpy, False); + + screen = (xgwa.screen ? screen_number (xgwa.screen) : -1); + + sprintf (wdesc, "%.20s / %.20s", + (hint.res_name ? hint.res_name : "(null)"), + (hint.res_class ? hint.res_class : "(null)")); + if (hint.res_name) XFree (hint.res_name); + if (hint.res_class) XFree (hint.res_class); + } + + fprintf (stderr, "%s: %d: unrecognised ClientMessage \"%s\" received\n", + blurb(), screen, (str ? str : "(null)")); + fprintf (stderr, "%s: %d: for window 0x%lx (%s)\n", + blurb(), screen, (unsigned long) w, wdesc); + if (str) XFree (str); +} + Bool handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) { @@ -1240,19 +1407,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) /* Preferences might affect our handling of client messages. */ maybe_reload_init_file (si); - if (event->xclient.message_type != XA_SCREENSAVER) - { - char *str; - str = XGetAtomName_safe (si->dpy, event->xclient.message_type); - fprintf (stderr, "%s: unrecognised ClientMessage type %s received\n", - blurb(), (str ? str : "(null)")); - if (str) XFree (str); - return False; - } - if (event->xclient.format != 32) + if (event->xclient.message_type != XA_SCREENSAVER || + event->xclient.format != 32) { - fprintf (stderr, "%s: ClientMessage of format %d received, not 32\n", - blurb(), event->xclient.format); + bogus_clientmessage_warning (si, event); return False; } @@ -1306,9 +1464,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) return True; } } - clientmessage_response(si, window, True, - "ClientMessage DEACTIVATE received while inactive.", - "not active."); + clientmessage_response(si, window, False, + "ClientMessage DEACTIVATE received while inactive: resetting idle timer.", + "not active: idle timer reset."); + reset_timers (si); } else if (type == XA_CYCLE) { @@ -1424,17 +1583,8 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) XSync (si->dpy, False); } - fflush (stdout); - fflush (stderr); - if (real_stdout) fflush (real_stdout); - if (real_stderr) fflush (real_stderr); - /* make sure error message shows up before exit. */ - if (real_stderr && stderr != real_stderr) - dup2 (fileno(real_stderr), fileno(stderr)); - - restart_process (si); - exit (1); /* shouldn't get here; but if restarting didn't work, - make this command be the same as EXIT. */ + restart_process (si); /* does not return */ + abort(); } else clientmessage_response (si, window, True, @@ -1624,13 +1774,13 @@ analyze_display (saver_info *si) const char *name; const char *desc; Bool useful_p; } exts[] = { - { "SCREEN_SAVER", "SGI Screen-Saver", + { "SCREEN_SAVER", /* underscore */ "SGI Screen-Saver", # ifdef HAVE_SGI_SAVER_EXTENSION True # else False # endif - }, { "SCREEN-SAVER", "SGI Screen-Saver", + }, { "SCREEN-SAVER", /* dash */ "SGI Screen-Saver", # ifdef HAVE_SGI_SAVER_EXTENSION True # else @@ -1695,20 +1845,31 @@ analyze_display (saver_info *si) }, }; - fprintf (stderr, "%s: running on display \"%s\"\n", blurb(), - DisplayString(si->dpy)); - fprintf (stderr, "%s: vendor is %s, %d\n", blurb(), + fprintf (stderr, "%s: running on display \"%s\" (%d screen%s).\n", + blurb(), + DisplayString(si->dpy), + si->nscreens, (si->nscreens == 1 ? "" : "s")); + fprintf (stderr, "%s: vendor is %s, %d.\n", blurb(), ServerVendor(si->dpy), VendorRelease(si->dpy)); fprintf (stderr, "%s: useful extensions:\n", blurb()); for (i = 0; i < countof(exts); i++) { int op = 0, event = 0, error = 0; - if (XQueryExtension (si->dpy, exts[i].name, &op, &event, &error)) - fprintf (stderr, "%s: %s%s\n", blurb(), - exts[i].desc, - (exts[i].useful_p ? "" : - " \t<== unsupported at compile-time!")); + char buf [255]; + int j; + if (!XQueryExtension (si->dpy, exts[i].name, &op, &event, &error)) + continue; + sprintf (buf, "%s: ", blurb()); + 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!"); + } + fprintf (stderr, "%s\n", buf); } for (i = 0; i < si->nscreens; i++) @@ -1733,15 +1894,16 @@ analyze_display (saver_info *si) for (j = 0; j < 32; j++) if (colormapped_depths & (1 << j)) fprintf (stderr, " %d", j); - fprintf (stderr, "\n"); + fprintf (stderr, ".\n"); } if (non_mapped_depths) { - fprintf (stderr, "%s: screen %d non-mapped depths:", blurb(), i); + fprintf (stderr, "%s: screen %d non-colormapped depths:", + blurb(), i); for (j = 0; j < 32; j++) if (non_mapped_depths & (1 << j)) fprintf (stderr, " %d", j); - fprintf (stderr, "\n"); + fprintf (stderr, ".\n"); } } }