-/* xscreensaver, Copyright (c) 1991-1999 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1991-2001 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
* 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
* 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
* 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
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;
\f
static XrmOptionDescRec options [] = {
fflush (stdout);
fflush (stderr);
fprintf (stdout, "\
-xscreensaver %s, copyright (c) 1991-1999 by Jamie Zawinski <jwz@jwz.org>\n\
+xscreensaver %s, copyright (c) 1991-2001 by Jamie Zawinski <jwz@jwz.org>\n\
The standard Xt command-line options are accepted; other options include:\n\
\n\
-timeout <minutes> When the screensaver should activate.\n\
"#######################################"
"#######################################\n\n");
fprintf (real_stderr,
- " If at all possible, please re-run xscreensaver with the command line\n"
- " arguments `-sync -verbose', and reproduce this bug. That will cause\n"
- " xscreensaver to dump a `core' file to the current directory. Please\n"
- " include the stack trace from that core file in your bug report.\n"
+ " If at all possible, please re-run xscreensaver with the command\ e\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 the\n"
- " most useful bug reports, and how to examine core files.\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 report\n"
+ " The more information you can provide, the better. But please\n"
" report this bug, regardless!\n"
"\n");
fprintf (real_stderr,
fprintf (stderr, "\n");
describe_uids (si, stderr);
- fprintf (stderr, "\n"
- "%s: Errors at startup are usually authorization problems.\n"
- " Did you read the manual? Specifically, the parts\n"
- " that talk about XAUTH, XDM, and root logins?\n"
- "\n"
- " http://www.jwz.org/xscreensaver/man.html\n"
- "\n",
+
+ if (si->orig_uid && !strncmp (si->orig_uid, "root/", 5))
+ {
+ fprintf (stderr, "\n"
+ "%s: This is probably because you're logging in as root. You\n"
+" shouldn't log in as root: you should log in as a normal user,\n"
+" and then `su' as needed. If you insist on logging in as\n"
+" root, you will have to turn off X's security features before\n"
+" xscreensaver will work.\n"
+ "\n"
+" Please read the manual and FAQ for more information:\n",
+ blurb());
+ }
+ else
+ {
+ fprintf (stderr, "\n"
+ "%s: Errors at startup are usually authorization problems.\n"
+" But you're not logging in as root (good!) so something\n"
+" else must be wrong. Did you read the manual and the FAQ?\n",
blurb());
+ }
+
+ fprintf (stderr, "\n"
+ " http://www.jwz.org/xscreensaver/faq.html\n"
+ " http://www.jwz.org/xscreensaver/man.html\n"
+ "\n");
fflush (stderr);
fflush (stdout);
lock_priv_init (*argc, argv, si->prefs.verbose_p);
#endif /* NO_LOCKING */
-#ifndef NO_SETUID
hack_uid (si);
-#endif /* NO_SETUID */
}
si->locking_disabled_p = True;
si->nolock_reason = "not compiled with locking support";
#else /* !NO_LOCKING */
- si->locking_disabled_p = False;
/* Finish initializing locking, now that we're out of privileged code. */
if (! lock_init (*argc, argv, si->prefs.verbose_p))
}
#endif /* NO_LOCKING */
-#ifndef NO_SETUID
hack_uid (si);
-#endif /* NO_SETUID */
}
{
Widget toplevel_shell;
+#ifdef HAVE_PUTENV
+ char *d = getenv ("DISPLAY");
+ if (!d || !*d)
+ {
+ const char ndpy[] = "DISPLAY=:0.0";
+ /* if (si->prefs.verbose_p) */ /* sigh, too early to test this... */
+ fprintf (stderr,
+ "%s: warning: $DISPLAY is not set: defaulting to \"%s\".\n",
+ blurb(), ndpy+8);
+ if (putenv (ndpy))
+ abort ();
+ }
+#endif /* HAVE_PUTENV */
+
XSetErrorHandler (saver_ehandler);
XtAppSetErrorMsgHandler (si->app, startup_ehandler);
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);
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;
}
if (p->verbose_p)
fprintf (stderr,
- "%s %s, copyright (c) 1991-1999 "
+ "%s %s, copyright (c) 1991-2001 "
"by Jamie Zawinski <jwz@jwz.org>.\n",
progname, si->version);
/* Examine all of the display's screens, and populate the `saver_screen_info'
- structures.
+ structures. Make sure this is called after hack_environment() sets $PATH.
*/
static void
initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
ssi->current_visual = ssi->default_visual;
ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
+ /* Execute a subprocess to find the GL visual. */
+ ssi->best_gl_visual = get_best_gl_visual (ssi);
+
if (ssi == si->default_screen)
/* Since this is the default screen, use the one already created. */
ssi->toplevel_shell = toplevel_shell;
}
}
- si->prefs.fading_possible_p = found_any_writable_cells;
+ si->fading_possible_p = found_any_writable_cells;
}
while (1)
{
+ Bool was_locked = False;
sleep_until_idle (si, True);
if (p->verbose_p)
}
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 */
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);
si->dbox_up_p = False;
XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
suspend_screenhack (si, False); /* resume */
+
+ if (!ok_to_unblank &&
+ !screenhack_running_p (si))
+ {
+ /* If the lock dialog has been dismissed and we're not about to
+ unlock the screen, and there is currently no hack running,
+ then launch one. (There might be no hack running if DPMS
+ had kicked in. But DPMS is off now, so bring back the hack)
+ */
+ if (si->cycle_id)
+ XtRemoveTimeOut (si->cycle_id);
+ si->cycle_id = 0;
+ cycle_timer ((XtPointer) si, 0);
+ }
}
#endif /* !NO_LOCKING */
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);
memset(si, 0, sizeof(*si));
global_si_kludge = si; /* I hate C so much... */
- srandom ((int) time ((time_t *) 0));
+# undef ya_rand_init
+ ya_rand_init (0);
save_argv (argc, argv);
set_version_string (si, &argc, 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);
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);
Bool
handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
{
+ saver_preferences *p = &si->prefs;
Atom type = 0;
Window window = event->xclient.window;
"activating.");
si->selection_mode = 0;
si->demoing_p = False;
+
+ 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);
{
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.");
"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;
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)
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)
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));
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;
}
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 */
{
}
#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];
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" }
+ static struct {
+ const char *name; const char *desc; Bool useful_p;
+ } exts[] = {
+
+ { "SCREEN_SAVER", "SGI Screen-Saver",
+# ifdef HAVE_SGI_SAVER_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "SCREEN-SAVER", "SGI Screen-Saver",
+# ifdef HAVE_SGI_SAVER_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "MIT-SCREEN-SAVER", "MIT Screen-Saver",
+# ifdef HAVE_MIT_SAVER_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "XIDLE", "XIdle",
+# ifdef HAVE_XIDLE_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "SGI-VIDEO-CONTROL", "SGI Video-Control",
+# ifdef HAVE_SGI_VC_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "READDISPLAY", "SGI Read-Display",
+# ifdef HAVE_READ_DISPLAY_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "MIT-SHM", "Shared Memory",
+# ifdef HAVE_XSHM_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "DOUBLE-BUFFER", "Double-Buffering",
+# ifdef HAVE_DOUBLE_BUFFER_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "DPMS", "Power Management",
+# ifdef HAVE_DPMS_EXTENSION
+ True
+# else
+ False
+# endif
+ }, { "GLX", "GLX",
+# ifdef HAVE_GL
+ True
+# else
+ False
+# endif
+ }, { "XFree86-VidModeExtension", "XF86 Video-Mode",
+# ifdef HAVE_XF86VMODE
+ True
+# else
+ False
+# endif
+ }, { "XINERAMA", "Xinerama",
+ True
+ },
};
fprintf (stderr, "%s: running on display \"%s\"\n", blurb(),
for (i = 0; i < countof(exts); i++)
{
int op = 0, event = 0, error = 0;
- if (XQueryExtension (si->dpy, exts[i][0], &op, &event, &error))
- fprintf (stderr, "%s: %s\n", blurb(), exts[i][1]);
+ 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!"));
}
for (i = 0; i < si->nscreens; i++)