http://svn.poeml.de/viewvc/ppc/src-unpacked/xscreensaver/xscreensaver-4.12.tar.bz2...
[xscreensaver] / driver / xscreensaver.c
index 628bcf1d442b4090899e397bed66979fbddf7de6..a70de0e4043a2eba2e497f7b36210824cd85c530 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1991-2002 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1991-2003 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
 #include <stdio.h>
 #include <ctype.h>
 #include <X11/Xlib.h>
+
+#include <X11/Xlibint.h>
+
 #include <X11/Xatom.h>
 #include <X11/Intrinsic.h>
 #include <X11/StringDefs.h>
@@ -213,6 +216,12 @@ static XrmOptionDescRec options [] = {
 #endif /* 0 */
 };
 
+#ifdef __GNUC__
+ __extension__     /* shut up about "string length is greater than the length
+                      ISO C89 compilers are required to support" when including
+                      the .ad file... */
+#endif
+
 static char *defaults[] = {
 #include "XScreenSaver_ad.h"
  0
@@ -228,13 +237,15 @@ do_help (saver_info *si)
   fflush (stdout);
   fflush (stderr);
   fprintf (stdout, "\
-xscreensaver %s, copyright (c) 1991-2002 by Jamie Zawinski <jwz@jwz.org>\n\
+xscreensaver %s, copyright (c) 1991-2003 by Jamie Zawinski <jwz@jwz.org>\n\
 \n\
   All xscreensaver configuration is via the `~/.xscreensaver' file.\n\
   Rather than editing that file by hand, just run `xscreensaver-demo':\n\
   that program lets you configure the screen saver graphically,\n\
   including timeouts, locking, and display modes.\n\
-\n\
+\n",
+         si->version);
+  fprintf (stdout, "\
   Just getting started?  Try this:\n\
 \n\
         xscreensaver &\n\
@@ -243,8 +254,8 @@ xscreensaver %s, copyright (c) 1991-2002 by Jamie Zawinski <jwz@jwz.org>\n\
   For updates, online manual, and FAQ, please see the web page:\n\
 \n\
        http://www.jwz.org/xscreensaver/\n\
-\n",
-         si->version);
+\n");
+
   fflush (stdout);
   fflush (stderr);
   exit (1);
@@ -289,6 +300,7 @@ saver_ehandler (Display *dpy, XErrorEvent *error)
 {
   saver_info *si = global_si_kludge;   /* I hate C so much... */
   int i;
+  Bool fatal_p;
 
   if (!real_stderr) real_stderr = stderr;
 
@@ -301,17 +313,27 @@ saver_ehandler (Display *dpy, XErrorEvent *error)
   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);
+             (unsigned int) RootWindowOfScreen (si->screens[i].screen),
+             (unsigned int) si->screens[i].real_vroot,
+             (unsigned int) si->screens[i].screensaver_window);
 
   fprintf (real_stderr, "\n"
           "#######################################"
           "#######################################\n\n");
 
-  if (XmuPrintDefaultErrorMessage (dpy, error, real_stderr))
+  fatal_p = XmuPrintDefaultErrorMessage (dpy, error, real_stderr);
+
+  fatal_p = True;  /* The only time I've ever seen a supposedly nonfatal error,
+                      it has been BadImplementation / Xlib sequence lost, which
+                      are in truth pretty damned fatal.
+                    */
+
+  fprintf (real_stderr, "\n");
+
+  if (! fatal_p)
+    fprintf (real_stderr, "%s: nonfatal error.\n\n", blurb());
+  else
     {
-      fprintf (real_stderr, "\n");
       if (si->prefs.xsync_p)
        {
          saver_exit (si, -1, "because of synchronous X Error");
@@ -327,7 +349,8 @@ saver_ehandler (Display *dpy, XErrorEvent *error)
    "    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"
+   "    That won't work.\n");
+          fprintf (real_stderr,
    "\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"
@@ -342,8 +365,7 @@ saver_ehandler (Display *dpy, XErrorEvent *error)
          saver_exit (si, -1, 0);
        }
     }
-  else
-    fprintf (real_stderr, " (nonfatal.)\n");
+
   return 0;
 }
 
@@ -483,9 +505,38 @@ lock_initialization (saver_info *si, int *argc, char **argv)
       si->locking_disabled_p = True;
       si->nolock_reason = "running under GDM";
     }
-#endif /* NO_LOCKING */
 
-  hack_uid (si);
+  /* If the server is XDarwin (MacOS X) then disable locking.
+     (X grabs only affect X programs, so you can use Command-Tab
+     to bring any other Mac program to the front, e.g., Terminal.)
+   */
+  if (!si->locking_disabled_p)
+    {
+      int op = 0, event = 0, error = 0;
+      Bool macos_p = False;
+
+#ifdef __APPLE__
+      /* Disable locking if *running* on Apple hardware, since we have no
+         reliable way to determine whether the server is running on MacOS.
+         Hopefully __APPLE__ means "MacOS" and not "Linux on Mac hardware"
+         but I'm not really sure about that.
+       */
+      macos_p = True;
+#endif
+
+      if (!macos_p)
+        /* This extension exists on the Apple X11 server, but not
+           on earlier versions of the XDarwin server. */
+        macos_p = XQueryExtension (si->dpy, "Apple-DRI", &op, &event, &error);
+
+      if (macos_p)
+        {
+          si->locking_disabled_p = True;
+          si->nolock_reason = "Cannot lock securely on MacOS X";
+        }
+    }
+
+#endif /* NO_LOCKING */
 }
 
 
@@ -500,13 +551,17 @@ connect_to_server (saver_info *si, int *argc, char **argv)
   char *d = getenv ("DISPLAY");
   if (!d || !*d)
     {
-      char ndpy[] = "DISPLAY=:0.0";
+      char *ndpy = strdup("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 ();
+      /* don't free (ndpy) -- some implementations of putenv (BSD 4.4,
+         glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
+         do not.  So we must leak it (and/or the previous setting). Yay.
+       */
     }
 #endif /* HAVE_PUTENV */
 
@@ -643,7 +698,7 @@ print_banner (saver_info *si)
 
   if (p->verbose_p)
     fprintf (stderr,
-            "%s %s, copyright (c) 1991-2002 "
+            "%s %s, copyright (c) 1991-2003 "
             "by Jamie Zawinski <jwz@jwz.org>.\n",
             progname, si->version);
 
@@ -676,11 +731,17 @@ print_banner (saver_info *si)
       fprintf (stderr, "%s: in process %lu.\n", blurb(),
               (unsigned long) getpid());
     }
+}
+
+static void
+print_lock_failure_banner (saver_info *si)
+{
+  saver_preferences *p = &si->prefs;
 
   /* If locking was not able to be initalized for some reason, explain why.
      (This has to be done after we've read the lock_p resource.)
    */
-  if (p->lock_p && si->locking_disabled_p)
+  if (si->locking_disabled_p)
     {
       p->lock_p = False;
       fprintf (stderr, "%s: locking is disabled (%s).\n", blurb(),
@@ -695,6 +756,7 @@ print_banner (saver_info *si)
                 "\t See the manual for details.\n",
                 blurb());
     }
+
 }
 
 
@@ -742,7 +804,7 @@ initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
                              XtNvisual, ssi->current_visual,
                              XtNdepth,  visual_depth (ssi->screen,
                                                       ssi->current_visual),
-                             0);
+                             NULL);
 
       if (! found_any_writable_cells)
        {
@@ -953,7 +1015,13 @@ main_loop (saver_info *si)
   while (1)
     {
       Bool was_locked = False;
+
+      if (p->verbose_p)
+       fprintf (stderr, "%s: awaiting idleness.\n", blurb());
+
+      check_for_leaks ("unblanked A");
       sleep_until_idle (si, True);
+      check_for_leaks ("unblanked B");
 
       if (p->verbose_p)
        {
@@ -1059,7 +1127,10 @@ main_loop (saver_info *si)
       ok_to_unblank = True;
       do {
 
+        check_for_leaks ("blanked A");
        sleep_until_idle (si, False);           /* until not idle */
+        check_for_leaks ("blanked B");
+
        maybe_reload_init_file (si);
 
 #ifndef NO_LOCKING
@@ -1181,13 +1252,11 @@ main_loop (saver_info *si)
           }
         XSync (si->dpy, False);
       }
-
-      if (p->verbose_p)
-       fprintf (stderr, "%s: awaiting idleness.\n", blurb());
     }
 }
 
 static void analyze_display (saver_info *si);
+static void fix_fds (void);
 
 int
 main (int argc, char **argv)
@@ -1201,6 +1270,8 @@ main (int argc, char **argv)
   memset(si, 0, sizeof(*si));
   global_si_kludge = si;       /* I hate C so much... */
 
+  fix_fds();
+
 # undef ya_rand_init
   ya_rand_init (0);
 
@@ -1229,6 +1300,7 @@ main (int argc, char **argv)
       exit (1);
 
   lock_initialization (si, &argc, argv);
+  print_lock_failure_banner (si);
 
   if (p->xsync_p) XSynchronize (si->dpy, True);
 
@@ -1259,6 +1331,36 @@ main (int argc, char **argv)
   return 0;
 }
 
+static void
+fix_fds (void)
+{
+  /* Bad Things Happen if stdin, stdout, and stderr have been closed
+     (as by the `sh incantation "xscreensaver >&- 2>&-").  When you do
+     that, the X connection gets allocated to one of these fds, and
+     then some random library writes to stderr, and random bits get
+     stuffed down the X pipe, causing "Xlib: sequence lost" errors.
+     So, we cause the first three file descriptors to be open to
+     /dev/null if they aren't open to something else already.  This
+     must be done before any other files are opened (or the closing
+     of that other file will again free up one of the "magic" first
+     three FDs.)
+
+     We do this by opening /dev/null three times, and then closing
+     those fds, *unless* any of them got allocated as #0, #1, or #2,
+     in which case we leave them open.  Gag.
+
+     Really, this crap is technically required of *every* X program,
+     if you want it to be robust in the face of "2>&-".
+   */
+  int fd0 = open ("/dev/null", O_RDWR);
+  int fd1 = open ("/dev/null", O_RDWR);
+  int fd2 = open ("/dev/null", O_RDWR);
+  if (fd0 > 2) close (fd0);
+  if (fd1 > 2) close (fd1);
+  if (fd2 > 2) close (fd2);
+}
+
+
 \f
 /* Processing ClientMessage events.
  */
@@ -1298,7 +1400,7 @@ XGetAtomName_safe (Display *dpy, Atom atom)
   else
     {
       char buf[100];
-      sprintf (buf, "<<undefined atom 0x%04X>>", (unsigned long) atom);
+      sprintf (buf, "<<undefined atom 0x%04X>>", (unsigned int) atom);
       return strdup (buf);
     }
 }
@@ -1842,6 +1944,8 @@ analyze_display (saver_info *si)
 #     endif
    }, { "XINERAMA",                             "Xinerama",
         True
+   }, { "Apple-DRI",                            "Apple-DRI (XDarwin)",
+        True
    },
   };
 
@@ -1954,3 +2058,20 @@ display_is_on_console_p (saver_info *si)
     }
   return !not_on_console;
 }
+
+
+/* Do a little bit of heap introspection...
+ */
+void
+check_for_leaks (const char *where)
+{
+#ifdef HAVE_SBRK
+  static unsigned long last_brk = 0;
+  int b = (unsigned long) sbrk(0);
+  if (last_brk && last_brk < b)
+    fprintf (stderr, "%s: %s: brk grew by %luK.\n",
+             blurb(), where,
+             (((b - last_brk) + 1023) / 1024));
+  last_brk = b;
+#endif /* HAVE_SBRK */
+}