X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fxscreensaver.c;h=fc8b89a47e4cd542f838f0e1636503b19b5abc54;hb=72c1f4c1dc6ab07fe121a327ff1c30bf51ef74c1;hp=d0efd9b0359f7942e5c2bef28f37c4e81c8c0ba8;hpb=c31d10b6605cd8dc1a7b61fef4256f06198767e5;p=xscreensaver diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index d0efd9b0..fc8b89a4 100644 --- a/driver/xscreensaver.c +++ b/driver/xscreensaver.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski +/* xscreensaver, Copyright (c) 1991-1999 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 @@ -59,7 +59,7 @@ * This program accepts ClientMessages of type SCREENSAVER; these messages * may contain the atom ACTIVATE or DEACTIVATE, meaning to turn the * screensaver on or off now, regardless of the idleness of the user, - * and a few other things. The included "xscreensaver_command" program + * and a few other things. The included "xscreensaver-command" program * sends these messsages. * * If we don't have the XIdle, MIT-SCREEN-SAVER, or SGI SCREEN_SAVER @@ -70,8 +70,9 @@ * KeyPress on windows which don't select them, because that would * interfere with event propagation. This will break if any program * changes its event mask to contain KeyRelease or PointerMotion more than - * 30 seconds after creating the window, but that's probably pretty rare. - * + * 30 seconds after creating the window, but such programs do not seem to + * occur in nature (I've never seen it happen in all these years.) + * * The reason that we can't select KeyPresses on windows that don't have * them already is that, when dispatching a KeyPress event, X finds the * lowest (leafmost) window in the hierarchy on which *any* client selects @@ -110,13 +111,13 @@ * to keep your emacs window alive even when xscreensaver has grabbed. * - Go read the code related to `debug_p'. * - You probably can't set breakpoints in functions that are called on - * the other side of a call to fork() -- if your clients are dying - * with signal 5, Trace/BPT Trap, you're losing in this way. + * the other side of a call to fork() -- if your subprocesses are + * dying with signal 5, Trace/BPT Trap, you're losing in this way. * - If you aren't using a server extension, don't leave this stopped * under the debugger for very long, or the X input buffer will get * huge because of the keypress events it's selecting for. This can * make your X server wedge with "no more input buffers." - * + * * ======================================================================== */ #ifdef HAVE_CONFIG_H @@ -131,6 +132,7 @@ #include #include #include +#include /* for gethostbyname() */ #ifdef HAVE_XMU # ifndef VMS # include @@ -142,7 +144,7 @@ #endif /* !HAVE_XMU */ #ifdef HAVE_XIDLE_EXTENSION -#include +# include #endif /* HAVE_XIDLE_EXTENSION */ #include "xscreensaver.h" @@ -150,6 +152,7 @@ #include "yarandom.h" #include "resources.h" #include "visual.h" +#include "usleep.h" saver_info *global_si_kludge = 0; /* I hate C so much... */ @@ -160,8 +163,9 @@ XrmDatabase db = 0; static Atom XA_SCREENSAVER_RESPONSE; static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV; -static Atom XA_EXIT, XA_RESTART, XA_LOCK, XA_SELECT; -Atom XA_DEMO, XA_PREFS; +static Atom XA_RESTART, XA_SELECT; +static Atom XA_THROTTLE, XA_UNTHROTTLE; +Atom XA_DEMO, XA_PREFS, XA_EXIT, XA_LOCK, XA_BLANK; static XrmOptionDescRec options [] = { @@ -187,6 +191,8 @@ static XrmOptionDescRec options [] = { { "-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" }, { "-splash", ".splash", XrmoptionNoArg, "on" }, { "-no-splash", ".splash", XrmoptionNoArg, "off" }, { "-nosplash", ".splash", XrmoptionNoArg, "off" }, @@ -213,7 +219,7 @@ do_help (saver_info *si) fflush (stdout); fflush (stderr); fprintf (stdout, "\ -xscreensaver %s, copyright (c) 1991-1998 by Jamie Zawinski \n\ +xscreensaver %s, copyright (c) 1991-1999 by Jamie Zawinski \n\ The standard Xt command-line options are accepted; other options include:\n\ \n\ -timeout When the screensaver should activate.\n\ @@ -287,6 +293,8 @@ saver_ehandler (Display *dpy, XErrorEvent *error) { saver_info *si = global_si_kludge; /* I hate C so much... */ + if (!real_stderr) real_stderr = stderr; + fprintf (real_stderr, "\n" "#######################################" "#######################################\n\n" @@ -303,11 +311,27 @@ saver_ehandler (Display *dpy, XErrorEvent *error) } else { - fprintf(real_stderr, - "%s: to dump a core file, re-run with `-sync'.\n" - "%s: see http://www.jwz.org/xscreensaver/bugs.html\n" - "\t\tfor bug reporting information.\n\n", - blurb(), blurb()); + fprintf (real_stderr, + "#######################################" + "#######################################\n\n"); + fprintf (real_stderr, + " If at all possible, please re-run xscreensaver with the command\n" + " line arguments `-sync -verbose -no-capture', and reproduce this\n" + " bug. That will cause xscreensaver to dump a `core' file to the\n" + " current directory. Please include the stack trace from that core\n" + " file in your bug report. *DO NOT* mail the core file itself!\n" + " That won't work.\n" + "\n" + " http://www.jwz.org/xscreensaver/bugs.html explains how to create\n" + " the most useful bug reports, and how to examine core files.\n" + "\n" + " The more information you can provide, the better. But please\n" + " report this bug, regardless!\n" + "\n"); + fprintf (real_stderr, + "#######################################" + "#######################################\n\n"); + saver_exit (si, -1, 0); } } @@ -316,6 +340,51 @@ saver_ehandler (Display *dpy, XErrorEvent *error) return 0; } + +/* This error handler is used only while the X connection is being set up; + after we've got a connection, we don't use this handler again. The only + reason for having this is so that we can present a more idiot-proof error + message than "cannot open display." + */ +static void +startup_ehandler (String name, String type, String class, + String defalt, /* one can't even spel properly + in this joke of a language */ + String *av, Cardinal *ac) +{ + char fmt[512]; + String p[10]; + saver_info *si = global_si_kludge; /* I hate C so much... */ + XrmDatabase *db = XtAppGetErrorDatabase(si->app); + *fmt = 0; + XtAppGetErrorDatabaseText(si->app, name, type, class, defalt, + fmt, sizeof(fmt)-1, *db); + + fprintf (stderr, "%s: ", blurb()); + + memset (p, 0, sizeof(p)); + if (*ac > countof (p)) *ac = countof (p); + memcpy ((char *) p, (char *) av, (*ac) * sizeof(*av)); + fprintf (stderr, fmt, /* Did I mention that I hate C? */ + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]); + fprintf (stderr, "\n"); + + describe_uids (si, stderr); + fprintf (stderr, "\n" + "%s: Errors at startup are usually authorization problems.\n" + " Did you read the manual and the FAQ? Specifically,\n" + " the parts of the manual that talk about XAUTH, XDM,\n" + " and root logins?\n" + "\n" + " http://www.jwz.org/xscreensaver/man.html\n" + "\n", + blurb()); + + fflush (stderr); + fflush (stdout); + exit (1); +} + /* The zillions of initializations. */ @@ -355,21 +424,34 @@ set_version_string (saver_info *si, int *argc, char **argv) static void privileged_initialization (saver_info *si, int *argc, char **argv) { +#ifndef NO_LOCKING + /* before hack_uid() for proper permissions */ + lock_priv_init (*argc, argv, si->prefs.verbose_p); +#endif /* NO_LOCKING */ + + hack_uid (si); +} + + +/* Figure out what locking mechanisms are supported. + */ +static void +lock_initialization (saver_info *si, int *argc, char **argv) +{ #ifdef NO_LOCKING si->locking_disabled_p = True; si->nolock_reason = "not compiled with locking support"; #else /* !NO_LOCKING */ - si->locking_disabled_p = False; - if (! lock_init (*argc, argv)) /* before hack_uid() for proper permissions */ + + /* Finish initializing locking, now that we're out of privileged code. */ + if (! lock_init (*argc, argv, si->prefs.verbose_p)) { si->locking_disabled_p = True; si->nolock_reason = "error getting password"; } #endif /* NO_LOCKING */ -#ifndef NO_SETUID hack_uid (si); -#endif /* NO_SETUID */ } @@ -381,9 +463,12 @@ connect_to_server (saver_info *si, int *argc, char **argv) Widget toplevel_shell; XSetErrorHandler (saver_ehandler); + + XtAppSetErrorMsgHandler (si->app, startup_ehandler); toplevel_shell = XtAppInitialize (&si->app, progclass, options, XtNumber (options), argc, argv, defaults, 0, 0); + XtAppSetErrorMsgHandler (si->app, 0); si->dpy = XtDisplay (toplevel_shell); si->prefs.db = XtDatabase (si->dpy); @@ -398,7 +483,7 @@ connect_to_server (saver_info *si, int *argc, char **argv) XA_SCREENSAVER = XInternAtom (si->dpy, "SCREENSAVER", False); XA_SCREENSAVER_VERSION = XInternAtom (si->dpy, "_SCREENSAVER_VERSION",False); XA_SCREENSAVER_ID = XInternAtom (si->dpy, "_SCREENSAVER_ID", False); - XA_SCREENSAVER_TIME = XInternAtom (si->dpy, "_SCREENSAVER_TIME", False); + XA_SCREENSAVER_STATUS = XInternAtom (si->dpy, "_SCREENSAVER_STATUS", False); XA_SCREENSAVER_RESPONSE = XInternAtom (si->dpy, "_SCREENSAVER_RESPONSE", False); XA_XSETROOT_ID = XInternAtom (si->dpy, "_XSETROOT_ID", False); @@ -413,6 +498,9 @@ connect_to_server (saver_info *si, int *argc, char **argv) XA_DEMO = XInternAtom (si->dpy, "DEMO", False); XA_PREFS = XInternAtom (si->dpy, "PREFS", False); XA_LOCK = XInternAtom (si->dpy, "LOCK", False); + XA_BLANK = XInternAtom (si->dpy, "BLANK", False); + XA_THROTTLE = XInternAtom (si->dpy, "THROTTLE", False); + XA_UNTHROTTLE = XInternAtom (si->dpy, "UNTHROTTLE", False); return toplevel_shell; } @@ -505,7 +593,7 @@ print_banner (saver_info *si) if (p->verbose_p) fprintf (stderr, - "%s %s, copyright (c) 1991-1998 " + "%s %s, copyright (c) 1991-1999 " "by Jamie Zawinski .\n", progname, si->version); @@ -617,7 +705,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell) } } - si->prefs.fading_possible_p = found_any_writable_cells; + si->fading_possible_p = found_any_writable_cells; } @@ -632,6 +720,13 @@ initialize_server_extensions (saver_info *si) Bool server_has_xidle_extension_p = False; Bool server_has_sgi_saver_extension_p = False; Bool server_has_mit_saver_extension_p = False; + Bool system_has_proc_interrupts_p = False; + const char *piwhy = 0; + + si->using_xidle_extension = p->use_xidle_extension; + si->using_sgi_saver_extension = p->use_sgi_saver_extension; + si->using_mit_saver_extension = p->use_mit_saver_extension; + si->using_proc_interrupts = p->use_proc_interrupts; #ifdef HAVE_XIDLE_EXTENSION server_has_xidle_extension_p = query_xidle_extension (si); @@ -642,22 +737,25 @@ initialize_server_extensions (saver_info *si) #ifdef HAVE_MIT_SAVER_EXTENSION server_has_mit_saver_extension_p = query_mit_saver_extension (si); #endif +#ifdef HAVE_PROC_INTERRUPTS + system_has_proc_interrupts_p = query_proc_interrupts_available (si, &piwhy); +#endif if (!server_has_xidle_extension_p) - p->use_xidle_extension = False; + si->using_xidle_extension = False; else if (p->verbose_p) { - if (p->use_xidle_extension) + if (si->using_xidle_extension) fprintf (stderr, "%s: using XIDLE extension.\n", blurb()); else fprintf (stderr, "%s: not using server's XIDLE extension.\n", blurb()); } if (!server_has_sgi_saver_extension_p) - p->use_sgi_saver_extension = False; + si->using_sgi_saver_extension = False; else if (p->verbose_p) { - if (p->use_sgi_saver_extension) + if (si->using_sgi_saver_extension) fprintf (stderr, "%s: using SGI SCREEN_SAVER extension.\n", blurb()); else fprintf (stderr, @@ -666,10 +764,10 @@ initialize_server_extensions (saver_info *si) } if (!server_has_mit_saver_extension_p) - p->use_mit_saver_extension = False; + si->using_mit_saver_extension = False; else if (p->verbose_p) { - if (p->use_mit_saver_extension) + if (si->using_mit_saver_extension) fprintf (stderr, "%s: using lame MIT-SCREEN-SAVER extension.\n", blurb()); else @@ -677,6 +775,25 @@ initialize_server_extensions (saver_info *si) "%s: not using server's lame MIT-SCREEN-SAVER extension.\n", blurb()); } + + if (!system_has_proc_interrupts_p) + { + si->using_proc_interrupts = False; + if (p->verbose_p && piwhy) + fprintf (stderr, "%s: not using /proc/interrupts: %s.\n", blurb(), + piwhy); + } + else if (p->verbose_p) + { + if (si->using_proc_interrupts) + fprintf (stderr, + "%s: consulting /proc/interrupts for keyboard activity.\n", + blurb()); + else + fprintf (stderr, + "%s: not consulting /proc/interrupts for keyboard activity.\n", + blurb()); + } } @@ -692,9 +809,9 @@ select_events (saver_info *si) saver_preferences *p = &si->prefs; int i; - if (p->use_xidle_extension || - p->use_mit_saver_extension || - p->use_sgi_saver_extension) + if (si->using_xidle_extension || + si->using_mit_saver_extension || + si->using_sgi_saver_extension) return; if (p->initial_delay) @@ -723,7 +840,8 @@ select_events (saver_info *si) for window creation events, so that new subwindows will be noticed. */ for (i = 0; i < si->nscreens; i++) - start_notice_events_timer (si, RootWindowOfScreen (si->screens[i].screen)); + start_notice_events_timer (si, RootWindowOfScreen (si->screens[i].screen), + False); if (p->verbose_p) fprintf (stderr, " done.\n"); @@ -766,6 +884,7 @@ main_loop (saver_info *si) while (1) { + Bool was_locked = False; sleep_until_idle (si, True); if (p->verbose_p) @@ -781,33 +900,77 @@ main_loop (saver_info *si) maybe_reload_init_file (si); - blank_screen (si); + if (! blank_screen (si)) + { + /* We were unable to grab either the keyboard or mouse. + This means we did not (and must not) blank the screen. + If we were to blank the screen while some other program + is holding both the mouse and keyboard grabbed, then + we would never be able to un-blank it! We would never + see any events, and the display would be wedged. + + So, just go around the loop again and wait for the + next bout of idleness. + */ + + fprintf (stderr, + "%s: unable to grab keyboard or mouse! Blanking aborted.\n", + blurb()); + continue; + } + kill_screenhack (si); - spawn_screenhack (si, True); + + if (!si->throttled_p) + spawn_screenhack (si, True); + else if (p->verbose_p) + fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb()); /* Don't start the cycle timer in demo mode. */ if (!si->demoing_p && p->cycle) - si->cycle_id = XtAppAddTimeOut (si->app, p->cycle, cycle_timer, + si->cycle_id = XtAppAddTimeOut (si->app, + (si->selection_mode + /* see comment in cycle_timer() */ + ? 1000 * 60 * 60 + : p->cycle), + cycle_timer, (XtPointer) si); #ifndef NO_LOCKING - if (!si->demoing_p && /* if not going into demo mode */ - p->lock_p && /* and locking is enabled */ - !si->locking_disabled_p && /* and locking is possible */ - p->lock_timeout == 0) /* and locking is not timer-deferred */ - si->locked_p = True; /* then lock right now. */ - - /* locked_p might be true already because of the above, or because of - the LOCK ClientMessage. But if not, and if we're supposed to lock - after some time, set up a timer to do so. - */ - if (p->lock_p && - !si->locked_p && - p->lock_timeout > 0) - si->lock_id = XtAppAddTimeOut (si->app, p->lock_timeout, - activate_lock_timer, - (XtPointer) si); + { + Time lock_timeout = p->lock_timeout; + + if (si->emergency_lock_p && p->lock_p && lock_timeout) + { + int secs = p->lock_timeout / 1000; + if (p->verbose_p) + fprintf (stderr, + "%s: locking now, instead of waiting for %d:%02d:%02d.\n", + blurb(), + (secs / (60 * 60)), ((secs / 60) % 60), (secs % 60)); + lock_timeout = 0; + } + + si->emergency_lock_p = False; + + if (!si->demoing_p && /* if not going into demo mode */ + p->lock_p && /* and locking is enabled */ + !si->locking_disabled_p && /* and locking is possible */ + lock_timeout == 0) /* and locking is not timer-deferred */ + set_locked_p (si, True); /* then lock right now. */ + + /* locked_p might be true already because of the above, or because of + the LOCK ClientMessage. But if not, and if we're supposed to lock + after some time, set up a timer to do so. + */ + if (p->lock_p && + !si->locked_p && + lock_timeout > 0) + si->lock_id = XtAppAddTimeOut (si->app, lock_timeout, + activate_lock_timer, + (XtPointer) si); + } #endif /* !NO_LOCKING */ @@ -823,6 +986,7 @@ main_loop (saver_info *si) saver_screen_info *ssi = si->default_screen; if (si->locking_disabled_p) abort (); + was_locked = True; si->dbox_up_p = True; suspend_screenhack (si, True); XUndefineCursor (si->dpy, ssi->screensaver_window); @@ -846,10 +1010,21 @@ main_loop (saver_info *si) kill_screenhack (si); unblank_screen (si); - si->locked_p = False; + set_locked_p (si, False); + si->emergency_lock_p = False; si->demoing_p = 0; si->selection_mode = 0; + /* If we're throttled, and the user has explicitly unlocked the screen, + then unthrottle. If we weren't locked, then don't unthrottle + automatically, because someone might have just bumped the desk... */ + if (was_locked) + { + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; + } + if (si->cycle_id) { XtRemoveTimeOut (si->cycle_id); @@ -892,20 +1067,31 @@ main (int argc, char **argv) process_command_line (si, &argc, argv); print_banner (si); - initialize_per_screen_info (si, shell); /* also sets p->fading_possible_p */ + load_init_file (p); /* must be before initialize_per_screen_info() */ + initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */ + + /* We can only issue this warnings now. */ + if (p->verbose_p && !si->fading_possible_p && (p->fade_p || p->unfade_p)) + fprintf (stderr, + "%s: there are no PseudoColor or GrayScale visuals.\n" + "%s: ignoring the request for fading/unfading.\n", + blurb(), blurb()); for (i = 0; i < si->nscreens; i++) if (ensure_no_screensaver_running (si->dpy, si->screens[i].screen)) exit (1); - load_init_file (p); + 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); + + si->blank_time = time ((time_t) 0); /* must be before ..._window */ initialize_screensaver_window (si); + select_events (si); init_sigchld (); disable_builtin_screensaver (si, True); @@ -939,7 +1125,7 @@ clientmessage_response (saver_info *si, Window w, Bool error, L++; XChangeProperty (si->dpy, w, XA_SCREENSAVER_RESPONSE, XA_STRING, 8, - PropModeReplace, proto, L); + PropModeReplace, (unsigned char *) proto, L); XSync (si->dpy, False); free (proto); } @@ -980,7 +1166,12 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) "activating."); si->selection_mode = 0; si->demoing_p = False; - if (p->use_mit_saver_extension || p->use_sgi_saver_extension) + + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; + + if (si->using_mit_saver_extension || si->using_sgi_saver_extension) { XForceScreenSaver (si->dpy, ScreenSaverActive); return False; @@ -998,10 +1189,14 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) { if (! until_idle_p) { + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; + clientmessage_response(si, window, False, "DEACTIVATE ClientMessage received.", "deactivating."); - if (p->use_mit_saver_extension || p->use_sgi_saver_extension) + if (si->using_mit_saver_extension || si->using_sgi_saver_extension) { XForceScreenSaver (si->dpy, ScreenSaverReset); return False; @@ -1024,6 +1219,11 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) "cycling."); si->selection_mode = 0; /* 0 means randomize when its time. */ si->demoing_p = False; + + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; + if (si->cycle_id) XtRemoveTimeOut (si->cycle_id); si->cycle_id = 0; @@ -1044,6 +1244,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) si->selection_mode = (type == XA_NEXT ? -1 : -2); si->demoing_p = False; + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; + if (! until_idle_p) { if (si->cycle_id) @@ -1068,6 +1272,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) si->selection_mode = which; si->demoing_p = False; + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; + if (! until_idle_p) { if (si->cycle_id) @@ -1116,6 +1324,10 @@ 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)); @@ -1149,6 +1361,10 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) si->selection_mode = which; si->demoing_p = True; + if (si->throttled_p && p->verbose_p) + fprintf (stderr, "%s: unthrottled.\n", blurb()); + si->throttled_p = False; + return True; } @@ -1190,11 +1406,11 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) char *response = (until_idle_p ? "activating and locking." : "locking."); - si->locked_p = True; - si->selection_mode = 0; - si->demoing_p = False; sprintf (buf, "LOCK ClientMessage received; %s", response); clientmessage_response (si, window, False, buf, response); + set_locked_p (si, True); + si->selection_mode = 0; + si->demoing_p = False; if (si->lock_id) /* we're doing it now, so lose the timeout */ { @@ -1204,7 +1420,8 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) if (until_idle_p) { - if (p->use_mit_saver_extension || p->use_sgi_saver_extension) + if (si->using_mit_saver_extension || + si->using_sgi_saver_extension) { XForceScreenSaver (si->dpy, ScreenSaverActive); return False; @@ -1217,6 +1434,58 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) } #endif /* !NO_LOCKING */ } + else if (type == XA_THROTTLE) + { + if (si->throttled_p) + clientmessage_response (si, window, True, + "THROTTLE ClientMessage received, but " + "already throttled.", + "already throttled."); + else + { + char buf [255]; + char *response = "throttled."; + si->throttled_p = True; + si->selection_mode = 0; + si->demoing_p = False; + sprintf (buf, "THROTTLE ClientMessage received; %s", response); + clientmessage_response (si, window, False, buf, response); + + if (! until_idle_p) + { + if (si->cycle_id) + XtRemoveTimeOut (si->cycle_id); + si->cycle_id = 0; + cycle_timer ((XtPointer) si, 0); + } + } + } + else if (type == XA_UNTHROTTLE) + { + if (! si->throttled_p) + clientmessage_response (si, window, True, + "UNTHROTTLE ClientMessage received, but " + "not throttled.", + "not throttled."); + else + { + char buf [255]; + char *response = "unthrottled."; + si->throttled_p = False; + si->selection_mode = 0; + si->demoing_p = False; + sprintf (buf, "UNTHROTTLE ClientMessage received; %s", response); + clientmessage_response (si, window, False, buf, response); + + if (! until_idle_p) + { + if (si->cycle_id) + XtRemoveTimeOut (si->cycle_id); + si->cycle_id = 0; + cycle_timer ((XtPointer) si, 0); + } + } + } else { char buf [1024]; @@ -1252,16 +1521,18 @@ analyze_display (saver_info *si) { int i, j; static const char *exts[][2] = { - { "SCREEN_SAVER", "SGI Screen-Saver" }, - { "SCREEN-SAVER", "SGI Screen-Saver" }, - { "MIT-SCREEN-SAVER", "MIT Screen-Saver" }, - { "XIDLE", "XIdle" }, - { "SGI-VIDEO-CONTROL", "SGI Video-Control" }, - { "READDISPLAY", "SGI Read-Display" }, - { "MIT-SHM", "Shared Memory" }, - { "DOUBLE-BUFFER", "Double-Buffering" }, - { "DPMS", "Power Management" }, - { "GLX", "GLX" } + { "SCREEN_SAVER", "SGI Screen-Saver" }, + { "SCREEN-SAVER", "SGI Screen-Saver" }, + { "MIT-SCREEN-SAVER", "MIT Screen-Saver" }, + { "XIDLE", "XIdle" }, + { "SGI-VIDEO-CONTROL", "SGI Video-Control" }, + { "READDISPLAY", "SGI Read-Display" }, + { "MIT-SHM", "Shared Memory" }, + { "DOUBLE-BUFFER", "Double-Buffering" }, + { "DPMS", "Power Management" }, + { "GLX", "GLX" }, + { "XFree86-VidModeExtension", "XF86 Video-Mode" }, + { "XINERAMA", "Xinerama" } }; fprintf (stderr, "%s: running on display \"%s\"\n", blurb(), @@ -1311,3 +1582,50 @@ analyze_display (saver_info *si) } } } + +Bool +display_is_on_console_p (saver_info *si) +{ + Bool not_on_console = True; + char *dpystr = DisplayString (si->dpy); + char *tail = (char *) strchr (dpystr, ':'); + if (! tail || strncmp (tail, ":0", 2)) + not_on_console = True; + else + { + char dpyname[255], localname[255]; + strncpy (dpyname, dpystr, tail-dpystr); + dpyname [tail-dpystr] = 0; + if (!*dpyname || + !strcmp(dpyname, "unix") || + !strcmp(dpyname, "localhost")) + not_on_console = False; + else if (gethostname (localname, sizeof (localname))) + not_on_console = True; /* can't find hostname? */ + else + { + /* We have to call gethostbyname() on the result of gethostname() + because the two aren't guarenteed to be the same name for the + same host: on some losing systems, one is a FQDN and the other + is not. Here in the wide wonderful world of Unix it's rocket + science to obtain the local hostname in a portable fashion. + + And don't forget, gethostbyname() reuses the structure it + returns, so we have to copy the fucker before calling it again. + Thank you master, may I have another. + */ + struct hostent *h = gethostbyname (dpyname); + if (!h) + not_on_console = True; + else + { + char hn [255]; + struct hostent *l; + strcpy (hn, h->h_name); + l = gethostbyname (localname); + not_on_console = (!l || !!(strcmp (l->h_name, hn))); + } + } + } + return !not_on_console; +}