http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.34.tar.gz
[xscreensaver] / driver / xscreensaver.c
index 9b26390bd6b40c092003ed5e65d192cac371fa42..08d98e4f82d3474d4f0628e451f593098528a3de 100644 (file)
@@ -1,4 +1,4 @@
-/* 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
@@ -219,7 +219,7 @@ do_help (saver_info *si)
   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\
@@ -292,16 +292,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");
@@ -315,7 +326,7 @@ saver_ehandler (Display *dpy, XErrorEvent *error)
                    "#######################################"
                    "#######################################\n\n");
           fprintf (real_stderr,
-   "    If at all possible, please re-run xscreensaver with the command\ e\n"
+   "    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"
@@ -370,15 +381,32 @@ startup_ehandler (String name, String type, String class,
   fprintf (stderr, "\n");
 
   describe_uids (si, stderr);
-  fprintf (stderr, "\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"
-          "              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",
+"              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);
@@ -462,6 +490,20 @@ connect_to_server (saver_info *si, int *argc, char **argv)
 {
   Widget toplevel_shell;
 
+#ifdef HAVE_PUTENV
+  char *d = getenv ("DISPLAY");
+  if (!d || !*d)
+    {
+      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);
@@ -593,7 +635,7 @@ print_banner (saver_info *si)
 
   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);
 
@@ -649,7 +691,7 @@ print_banner (saver_info *si)
 
 
 /* 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)
@@ -676,6 +718,9 @@ 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;
@@ -706,6 +751,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
 }
 
 
@@ -863,6 +912,14 @@ maybe_reload_init_file (saver_info *si)
       /* 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);
+
+      /* 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,
+                                 p->dpms_standby / 1000,
+                                 p->dpms_suspend / 1000,
+                                 p->dpms_off / 1000,
+                                 False);
     }
 }
 
@@ -1071,7 +1128,7 @@ main (int argc, char **argv)
   global_si_kludge = si;       /* I hate C so much... */
 
 # undef ya_rand_init
-  ya_rand_init ((int) time ((time_t *) 0));
+  ya_rand_init (0);
 
   save_argv (argc, argv);
   set_version_string (si, &argc, argv);
@@ -1109,7 +1166,14 @@ main (int argc, char **argv)
 
   select_events (si);
   init_sigchld ();
+
   disable_builtin_screensaver (si, True);
+  sync_server_dpms_settings (si->dpy, p->dpms_enabled_p,
+                             p->dpms_standby / 1000,
+                             p->dpms_suspend / 1000,
+                             p->dpms_off / 1000,
+                             False);
+
   initialize_stderr (si);
 
   make_splash_dialog (si);
@@ -1122,6 +1186,47 @@ main (int argc, char **argv)
 /* Processing ClientMessage events.
  */
 
+
+static Bool error_handler_hit_p = False;
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+  error_handler_hit_p = True;
+  return 0;
+}
+
+/* Sometimes some systems send us ClientMessage events with bogus atoms in
+   them.  We only look up the atom names for printing warning messages,
+   so don't bomb out when it happens...
+ */
+static char *
+XGetAtomName_safe (Display *dpy, Atom atom)
+{
+  char *result;
+  XErrorHandler old_handler;
+  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;
+  else
+    {
+      char buf[100];
+      sprintf (buf, "<<undefined atom 0x%04X>>", (unsigned long) atom);
+      return strdup (buf);
+    }
+}
+
+
 static void
 clientmessage_response (saver_info *si, Window w, Bool error,
                        const char *stderr_msg,
@@ -1130,6 +1235,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);
 
@@ -1139,9 +1246,23 @@ 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);
 }
 
@@ -1158,7 +1279,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
   if (event->xclient.message_type != XA_SCREENSAVER)
     {
       char *str;
-      str = XGetAtomName (si->dpy, event->xclient.message_type);
+      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);
@@ -1221,9 +1342,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)
     {
@@ -1505,7 +1627,7 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
     {
       char buf [1024];
       char *str;
-      str = (type ? XGetAtomName(si->dpy, type) : 0);
+      str = XGetAtomName_safe (si->dpy, type);
 
       if (str)
        {
@@ -1535,19 +1657,79 @@ 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" },
-    { "XFree86-VidModeExtension", "XF86 Video-Mode" },
-    { "XINERAMA",                "Xinerama" }
+  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(),
@@ -1559,8 +1741,11 @@ analyze_display (saver_info *si)
   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++)