X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=driver%2Fxscreensaver.c;h=4460c19df6125b9c358df07e4a3a179bb06f98e4;hp=92b0f6f4a35a1e08419c6cee7497ce7f96d1ee57;hb=551b3de3f619c04c2dd1971ee9b3f02e270c28c9;hpb=2a991a811de4c7b22f812682b267b616a809fd9a diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c index 92b0f6f4..4460c19d 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 @@ -131,6 +131,7 @@ #include #include #include +#include /* for gethostbyname() */ #ifdef HAVE_XMU # ifndef VMS # include @@ -142,7 +143,7 @@ #endif /* !HAVE_XMU */ #ifdef HAVE_XIDLE_EXTENSION -#include +# include #endif /* HAVE_XIDLE_EXTENSION */ #include "xscreensaver.h" @@ -150,6 +151,7 @@ #include "yarandom.h" #include "resources.h" #include "visual.h" +#include "usleep.h" saver_info *global_si_kludge = 0; /* I hate C so much... */ @@ -169,6 +171,7 @@ static XrmOptionDescRec options [] = { { "-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" }, @@ -186,6 +189,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" }, @@ -212,7 +217,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\ @@ -228,7 +233,8 @@ The standard Xt command-line options are accepted; other options include:\n\ See the manual for other options and X resources.\n\ \n\ The `xscreensaver' program should be left running in the background.\n\ -Use the `xscreensaver-command' program to manipulate a running xscreensaver.\n\ +Use the `xscreensaver-demo' and `xscreensaver-command' programs to\n\ +manipulate a running xscreensaver.\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\ @@ -236,7 +242,7 @@ the screensaver. See `man xscreensaver' or the web page for more details.\n\ Just getting started? Try this:\n\ \n\ xscreensaver &\n\ - xscreensaver-command -demo\n\ + xscreensaver-demo\n\ \n\ For updates, check http://www.jwz.org/xscreensaver/\n\ \n", @@ -285,6 +291,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" @@ -301,11 +309,25 @@ 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 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" + "\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" + "\n" + " The more information you can provide, the better. But please report\n" + " report this bug, regardless!\n" + "\n"); + fprintf (real_stderr, + "#######################################" + "#######################################\n\n"); + saver_exit (si, -1, 0); } } @@ -314,13 +336,53 @@ saver_ehandler (Display *dpy, XErrorEvent *error) return 0; } - -/* The zillions of initializations. - */ -static void get_screenhacks (saver_info *si); +/* 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? Specifically, the parts\n" + " that talk about XAUTH, XDM, 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. + */ /* Set progname, version, etc. This is done very early. */ @@ -357,12 +419,30 @@ 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 */ + +#ifndef NO_SETUID + hack_uid (si); +#endif /* NO_SETUID */ +} + + +/* 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"; @@ -383,18 +463,21 @@ 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->db = XtDatabase (si->dpy); + si->prefs.db = XtDatabase (si->dpy); XtGetApplicationNameAndClass (si->dpy, &progname, &progclass); if(strlen(progname) > 100) /* keep it short. */ progname [99] = 0; - db = si->db; /* resources.c needs this */ + db = si->prefs.db; /* resources.c needs this */ XA_VROOT = XInternAtom (si->dpy, "__SWM_VROOT", False); XA_SCREENSAVER = XInternAtom (si->dpy, "SCREENSAVER", False); @@ -433,11 +516,6 @@ process_command_line (saver_info *si, int *argc, char **argv) /* no resource for this one, out of paranoia. */ si->prefs.debug_p = True; - else if (!strcmp (argv[i], "-initial-demo-mode")) - /* This isn't an advertized option; it is used internally to implement - the "Reinitialize" button on the Demo Mode window. */ - si->demo_mode_p = True; - else if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "-help") || !strcmp (argv[i], "--help")) @@ -464,13 +542,20 @@ process_command_line (saver_info *si, int *argc, char **argv) !strcmp (s, "-version") || !strcmp (s, "-time")) { - fprintf (stderr, "\n\ - However, %s is an option to the `xscreensaver-command' program.\n\ + + if (!strcmp (s, "-demo") || !strcmp (s, "-prefs")) + fprintf (stderr, "\n\ + Perhaps you meant to run the `xscreensaver-demo' program instead?\n"); + else + fprintf (stderr, "\n\ + However, `%s' is an option to the `xscreensaver-command' program.\n", s); + + fprintf (stderr, "\ The `xscreensaver' program is a daemon that runs in the background.\n\ You control a running xscreensaver process by sending it messages\n\ - with `xscreensaver-command'. See the man pages for details,\n\ - or check the web page: http://www.jwz.org/xscreensaver/\n\n", - s); + with `xscreensaver-demo' or `xscreensaver-command'.\n\ +. See the man pages for details, or check the web page:\n\ + http://www.jwz.org/xscreensaver/\n\n"); /* Since version 1.21 renamed the "-lock" option to "-lock-mode", suggest that explicitly. */ @@ -479,6 +564,7 @@ process_command_line (saver_info *si, int *argc, char **argv) Or perhaps you meant either the \"-lock-mode\" or the\n\ \"-lock-timeout \" options to xscreensaver?\n\n"); } + exit (1); } } @@ -504,9 +590,9 @@ print_banner (saver_info *si) if (p->verbose_p) fprintf (stderr, - "%s %s, copyright (c) 1991-1998 by Jamie Zawinski \n" - " pid = %d.\n", - blurb(), si->version, (int) getpid ()); + "%s %s, copyright (c) 1991-1999 " + "by Jamie Zawinski .\n", + progname, si->version); if (p->debug_p) fprintf (stderr, "\n" @@ -533,6 +619,9 @@ print_banner (saver_info *si) blurb(), si->orig_uid); fprintf (stderr, "%s: %s\n", blurb(), si->uid_message); } + + fprintf (stderr, "%s: in process %lu.\n", blurb(), + (unsigned long) getpid()); } /* If locking was not able to be initalized for some reason, explain why. @@ -613,237 +702,95 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell) } } - si->fading_possible_p = found_any_writable_cells; + si->prefs.fading_possible_p = found_any_writable_cells; } -/* Populate `saver_preferences' with the contents of the resource database. - Note that this may be called multiple times -- it is re-run each time - the ~/.xscreensaver file is reloaded. - - This function can be very noisy, since it issues resource syntax errors - and so on. +/* If any server extensions have been requested, try and initialize them. + Issue warnings if requests can't be honored. */ -void -get_resources (saver_info *si) +static void +initialize_server_extensions (saver_info *si) { - char *s; saver_preferences *p = &si->prefs; - if (si->init_file_date == 0) - /* The date will be 0 the first time this is called; and when this is - called subsequent times, the file will have already been reloaded. */ - read_init_file (si); - - p->xsync_p = get_boolean_resource ("synchronous", "Synchronous"); - if (p->xsync_p) - XSynchronize(si->dpy, True); - - p->verbose_p = get_boolean_resource ("verbose", "Boolean"); - p->timestamp_p = get_boolean_resource ("timestamp", "Boolean"); - p->lock_p = get_boolean_resource ("lock", "Boolean"); - p->lock_vt_p = get_boolean_resource ("lockVTs", "Boolean"); - p->fade_p = get_boolean_resource ("fade", "Boolean"); - p->unfade_p = get_boolean_resource ("unfade", "Boolean"); - p->fade_seconds = 1000 * get_seconds_resource ("fadeSeconds", "Time"); - p->fade_ticks = get_integer_resource ("fadeTicks", "Integer"); - p->install_cmap_p = get_boolean_resource ("installColormap", "Boolean"); - p->nice_inferior = get_integer_resource ("nice", "Nice"); - - p->initial_delay = 1000 * get_seconds_resource ("initialDelay", "Time"); - p->splash_duration = 1000 * get_seconds_resource ("splashDuration", "Time"); - p->timeout = 1000 * get_minutes_resource ("timeout", "Time"); - p->lock_timeout = 1000 * get_minutes_resource ("lockTimeout", "Time"); - p->cycle = 1000 * get_minutes_resource ("cycle", "Time"); - p->passwd_timeout = 1000 * get_seconds_resource ("passwdTimeout", "Time"); - p->pointer_timeout = 1000 * get_seconds_resource ("pointerPollTime", "Time"); - p->notice_events_timeout = 1000*get_seconds_resource("windowCreationTimeout", - "Time"); - p->shell = get_string_resource ("bourneShell", "BourneShell"); - - p->help_url = get_string_resource("helpURL", "URL"); - p->load_url_command = get_string_resource("loadURL", "LoadURL"); - - if ((s = get_string_resource ("splash", "Boolean"))) - if (!get_boolean_resource("splash", "Boolean")) - p->splash_duration = 0; - if (s) free (s); - - if (p->verbose_p && !si->fading_possible_p && (p->fade_p || p->unfade_p)) - { - fprintf (stderr, - (si->nscreens == 1 - ? "%s: the screen has no PseudoColor or GrayScale visuals.\n" - : "%s: no screens have PseudoColor or GrayScale visuals.\n"), - blurb()); - fprintf (stderr, "%s: ignoring the request for fading/unfading.\n", - blurb()); - } - - /* don't set use_xidle_extension unless it is explicitly specified */ - if ((s = get_string_resource ("xidleExtension", "Boolean"))) - p->use_xidle_extension = get_boolean_resource ("xidleExtension","Boolean"); - else -#ifdef HAVE_XIDLE_EXTENSION /* pick a default */ - p->use_xidle_extension = True; /* if we have it, use it */ -#else /* !HAVE_XIDLE_EXTENSION */ - p->use_xidle_extension = False; -#endif /* !HAVE_XIDLE_EXTENSION */ - if (s) free (s); - - /* don't set use_mit_extension unless it is explicitly specified */ - if ((s = get_string_resource ("mitSaverExtension", "Boolean"))) - p->use_mit_saver_extension = get_boolean_resource ("mitSaverExtension", - "Boolean"); - else -#ifdef HAVE_MIT_SAVER_EXTENSION /* pick a default */ - p->use_mit_saver_extension = False; /* Default false, because it sucks */ -#else /* !HAVE_MIT_SAVER_EXTENSION */ - p->use_mit_saver_extension = False; -#endif /* !HAVE_MIT_SAVER_EXTENSION */ - if (s) free (s); - - - /* don't set use_mit_extension unless it is explicitly specified */ - if ((s = get_string_resource ("sgiSaverExtension", "Boolean"))) - p->use_sgi_saver_extension = get_boolean_resource ("sgiSaverExtension", - "Boolean"); - else -#ifdef HAVE_SGI_SAVER_EXTENSION /* pick a default */ - p->use_sgi_saver_extension = True; /* if we have it, use it */ -#else /* !HAVE_SGI_SAVER_EXTENSION */ - p->use_sgi_saver_extension = False; -#endif /* !HAVE_SGI_SAVER_EXTENSION */ - if (s) free (s); + 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; - /* Throttle the various timeouts to reasonable values. - */ - if (p->passwd_timeout == 0) p->passwd_timeout = 30000; /* 30 secs */ - if (p->timeout < 10000) p->timeout = 10000; /* 10 secs */ - if (p->cycle != 0 && p->cycle < 2000) p->cycle = 2000; /* 2 secs */ - if (p->pointer_timeout == 0) p->pointer_timeout = 5000; /* 5 secs */ - if (p->notice_events_timeout == 0) - p->notice_events_timeout = 10000; /* 10 secs */ - if (p->fade_seconds == 0 || p->fade_ticks == 0) - p->fade_p = False; - if (! p->fade_p) p->unfade_p = False; - - p->watchdog_timeout = p->cycle; - if (p->watchdog_timeout < 30000) p->watchdog_timeout = 30000; /* 30 secs */ - if (p->watchdog_timeout > 3600000) p->watchdog_timeout = 3600000; /* 1 hr */ - - get_screenhacks (si); +#ifdef HAVE_XIDLE_EXTENSION + server_has_xidle_extension_p = query_xidle_extension (si); +#endif +#ifdef HAVE_SGI_SAVER_EXTENSION + server_has_sgi_saver_extension_p = query_sgi_saver_extension (si); +#endif +#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 (p->debug_p) + if (!server_has_xidle_extension_p) + si->using_xidle_extension = False; + else if (p->verbose_p) { - XSynchronize(si->dpy, True); - p->xsync_p = True; - p->verbose_p = True; - p->timestamp_p = True; - p->initial_delay = 0; + 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()); } - blurb_timestamp_p = p->timestamp_p; -} - - -/* If any server extensions have been requested, try and initialize them. - Issue warnings if requests can't be honored. - */ -static void -initialize_server_extensions (saver_info *si) -{ - saver_preferences *p = &si->prefs; - - if (p->use_sgi_saver_extension) + if (!server_has_sgi_saver_extension_p) + si->using_sgi_saver_extension = False; + else if (p->verbose_p) { -#ifdef HAVE_SGI_SAVER_EXTENSION - if (! query_sgi_saver_extension (si)) - { - fprintf (stderr, - "%s: display %s does not support the SGI SCREEN_SAVER extension.\n", - blurb(), DisplayString (si->dpy)); - p->use_sgi_saver_extension = False; - } - else if (p->use_mit_saver_extension) - { - fprintf (stderr, - "%s: SGI SCREEN_SAVER extension used instead" - " of MIT-SCREEN-SAVER extension.\n", - blurb()); - p->use_mit_saver_extension = False; - } - else if (p->use_xidle_extension) - { - fprintf (stderr, - "%s: SGI SCREEN_SAVER extension used instead of XIDLE extension.\n", - blurb()); - p->use_xidle_extension = False; - } -#else /* !HAVE_MIT_SAVER_EXTENSION */ - fprintf (stderr, - "%s: not compiled with support for the SGI SCREEN_SAVER" - " extension.\n", - blurb()); - p->use_sgi_saver_extension = False; -#endif /* !HAVE_SGI_SAVER_EXTENSION */ + if (si->using_sgi_saver_extension) + fprintf (stderr, "%s: using SGI SCREEN_SAVER extension.\n", blurb()); + else + fprintf (stderr, + "%s: not using server's SGI SCREEN_SAVER extension.\n", + blurb()); } - if (p->use_mit_saver_extension) + if (!server_has_mit_saver_extension_p) + si->using_mit_saver_extension = False; + else if (p->verbose_p) { -#ifdef HAVE_MIT_SAVER_EXTENSION - if (! query_mit_saver_extension (si)) - { - fprintf (stderr, - "%s: display %s does not support the MIT-SCREEN-SAVER" - " extension.\n", - blurb(), DisplayString (si->dpy)); - p->use_mit_saver_extension = False; - } - else if (p->use_xidle_extension) - { - fprintf (stderr, - "%s: MIT-SCREEN-SAVER extension used instead of XIDLE" - " extension.\n", - blurb()); - p->use_xidle_extension = False; - } -#else /* !HAVE_MIT_SAVER_EXTENSION */ - fprintf (stderr, - "%s: not compiled with support for the MIT-SCREEN-SAVER" - " extension.\n", - blurb()); - p->use_mit_saver_extension = False; -#endif /* !HAVE_MIT_SAVER_EXTENSION */ + if (si->using_mit_saver_extension) + fprintf (stderr, "%s: using lame MIT-SCREEN-SAVER extension.\n", + blurb()); + else + fprintf (stderr, + "%s: not using server's lame MIT-SCREEN-SAVER extension.\n", + blurb()); } - if (p->use_xidle_extension) + if (!system_has_proc_interrupts_p) { -#ifdef HAVE_XIDLE_EXTENSION - int first_event, first_error; - if (! XidleQueryExtension (si->dpy, &first_event, &first_error)) - { - fprintf (stderr, - "%s: display %s does not support the XIdle extension.\n", - blurb(), DisplayString (si->dpy)); - p->use_xidle_extension = False; - } -#else /* !HAVE_XIDLE_EXTENSION */ - fprintf (stderr, "%s: not compiled with support for XIdle.\n", blurb()); - p->use_xidle_extension = False; -#endif /* !HAVE_XIDLE_EXTENSION */ + 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()); } - - if (p->verbose_p && p->use_mit_saver_extension) - fprintf (stderr, "%s: using MIT-SCREEN-SAVER server extension.\n", - blurb()); - if (p->verbose_p && p->use_sgi_saver_extension) - fprintf (stderr, "%s: using SGI SCREEN_SAVER server extension.\n", - blurb()); - if (p->verbose_p && p->use_xidle_extension) - fprintf (stderr, "%s: using XIdle server extension.\n", - blurb()); } @@ -859,12 +806,12 @@ 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 && !si->demo_mode_p) + if (p->initial_delay) { if (p->verbose_p) { @@ -890,13 +837,33 @@ 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"); } +void +maybe_reload_init_file (saver_info *si) +{ + saver_preferences *p = &si->prefs; + if (init_file_changed_p (p)) + { + if (p->verbose_p) + fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n", + blurb(), init_file_name()); + + load_init_file (p); + + /* If a server extension is in use, and p->timeout has changed, + we need to inform the server of the new timeout. */ + disable_builtin_screensaver (si, False); + } +} + + /* Loop forever: - wait until the user is idle; @@ -910,104 +877,130 @@ static void main_loop (saver_info *si) { saver_preferences *p = &si->prefs; + Bool ok_to_unblank; + while (1) { - if (! si->demo_mode_p) - sleep_until_idle (si, True); + sleep_until_idle (si, True); + + if (p->verbose_p) + { + if (si->demoing_p) + 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()); + } maybe_reload_init_file (si); -#ifndef NO_DEMO_MODE - if (si->demo_mode_p) - demo_mode (si); - else -#endif /* !NO_DEMO_MODE */ - { - if (p->verbose_p) - fprintf (stderr, "%s: user is idle; waking up at %s.\n", blurb(), - timestring()); - maybe_reload_init_file (si); - blank_screen (si); - spawn_screenhack (si, True); - if (p->cycle) - si->cycle_id = XtAppAddTimeOut (si->app, p->cycle, cycle_timer, - (XtPointer) 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. -#ifndef NO_LOCKING - if (p->lock_p && - !si->locking_disabled_p && - p->lock_timeout == 0) - si->locked_p = True; - - if (p->lock_p && !si->locked_p) - /* locked_p might be true already because of ClientMessage */ - si->lock_id = XtAppAddTimeOut (si->app, p->lock_timeout, - activate_lock_timer, - (XtPointer) si); -#endif /* !NO_LOCKING */ + 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; + } - PASSWD_INVALID: + kill_screenhack (si); + spawn_screenhack (si, True); + + /* 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, + (XtPointer) si); - sleep_until_idle (si, False); /* until not idle */ - maybe_reload_init_file (si); #ifndef NO_LOCKING - if (si->locked_p) - { - Bool val; - if (si->locking_disabled_p) abort (); - si->dbox_up_p = True; - - { - saver_screen_info *ssi = si->default_screen; - suspend_screenhack (si, True); - XUndefineCursor (si->dpy, ssi->screensaver_window); - if (p->verbose_p) - fprintf (stderr, "%s: prompting for password.\n", blurb()); - val = unlock_p (si); - if (p->verbose_p && val == False) - fprintf (stderr, "%s: password incorrect!\n", blurb()); - si->dbox_up_p = False; - XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor); - suspend_screenhack (si, False); - } - - if (! val) - goto PASSWD_INVALID; - si->locked_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 */ + 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); #endif /* !NO_LOCKING */ - if (p->verbose_p) - fprintf (stderr, "%s: user is active at %s.\n", - blurb(), timestring ()); - /* Let's kill it before unblanking, to get it to stop drawing as - soon as possible... */ - kill_screenhack (si); - unblank_screen (si); - si->selection_mode = 0; + ok_to_unblank = True; + do { - if (si->cycle_id) - { - XtRemoveTimeOut (si->cycle_id); - si->cycle_id = 0; - } + sleep_until_idle (si, False); /* until not idle */ + maybe_reload_init_file (si); #ifndef NO_LOCKING - if (si->lock_id) - { - XtRemoveTimeOut (si->lock_id); - si->lock_id = 0; - } + if (si->locked_p) + { + saver_screen_info *ssi = si->default_screen; + if (si->locking_disabled_p) abort (); + + si->dbox_up_p = True; + suspend_screenhack (si, True); + XUndefineCursor (si->dpy, ssi->screensaver_window); + + ok_to_unblank = unlock_p (si); + + si->dbox_up_p = False; + XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor); + suspend_screenhack (si, False); /* resume */ + } #endif /* !NO_LOCKING */ - if (p->verbose_p) - fprintf (stderr, "%s: going to sleep.\n", blurb()); + } while (!ok_to_unblank); + + + if (p->verbose_p) + fprintf (stderr, "%s: unblanking screen at %s.\n", + blurb(), timestring ()); + + /* Kill before unblanking, to stop drawing as soon as possible. */ + kill_screenhack (si); + unblank_screen (si); + + si->locked_p = False; + si->demoing_p = 0; + si->selection_mode = 0; + + if (si->cycle_id) + { + XtRemoveTimeOut (si->cycle_id); + si->cycle_id = 0; } + + if (si->lock_id) + { + XtRemoveTimeOut (si->lock_id); + si->lock_id = 0; + } + + if (p->verbose_p) + fprintf (stderr, "%s: awaiting idleness.\n", blurb()); } } +static void analyze_display (saver_info *si); int main (int argc, char **argv) @@ -1015,6 +1008,7 @@ main (int argc, char **argv) Widget shell; saver_info the_si; saver_info *si = &the_si; + saver_preferences *p = &si->prefs; int i; memset(si, 0, sizeof(*si)); @@ -1022,21 +1016,28 @@ main (int argc, char **argv) srandom ((int) time ((time_t *) 0)); - set_version_string (si, &argc, argv); save_argv (argc, argv); + set_version_string (si, &argc, argv); privileged_initialization (si, &argc, argv); hack_environment (si); shell = connect_to_server (si, &argc, argv); process_command_line (si, &argc, argv); print_banner (si); - initialize_per_screen_info (si, shell); - get_resources (si); + + initialize_per_screen_info (si, shell); /* also sets p->fading_possible_p */ 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); initialize_screensaver_window (si); select_events (si); @@ -1044,173 +1045,12 @@ main (int argc, char **argv) disable_builtin_screensaver (si, True); initialize_stderr (si); - if (!si->demo_mode_p) - make_splash_dialog (si); + make_splash_dialog (si); main_loop (si); /* doesn't return */ return 0; } - -/* Parsing the programs resource. - */ - -static char * -reformat_hack (const char *hack) -{ - int i; - const char *in = hack; - int indent = 13; - char *h2 = (char *) malloc(strlen(in) + indent + 2); - char *out = h2; - - while (isspace(*in)) in++; /* skip whitespace */ - while (*in && !isspace(*in) && *in != ':') - *out++ = *in++; /* snarf first token */ - while (isspace(*in)) in++; /* skip whitespace */ - - if (*in == ':') - *out++ = *in++; /* copy colon */ - else - { - in = hack; - out = h2; /* reset to beginning */ - } - - *out = 0; - - while (isspace(*in)) in++; /* skip whitespace */ - for (i = strlen(h2); i < indent; i++) /* indent */ - *out++ = ' '; - - /* copy the rest of the line. */ - while (*in) - { - /* shrink all whitespace to one space, for the benefit of the "demo" - mode display. We only do this when we can easily tell that the - whitespace is not significant (no shell metachars). - */ - switch (*in) - { - case '\'': case '"': case '`': case '\\': - { - /* Metachars are scary. Copy the rest of the line unchanged. */ - while (*in) - *out++ = *in++; - } - break; - case ' ': case '\t': - { - while (*in == ' ' || *in == '\t') - in++; - *out++ = ' '; - } - break; - default: - *out++ = *in++; - break; - } - } - *out = 0; - - /* strip trailing whitespace. */ - out = out-1; - while (out > h2 && (*out == ' ' || *out == '\t' || *out == '\n')) - *out-- = 0; - - return h2; -} - - -static void -get_screenhacks (saver_info *si) -{ - saver_preferences *p = &si->prefs; - int i = 0; - int start = 0; - int end = 0; - int size; - char *d; - - d = get_string_resource ("monoPrograms", "MonoPrograms"); - if (d && !*d) { free(d); d = 0; } - if (!d) - d = get_string_resource ("colorPrograms", "ColorPrograms"); - if (d && !*d) { free(d); d = 0; } - - if (d) - { - fprintf (stderr, - "%s: the `monoPrograms' and `colorPrograms' resources are obsolete;\n\ - see the manual for details.\n", blurb()); - free(d); - } - - d = get_string_resource ("programs", "Programs"); - - if (p->screenhacks) - { - for (i = 0; i < p->screenhacks_count; i++) - if (p->screenhacks[i]) - free (p->screenhacks[i]); - free(p->screenhacks); - p->screenhacks = 0; - } - - if (!d || !*d) - { - p->screenhacks_count = 0; - p->screenhacks = 0; - return; - } - - size = strlen (d); - - - /* Count up the number of newlines (which will be equal to or larger than - the number of hacks.) - */ - i = 0; - for (i = 0; d[i]; i++) - if (d[i] == '\n') - i++; - i++; - - p->screenhacks = (char **) calloc (sizeof (char *), i+1); - - /* Iterate over the lines in `d' (the string with newlines) - and make new strings to stuff into the `screenhacks' array. - */ - p->screenhacks_count = 0; - while (start < size) - { - /* skip forward over whitespace. */ - while (d[start] == ' ' || d[start] == '\t' || d[start] == '\n') - start++; - - /* skip forward to newline or end of string. */ - end = start; - while (d[end] != 0 && d[end] != '\n') - end++; - - /* null terminate. */ - d[end] = 0; - - p->screenhacks[p->screenhacks_count++] = reformat_hack (d + start); - if (p->screenhacks_count >= i) - abort(); - - start = end+1; - } - - if (p->screenhacks_count == 0) - { - free (p->screenhacks); - p->screenhacks = 0; - } -} - - /* Processing ClientMessage events. */ @@ -1233,7 +1073,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); } @@ -1241,7 +1081,6 @@ clientmessage_response (saver_info *si, Window w, Bool error, 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; @@ -1273,7 +1112,8 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) "ACTIVATE ClientMessage received.", "activating."); si->selection_mode = 0; - if (p->use_mit_saver_extension || p->use_sgi_saver_extension) + si->demoing_p = False; + if (si->using_mit_saver_extension || si->using_sgi_saver_extension) { XForceScreenSaver (si->dpy, ScreenSaverActive); return False; @@ -1294,7 +1134,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) 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; @@ -1316,6 +1156,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) "CYCLE ClientMessage received.", "cycling."); si->selection_mode = 0; /* 0 means randomize when its time. */ + si->demoing_p = False; if (si->cycle_id) XtRemoveTimeOut (si->cycle_id); si->cycle_id = 0; @@ -1334,6 +1175,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) : "PREV ClientMessage received."), "cycling."); si->selection_mode = (type == XA_NEXT ? -1 : -2); + si->demoing_p = False; if (! until_idle_p) { @@ -1357,6 +1199,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) if (which < 0) which = 0; /* 0 == "random" */ si->selection_mode = which; + si->demoing_p = False; if (! until_idle_p) { @@ -1421,43 +1264,43 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) } else if (type == XA_DEMO) { -#ifdef NO_DEMO_MODE - clientmessage_response (si, window, True, - "not compiled with support for DEMO mode.", - "demo mode not enabled."); -#else /* !NO_DEMO_MODE */ - if (until_idle_p) + long arg = event->xclient.data.l[1]; + Bool demo_one_hack_p = (arg == 300); + + if (demo_one_hack_p) { - clientmessage_response (si, window, False, - "DEMO ClientMessage received.", - "Demo mode."); - si->demo_mode_p = True; - return True; + if (until_idle_p) + { + long which = event->xclient.data.l[2]; + char buf [255]; + char buf2 [255]; + sprintf (buf, "DEMO %ld ClientMessage received.", which); + sprintf (buf2, "demoing (%ld).", which); + clientmessage_response (si, window, False, buf, buf2); + + if (which < 0) which = 0; /* 0 == "random" */ + si->selection_mode = which; + si->demoing_p = True; + + return True; + } + + clientmessage_response (si, window, True, + "DEMO ClientMessage received while active.", + "already active."); + } + else + { + clientmessage_response (si, window, True, + "obsolete form of DEMO ClientMessage.", + "obsolete form of DEMO ClientMessage."); } - clientmessage_response (si, window, True, - "DEMO ClientMessage received while active.", - "already active."); -#endif /* !NO_DEMO_MODE */ } else if (type == XA_PREFS) { -#ifdef NO_DEMO_MODE clientmessage_response (si, window, True, - "not compiled with support for DEMO mode.", - "preferences mode not enabled."); -#else /* !NO_DEMO_MODE */ - if (until_idle_p) - { - clientmessage_response (si, window, False, - "PREFS ClientMessage received.", - "preferences mode."); - si->demo_mode_p = (Bool) 2; /* kludge, so sue me. */ - return True; - } - clientmessage_response (si, window, True, - "PREFS ClientMessage received while active.", - "already active."); -#endif /* !NO_DEMO_MODE */ + "the PREFS client-message is obsolete.", + "the PREFS client-message is obsolete."); } else if (type == XA_LOCK) { @@ -1482,6 +1325,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) : "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); @@ -1493,7 +1337,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; @@ -1531,3 +1376,119 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p) } return False; } + + +/* Some random diagnostics printed in -verbose mode. + */ + +static void +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" } + }; + + fprintf (stderr, "%s: running on display \"%s\"\n", blurb(), + DisplayString(si->dpy)); + 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][0], &op, &event, &error)) + fprintf (stderr, "%s: %s\n", blurb(), exts[i][1]); + } + + for (i = 0; i < si->nscreens; i++) + { + unsigned long colormapped_depths = 0; + unsigned long non_mapped_depths = 0; + XVisualInfo vi_in, *vi_out; + int out_count; + vi_in.screen = i; + vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count); + if (!vi_out) continue; + for (j = 0; j < out_count; j++) + if (vi_out[j].class == PseudoColor) + colormapped_depths |= (1 << vi_out[j].depth); + else + non_mapped_depths |= (1 << vi_out[j].depth); + XFree ((char *) vi_out); + + if (colormapped_depths) + { + fprintf (stderr, "%s: screen %d colormapped depths:", blurb(), i); + for (j = 0; j < 32; j++) + if (colormapped_depths & (1 << j)) + fprintf (stderr, " %d", j); + fprintf (stderr, "\n"); + } + if (non_mapped_depths) + { + fprintf (stderr, "%s: screen %d non-mapped depths:", blurb(), i); + for (j = 0; j < 32; j++) + if (non_mapped_depths & (1 << j)) + fprintf (stderr, " %d", j); + fprintf (stderr, "\n"); + } + } +} + +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; +}