Copied files from xscreensaver distribution
authorJoachim Breitner <mail@joachim-breitner.de>
Tue, 8 Dec 2009 00:02:17 +0000 (01:02 +0100)
committerJoachim Breitner <mail@joachim-breitner.de>
Tue, 8 Dec 2009 00:02:17 +0000 (01:02 +0100)
20 files changed:
hacks/fps.c [new file with mode: 0644]
hacks/fps.h [new file with mode: 0644]
hacks/fpsI.h [new file with mode: 0644]
hacks/screenhack.c [new file with mode: 0644]
hacks/screenhack.h [new file with mode: 0644]
hacks/screenhackI.h [new file with mode: 0644]
utils/colors.h [new file with mode: 0644]
utils/grabscreen.h [new file with mode: 0644]
utils/hsv.h [new file with mode: 0644]
utils/resources.c [new file with mode: 0644]
utils/resources.h [new file with mode: 0644]
utils/usleep.c [new file with mode: 0644]
utils/usleep.h [new file with mode: 0644]
utils/utils.h [new file with mode: 0644]
utils/visual.c [new file with mode: 0644]
utils/visual.h [new file with mode: 0644]
utils/vroot.h [new file with mode: 0644]
utils/xmu.h [new file with mode: 0644]
utils/yarandom.c [new file with mode: 0644]
utils/yarandom.h [new file with mode: 0644]

diff --git a/hacks/fps.c b/hacks/fps.c
new file mode 100644 (file)
index 0000000..2aa0174
--- /dev/null
@@ -0,0 +1,242 @@
+/* fps, Copyright (c) 2001-2008 Jamie Zawinski <jwz@jwz.org>
+ * Draw a frames-per-second display (Xlib and OpenGL).
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "screenhackI.h"
+#include "fpsI.h"
+
+fps_state *
+fps_init (Display *dpy, Window window)
+{
+  fps_state *st;
+  const char *font;
+  XFontStruct *f;
+  int first, last;
+
+  if (! get_boolean_resource (dpy, "doFPS", "DoFPS"))
+    return 0;
+
+  st = (fps_state *) calloc (1, sizeof(*st));
+
+  st->dpy = dpy;
+  st->window = window;
+  st->clear_p = get_boolean_resource (dpy, "fpsSolid", "FPSSolid");
+
+  font = get_string_resource (dpy, "fpsFont", "Font");
+
+  if (!font) font = "-*-courier-bold-r-normal-*-180-*";
+  f = XLoadQueryFont (dpy, font);
+  if (!f) f = XLoadQueryFont (dpy, "fixed");
+
+  first = f->min_char_or_byte2;
+  last = f->max_char_or_byte2;
+
+  {
+    XWindowAttributes xgwa;
+    XGCValues gcv;
+    XGetWindowAttributes (dpy, window, &xgwa);
+    gcv.font = f->fid;
+    gcv.foreground = 
+      get_pixel_resource (st->dpy, xgwa.colormap, "foreground", "Foreground");
+    st->draw_gc = XCreateGC (dpy, window, GCFont|GCForeground, &gcv);
+    gcv.foreground =
+      get_pixel_resource (st->dpy, xgwa.colormap, "background", "Background");
+    st->erase_gc = XCreateGC (dpy, window, GCFont|GCForeground, &gcv);
+  }
+
+  st->font = f;
+  st->x = 10;
+  st->y = 10;
+  if (get_boolean_resource (dpy, "fpsTop", "FPSTop"))
+    st->y = - (st->font->ascent + st->font->descent + 10);
+
+  strcpy (st->string, "FPS: ... ");
+
+  return st;
+}
+
+void
+fps_free (fps_state *st)
+{
+  if (st->draw_gc)  XFreeGC (st->dpy, st->draw_gc);
+  if (st->erase_gc) XFreeGC (st->dpy, st->erase_gc);
+  if (st->font) XFreeFont (st->dpy, st->font);
+  free (st);
+}
+
+
+void
+fps_slept (fps_state *st, unsigned long usecs)
+{
+  st->slept += usecs;
+}
+
+
+double
+fps_compute (fps_state *st, unsigned long polys)
+{
+  if (! st) return 0;  /* too early? */
+
+  /* Every N frames (where N is approximately one second's worth of frames)
+     check the wall clock.  We do this because checking the wall clock is
+     a slow operation.
+   */
+  if (st->frame_count++ >= st->last_ifps)
+    {
+# ifdef GETTIMEOFDAY_TWO_ARGS
+      struct timezone tzp;
+      gettimeofday(&st->this_frame_end, &tzp);
+# else
+      gettimeofday(&st->this_frame_end);
+# endif
+
+      if (st->prev_frame_end.tv_sec == 0)
+        st->prev_frame_end = st->this_frame_end;
+    }
+
+  /* If we've probed the wall-clock time, regenerate the string.
+   */
+  if (st->this_frame_end.tv_sec != st->prev_frame_end.tv_sec)
+    {
+      double uprev_frame_end = (st->prev_frame_end.tv_sec +
+                                ((double) st->prev_frame_end.tv_usec
+                                 * 0.000001));
+      double uthis_frame_end = (st->this_frame_end.tv_sec +
+                                ((double) st->this_frame_end.tv_usec
+                                 * 0.000001));
+      double fps = st->frame_count / (uthis_frame_end - uprev_frame_end);
+      double idle = (((double) st->slept * 0.000001) /
+                     (uthis_frame_end - uprev_frame_end));
+      double load = 100 * (1 - idle);
+
+      if (load < 0) load = 0;  /* well that's obviously nonsense... */
+
+      st->prev_frame_end = st->this_frame_end;
+      st->frame_count = 0;
+      st->slept       = 0;
+      st->last_ifps   = fps;
+      st->last_fps    = fps;
+
+      sprintf (st->string, (polys 
+                            ? "FPS:   %.1f \nLoad:  %.1f%% "
+                            : "FPS:  %.1f \nLoad: %.1f%% "),
+               fps, load);
+
+      if (polys > 0)
+        {
+          const char *s = "";
+# if 0
+          if      (polys >= (1024 * 1024)) polys >>= 20, s = "M";
+          else if (polys >= 2048)          polys >>= 10, s = "K";
+# endif
+
+          strcat (st->string, "\nPolys: ");
+          if (polys >= 1000000)
+            sprintf (st->string + strlen(st->string), "%lu,%03lu,%03lu%s ",
+                     (polys / 1000000), ((polys / 1000) % 1000),
+                     (polys % 1000), s);
+          else if (polys >= 1000)
+            sprintf (st->string + strlen(st->string), "%lu,%03lu%s ",
+                     (polys / 1000), (polys % 1000), s);
+          else
+            sprintf (st->string + strlen(st->string), "%lu%s ", polys, s);
+        }
+    }
+
+  return st->last_fps;
+}
+
+
+
+/* Width (and optionally height) of the string in pixels.
+ */
+static int
+string_width (XFontStruct *f, const char *c, int *height_ret)
+{
+  int x = 0;
+  int max_w = 0;
+  int h = f->ascent + f->descent;
+  while (*c)
+    {
+      int cc = *((unsigned char *) c);
+      if (*c == '\n')
+        {
+          if (x > max_w) max_w = x;
+          x = 0;
+          h += f->ascent + f->descent;
+        }
+      else
+        x += (f->per_char
+              ? f->per_char[cc-f->min_char_or_byte2].width
+              : f->min_bounds.rbearing);
+      c++;
+    }
+  if (x > max_w) max_w = x;
+  if (height_ret) *height_ret = h;
+
+  return max_w;
+}
+
+
+/* This function is used only in Xlib mode.  For GL mode, see glx/fps-glx.c.
+ */
+void
+fps_draw (fps_state *st)
+{
+  XWindowAttributes xgwa;
+  const char *string = st->string;
+  const char *s;
+  int x = st->x;
+  int y = st->y;
+  int lines = 1;
+  int lh = st->font->ascent + st->font->descent;
+
+  XGetWindowAttributes (st->dpy, st->window, &xgwa);
+
+  for (s = string; *s; s++) 
+    if (*s == '\n') lines++;
+
+  if (y < 0)
+    y = -y + (lines-1) * lh;
+  else
+    y = xgwa.height - y;
+
+  y -= lh * (lines-1) + st->font->descent;
+
+  /* clear the background */
+  if (st->clear_p)
+    {
+      int w, h;
+      w = string_width (st->font, string, &h);
+      XFillRectangle (st->dpy, st->window, st->erase_gc,
+                      x - st->font->descent,
+                      y - lh,
+                      w + 2*st->font->descent,
+                      h + 2*st->font->descent);
+    }
+
+  /* draw the text */
+  while (lines)
+    {
+      s = strchr (string, '\n');
+      if (! s) s = string + strlen(string);
+      XDrawString (st->dpy, st->window, st->draw_gc,
+                   x, y, string, s - string);
+      string = s;
+      string++;
+      lines--;
+      y += lh;
+    }
+}
diff --git a/hacks/fps.h b/hacks/fps.h
new file mode 100644 (file)
index 0000000..6f9559c
--- /dev/null
@@ -0,0 +1,28 @@
+/* fps, Copyright (c) 2001-2008 Jamie Zawinski <jwz@jwz.org>
+ * Draw a frames-per-second display (Xlib and OpenGL).
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __XSCREENSAVER_FPS_H__
+# define __XSCREENSAVER_FPS_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+typedef struct fps_state fps_state;
+
+extern fps_state *fps_init (Display *, Window);
+extern void fps_free (fps_state *);
+extern void fps_slept (fps_state *, unsigned long usecs);
+extern double fps_compute (fps_state *, unsigned long polys);
+extern void fps_draw (fps_state *);
+
+#endif /* __XSCREENSAVER_FPS_H__ */
diff --git a/hacks/fpsI.h b/hacks/fpsI.h
new file mode 100644 (file)
index 0000000..e656362
--- /dev/null
@@ -0,0 +1,36 @@
+/* fps, Copyright (c) 2001-2008 Jamie Zawinski <jwz@jwz.org>
+ * Draw a frames-per-second display (Xlib and OpenGL).
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __XSCREENSAVER_FPSI_H__
+# define __XSCREENSAVER_FPSI_H__
+
+#include "fps.h"
+
+struct fps_state {
+  Display *dpy;
+  Window window;
+  int x, y;
+  XFontStruct *font;
+  unsigned long font_dlist;  /* for glx/fps-gl.c */
+  Bool clear_p;
+  char string[1024];
+
+  GC draw_gc, erase_gc;
+
+  int last_ifps;
+  double last_fps;
+  int frame_count;
+  unsigned long slept;
+  struct timeval prev_frame_end, this_frame_end;
+};
+
+#endif /* __XSCREENSAVER_FPSI_H__ */
diff --git a/hacks/screenhack.c b/hacks/screenhack.c
new file mode 100644 (file)
index 0000000..f90289d
--- /dev/null
@@ -0,0 +1,922 @@
+/* xscreensaver, Copyright (c) 1992-2008 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ *
+ * And remember: X Windows is to graphics hacking as roman numerals are to
+ * the square root of pi.
+ */
+
+/* This file contains simple code to open a window or draw on the root.
+   The idea being that, when writing a graphics hack, you can just link
+   with this .o to get all of the uninteresting junk out of the way.
+
+   Create a few static global procedures and variables:
+
+      static void *YOURNAME_init (Display *, Window);
+
+          Return an opaque structure representing your drawing state.
+
+      static unsigned long YOURNAME_draw (Display *, Window, void *closure);
+
+          Draw one frame.
+          The `closure' arg is your drawing state, that you created in `init'.
+          Return the number of microseconds to wait until the next frame.
+
+          This should return in some small fraction of a second. 
+          Do not call `usleep' or loop excessively.  For long loops, use a
+          finite state machine.
+
+      static void YOURNAME_reshape (Display *, Window, void *closure,
+                                   unsigned int width, unsigned int height);
+
+          Called when the size of the window changes with the new size.
+
+      static Bool YOURNAME_event (Display *, Window, void *closure,
+                                 XEvent *event);
+
+          Called when a keyboard or mouse event arrives.
+          Return True if you handle it in some way, False otherwise.
+
+      static void YOURNAME_free (Display *, Window, void *closure);
+
+           Called when you are done: free everything you've allocated,
+           including your private `state' structure.  
+
+           NOTE: this is called in windowed-mode when the user typed
+           'q' or clicks on the window's close box; but when
+           xscreensaver terminates this screenhack, it does so by
+           killing the process with SIGSTOP.  So this callback is
+           mostly useless.
+
+      static char YOURNAME_defaults [] = { "...", "...", ... , 0 };
+
+           This variable is an array of strings, your default resources.
+           Null-terminate the list.
+
+      static XrmOptionDescRec YOURNAME_options[] = { { ... }, ... { 0,0,0,0 } }
+
+           This variable describes your command-line options.
+           Null-terminate the list.
+
+      Finally , invoke the XSCREENSAVER_MODULE() macro to tie it all together.
+
+   Additional caveats:
+
+      - Make sure that all functions in your module are static (check this
+        by running "nm -g" on the .o file).
+
+      - Do not use global variables: all such info must be stored in the
+        private `state' structure.
+
+      - Do not use static function-local variables, either.  Put it in `state'.
+
+        Assume that there are N independent runs of this code going in the
+        same address space at the same time: they must not affect each other.
+
+      - Don't forget to write an XML file to describe the user interface
+        of your screen saver module.  See .../hacks/config/README for details.
+ */
+
+#define DEBUG_PAIR
+
+#include <stdio.h>
+#include <X11/Intrinsic.h>
+#include <X11/IntrinsicP.h>
+#include <X11/CoreP.h>
+#include <X11/Shell.h>
+#include <X11/StringDefs.h>
+#include <X11/keysym.h>
+
+#ifdef __sgi
+# include <X11/SGIScheme.h>    /* for SgiUseSchemes() */
+#endif /* __sgi */
+
+#ifdef HAVE_XMU
+# ifndef VMS
+#  include <X11/Xmu/Error.h>
+# else /* VMS */
+#  include <Xmu/Error.h>
+# endif
+#else
+# include "xmu.h"
+#endif
+
+#include "screenhackI.h"
+#include "version.h"
+#include "vroot.h"
+#include "fps.h"
+
+#ifndef _XSCREENSAVER_VROOT_H_
+# error Error!  You have an old version of vroot.h!  Check -I args.
+#endif /* _XSCREENSAVER_VROOT_H_ */
+
+#ifndef isupper
+# define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef _tolower
+# define _tolower(c)  ((c) - 'A' + 'a')
+#endif
+
+
+/* This is defined by the SCREENHACK_MAIN() macro via screenhack.h.
+ */
+extern struct xscreensaver_function_table *xscreensaver_function_table;
+
+
+const char *progname;   /* used by hacks in error messages */
+const char *progclass;  /* used by ../utils/resources.c */
+Bool mono_p;           /* used by hacks */
+
+
+static XrmOptionDescRec default_options [] = {
+  { "-root",   ".root",                XrmoptionNoArg, "True" },
+  { "-window", ".root",                XrmoptionNoArg, "False" },
+  { "-mono",   ".mono",                XrmoptionNoArg, "True" },
+  { "-install",        ".installColormap",     XrmoptionNoArg, "True" },
+  { "-noinstall",".installColormap",   XrmoptionNoArg, "False" },
+  { "-visual", ".visualID",            XrmoptionSepArg, 0 },
+  { "-window-id", ".windowID",         XrmoptionSepArg, 0 },
+  { "-fps",    ".doFPS",               XrmoptionNoArg, "True" },
+  { "-no-fps",  ".doFPS",              XrmoptionNoArg, "False" },
+
+# ifdef DEBUG_PAIR
+  { "-pair",   ".pair",                XrmoptionNoArg, "True" },
+# endif /* DEBUG_PAIR */
+  { 0, 0, 0, 0 }
+};
+
+static char *default_defaults[] = {
+  ".root:              false",
+  "*geometry:          600x480", /* this should be .geometry, but nooooo... */
+  "*mono:              false",
+  "*installColormap:   false",
+  "*doFPS:             false",
+  "*visualID:          default",
+  "*windowID:          ",
+  "*desktopGrabber:    xscreensaver-getimage %s",
+  0
+};
+
+static XrmOptionDescRec *merged_options;
+static int merged_options_size;
+static char **merged_defaults;
+
+
+static void
+merge_options (void)
+{
+  struct xscreensaver_function_table *ft = xscreensaver_function_table;
+
+  const XrmOptionDescRec *options = ft->options;
+  const char * const *defaults    = ft->defaults;
+  const char *progclass           = ft->progclass;
+
+  int def_opts_size, opts_size;
+  int def_defaults_size, defaults_size;
+
+  for (def_opts_size = 0; default_options[def_opts_size].option;
+       def_opts_size++)
+    ;
+  for (opts_size = 0; options[opts_size].option; opts_size++)
+    ;
+
+  merged_options_size = def_opts_size + opts_size;
+  merged_options = (XrmOptionDescRec *)
+    malloc ((merged_options_size + 1) * sizeof(*default_options));
+  memcpy (merged_options, default_options,
+         (def_opts_size * sizeof(*default_options)));
+  memcpy (merged_options + def_opts_size, options,
+         ((opts_size + 1) * sizeof(*default_options)));
+
+  for (def_defaults_size = 0; default_defaults[def_defaults_size];
+       def_defaults_size++)
+    ;
+  for (defaults_size = 0; defaults[defaults_size]; defaults_size++)
+    ;
+  merged_defaults = (char **)
+    malloc ((def_defaults_size + defaults_size + 1) * sizeof (*defaults));;
+  memcpy (merged_defaults, default_defaults,
+         def_defaults_size * sizeof(*defaults));
+  memcpy (merged_defaults + def_defaults_size, defaults,
+         (defaults_size + 1) * sizeof(*defaults));
+
+  /* This totally sucks.  Xt should behave like this by default.
+     If the string in `defaults' looks like ".foo", change that
+     to "Progclass.foo".
+   */
+  {
+    char **s;
+    for (s = merged_defaults; *s; s++)
+      if (**s == '.')
+       {
+         const char *oldr = *s;
+         char *newr = (char *) malloc(strlen(oldr) + strlen(progclass) + 3);
+         strcpy (newr, progclass);
+         strcat (newr, oldr);
+         *s = newr;
+       }
+  }
+}
+
+\f
+/* Make the X errors print out the name of this program, so we have some
+   clue which one has a bug when they die under the screensaver.
+ */
+
+static int
+screenhack_ehandler (Display *dpy, XErrorEvent *error)
+{
+  fprintf (stderr, "\nX error in %s:\n", progname);
+  if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
+    exit (-1);
+  else
+    fprintf (stderr, " (nonfatal.)\n");
+  return 0;
+}
+
+static Bool
+MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
+{
+  return (event->xany.type == MapNotify &&
+         event->xvisibility.window == (Window) window);
+}
+
+
+static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW;
+
+/* Dead-trivial event handling: exits if "q" or "ESC" are typed.
+   Exit if the WM_PROTOCOLS WM_DELETE_WINDOW ClientMessage is received.
+   Returns False if the screen saver should now terminate.
+ */
+static Bool
+screenhack_handle_event_1 (Display *dpy, XEvent *event)
+{
+  switch (event->xany.type)
+    {
+    case KeyPress:
+      {
+        KeySym keysym;
+        char c = 0;
+        XLookupString (&event->xkey, &c, 1, &keysym, 0);
+        if (c == 'q' ||
+            c == 'Q' ||
+            c == 3 ||  /* ^C */
+            c == 27)   /* ESC */
+          return False;  /* exit */
+        else if (! (keysym >= XK_Shift_L && keysym <= XK_Hyper_R))
+          XBell (dpy, 0);  /* beep for non-chord keys */
+      }
+      break;
+    case ButtonPress:
+      XBell (dpy, 0);
+      break;
+    case ClientMessage:
+      {
+        if (event->xclient.message_type != XA_WM_PROTOCOLS)
+          {
+            char *s = XGetAtomName(dpy, event->xclient.message_type);
+            if (!s) s = "(null)";
+            fprintf (stderr, "%s: unknown ClientMessage %s received!\n",
+                     progname, s);
+          }
+        else if (event->xclient.data.l[0] != XA_WM_DELETE_WINDOW)
+          {
+            char *s1 = XGetAtomName(dpy, event->xclient.message_type);
+            char *s2 = XGetAtomName(dpy, event->xclient.data.l[0]);
+            if (!s1) s1 = "(null)";
+            if (!s2) s2 = "(null)";
+            fprintf (stderr, "%s: unknown ClientMessage %s[%s] received!\n",
+                     progname, s1, s2);
+          }
+        else
+          {
+            return False;  /* exit */
+          }
+      }
+      break;
+    }
+  return True;
+}
+
+
+static Visual *
+pick_visual (Screen *screen)
+{
+  struct xscreensaver_function_table *ft = xscreensaver_function_table;
+
+  if (ft->pick_visual_hook)
+    {
+      Visual *v = ft->pick_visual_hook (screen);
+      if (v) return v;
+    }
+
+  return get_visual_resource (screen, "visualID", "VisualID", False);
+}
+
+
+/* Notice when the user has requested a different visual or colormap
+   on a pre-existing window (e.g., "-root -visual truecolor" or
+   "-window-id 0x2c00001 -install") and complain, since when drawing
+   on an existing window, we have no choice about these things.
+ */
+static void
+visual_warning (Screen *screen, Window window, Visual *visual, Colormap cmap,
+                Bool window_p)
+{
+  struct xscreensaver_function_table *ft = xscreensaver_function_table;
+
+  char *visual_string = get_string_resource (DisplayOfScreen (screen),
+                                             "visualID", "VisualID");
+  Visual *desired_visual = pick_visual (screen);
+  char win[100];
+  char why[100];
+
+  if (window == RootWindowOfScreen (screen))
+    strcpy (win, "root window");
+  else
+    sprintf (win, "window 0x%lx", (unsigned long) window);
+
+  if (window_p)
+    sprintf (why, "-window-id 0x%lx", (unsigned long) window);
+  else
+    strcpy (why, "-root");
+
+  if (visual_string && *visual_string)
+    {
+      char *s;
+      for (s = visual_string; *s; s++)
+        if (isupper (*s)) *s = _tolower (*s);
+
+      if (!strcmp (visual_string, "default") ||
+          !strcmp (visual_string, "default") ||
+          !strcmp (visual_string, "best"))
+        /* don't warn about these, just silently DWIM. */
+        ;
+      else if (visual != desired_visual)
+        {
+          fprintf (stderr, "%s: ignoring `-visual %s' because of `%s'.\n",
+                   progname, visual_string, why);
+          fprintf (stderr, "%s: using %s's visual 0x%lx.\n",
+                   progname, win, XVisualIDFromVisual (visual));
+        }
+      free (visual_string);
+    }
+
+  if (visual == DefaultVisualOfScreen (screen) &&
+      has_writable_cells (screen, visual) &&
+      get_boolean_resource (DisplayOfScreen (screen),
+                            "installColormap", "InstallColormap"))
+    {
+      fprintf (stderr, "%s: ignoring `-install' because of `%s'.\n",
+               progname, why);
+      fprintf (stderr, "%s: using %s's colormap 0x%lx.\n",
+               progname, win, (unsigned long) cmap);
+    }
+
+  if (ft->validate_visual_hook)
+    {
+      if (! ft->validate_visual_hook (screen, win, visual))
+        exit (1);
+    }
+}
+
+
+static void
+fix_fds (void)
+{
+  /* Bad Things Happen if stdin, stdout, and stderr have been closed
+     (as by the `sh incantation "attraction >&- 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);
+}
+
+
+static Boolean
+screenhack_table_handle_events (Display *dpy,
+                                const struct xscreensaver_function_table *ft,
+                                Window window, void *closure
+#ifdef DEBUG_PAIR
+                                , Window window2, void *closure2
+#endif
+                                )
+{
+  XtAppContext app = XtDisplayToApplicationContext (dpy);
+
+  if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
+    XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
+
+  while (XPending (dpy))
+    {
+      XEvent event;
+      XNextEvent (dpy, &event);
+
+      if (event.xany.type == ConfigureNotify)
+        {
+          if (event.xany.window == window)
+            ft->reshape_cb (dpy, window, closure,
+                            event.xconfigure.width, event.xconfigure.height);
+#ifdef DEBUG_PAIR
+          if (event.xany.window == window2)
+            ft->reshape_cb (dpy, window2, closure2,
+                            event.xconfigure.width, event.xconfigure.height);
+#endif
+        }
+      else if (event.xany.type == ClientMessage ||
+               (! (event.xany.window == window
+                   ? ft->event_cb (dpy, window, closure, &event)
+#ifdef DEBUG_PAIR
+                   : event.xany.window == window2
+                   ? ft->event_cb (dpy, window2, closure2, &event)
+#endif
+                   : 0)))
+        if (! screenhack_handle_event_1 (dpy, &event))
+          return False;
+
+      if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
+        XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
+    }
+  return True;
+}
+
+
+static Boolean
+usleep_and_process_events (Display *dpy,
+                           const struct xscreensaver_function_table *ft,
+                           Window window, fps_state *fpst, void *closure,
+                           unsigned long delay
+#ifdef DEBUG_PAIR
+                         , Window window2, fps_state *fpst2, void *closure2,
+                           unsigned long delay2
+#endif
+                           )
+{
+  do {
+    unsigned long quantum = 100000;  /* 1/10th second */
+    if (quantum > delay) 
+      quantum = delay;
+    delay -= quantum;
+
+    XSync (dpy, False);
+    if (quantum > 0)
+      {
+        usleep (quantum);
+        if (fpst) fps_slept (fpst, quantum);
+#ifdef DEBUG_PAIR
+        if (fpst2) fps_slept (fpst2, quantum);
+#endif
+      }
+
+    if (! screenhack_table_handle_events (dpy, ft, window, closure
+#ifdef DEBUG_PAIR
+                                          , window2, closure2
+#endif
+                                          ))
+      return False;
+  } while (delay > 0);
+
+  return True;
+}
+
+
+static void
+screenhack_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure)
+{
+  fps_compute (fpst, 0);
+  fps_draw (fpst);
+}
+
+
+static void
+run_screenhack_table (Display *dpy, 
+                      Window window,
+# ifdef DEBUG_PAIR
+                      Window window2,
+# endif
+                      const struct xscreensaver_function_table *ft)
+{
+
+  /* Kludge: even though the init_cb functions are declared to take 2 args,
+     actually call them with 3, for the benefit of xlockmore_init() and
+     xlockmore_setup().
+   */
+  void *(*init_cb) (Display *, Window, void *) = 
+    (void *(*) (Display *, Window, void *)) ft->init_cb;
+
+  void (*fps_cb) (Display *, Window, fps_state *, void *) = ft->fps_cb;
+
+  void *closure = init_cb (dpy, window, ft->setup_arg);
+  fps_state *fpst = fps_init (dpy, window);
+
+#ifdef DEBUG_PAIR
+  void *closure2 = 0;
+  fps_state *fpst2 = 0;
+  if (window2) closure2 = init_cb (dpy, window2, ft->setup_arg);
+  if (window2) fpst2 = fps_init (dpy, window2);
+#endif
+
+  if (! closure)  /* if it returns nothing, it can't possibly be re-entrant. */
+    abort();
+
+  if (! fps_cb) fps_cb = screenhack_do_fps;
+
+  while (1)
+    {
+      unsigned long delay = ft->draw_cb (dpy, window, closure);
+#ifdef DEBUG_PAIR
+      unsigned long delay2 = 0;
+      if (window2) delay2 = ft->draw_cb (dpy, window2, closure2);
+#endif
+
+      if (fpst) fps_cb (dpy, window, fpst, closure);
+#ifdef DEBUG_PAIR
+      if (fpst2) fps_cb (dpy, window, fpst2, closure);
+#endif
+
+      if (! usleep_and_process_events (dpy, ft,
+                                       window, fpst, closure, delay
+#ifdef DEBUG_PAIR
+                                       , window2, fpst2, closure2, delay2
+#endif
+                                       ))
+        break;
+    }
+
+  ft->free_cb (dpy, window, closure);
+  if (fpst) fps_free (fpst);
+
+#ifdef DEBUG_PAIR
+  if (window2) ft->free_cb (dpy, window2, closure2);
+  if (window2) fps_free (fpst2);
+#endif
+}
+
+
+static Widget
+make_shell (Screen *screen, Widget toplevel, int width, int height)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  Visual *visual = pick_visual (screen);
+  Boolean def_visual_p = (toplevel && 
+                          visual == DefaultVisualOfScreen (screen));
+
+  if (width  <= 0) width  = 600;
+  if (height <= 0) height = 480;
+
+  if (def_visual_p)
+    {
+      Window window;
+      XtVaSetValues (toplevel,
+                     XtNmappedWhenManaged, False,
+                     XtNwidth, width,
+                     XtNheight, height,
+                     XtNinput, True,  /* for WM_HINTS */
+                     NULL);
+      XtRealizeWidget (toplevel);
+      window = XtWindow (toplevel);
+
+      if (get_boolean_resource (dpy, "installColormap", "InstallColormap"))
+        {
+          Colormap cmap = 
+            XCreateColormap (dpy, window, DefaultVisualOfScreen (screen),
+                             AllocNone);
+          XSetWindowColormap (dpy, window, cmap);
+        }
+    }
+  else
+    {
+      unsigned int bg, bd;
+      Widget new;
+      Colormap cmap = XCreateColormap (dpy, VirtualRootWindowOfScreen(screen),
+                                       visual, AllocNone);
+      bg = get_pixel_resource (dpy, cmap, "background", "Background");
+      bd = get_pixel_resource (dpy, cmap, "borderColor", "Foreground");
+
+      new = XtVaAppCreateShell (progname, progclass,
+                                topLevelShellWidgetClass, dpy,
+                                XtNmappedWhenManaged, False,
+                                XtNvisual, visual,
+                                XtNdepth, visual_depth (screen, visual),
+                                XtNwidth, width,
+                                XtNheight, height,
+                                XtNcolormap, cmap,
+                                XtNbackground, (Pixel) bg,
+                                XtNborderColor, (Pixel) bd,
+                                XtNinput, True,  /* for WM_HINTS */
+                                NULL);
+
+      if (!toplevel)  /* kludge for the second window in -pair mode... */
+        XtVaSetValues (new, XtNx, 0, XtNy, 550, NULL);
+
+      XtRealizeWidget (new);
+      toplevel = new;
+    }
+
+  return toplevel;
+}
+
+static void
+init_window (Display *dpy, Widget toplevel, const char *title)
+{
+  Window window;
+  XWindowAttributes xgwa;
+  XtPopup (toplevel, XtGrabNone);
+  XtVaSetValues (toplevel, XtNtitle, title, NULL);
+
+  /* Select KeyPress, and announce that we accept WM_DELETE_WINDOW.
+   */
+  window = XtWindow (toplevel);
+  XGetWindowAttributes (dpy, window, &xgwa);
+  XSelectInput (dpy, window,
+                (xgwa.your_event_mask | KeyPressMask | KeyReleaseMask |
+                 ButtonPressMask | ButtonReleaseMask));
+  XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32,
+                   PropModeReplace,
+                   (unsigned char *) &XA_WM_DELETE_WINDOW, 1);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  struct xscreensaver_function_table *ft = xscreensaver_function_table;
+
+  XWindowAttributes xgwa;
+  Widget toplevel;
+  Display *dpy;
+  Window window;
+# ifdef DEBUG_PAIR
+  Window window2 = 0;
+  Widget toplevel2 = 0;
+# endif
+  XtAppContext app;
+  Bool root_p;
+  Window on_window = 0;
+  XEvent event;
+  Boolean dont_clear;
+  char version[255];
+
+  fix_fds();
+
+  progname = argv[0];   /* reset later */
+  progclass = ft->progclass;
+
+  if (ft->setup_cb)
+    ft->setup_cb (ft, ft->setup_arg);
+
+  merge_options ();
+
+#ifdef __sgi
+  /* We have to do this on SGI to prevent the background color from being
+     overridden by the current desktop color scheme (we'd like our backgrounds
+     to be black, thanks.)  This should be the same as setting the
+     "*useSchemes: none" resource, but it's not -- if that resource is
+     present in the `default_defaults' above, it doesn't work, though it
+     does work when passed as an -xrm arg on the command line.  So screw it,
+     turn them off from C instead.
+   */
+  SgiUseSchemes ("none"); 
+#endif /* __sgi */
+
+  toplevel = XtAppInitialize (&app, progclass, merged_options,
+                             merged_options_size, &argc, argv,
+                             merged_defaults, 0, 0);
+
+  dpy = XtDisplay (toplevel);
+
+  XtGetApplicationNameAndClass (dpy,
+                                (char **) &progname,
+                                (char **) &progclass);
+
+  /* half-assed way of avoiding buffer-overrun attacks. */
+  if (strlen (progname) >= 100) ((char *) progname)[100] = 0;
+
+  XSetErrorHandler (screenhack_ehandler);
+
+  XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
+  XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
+
+  {
+    char *v = (char *) strdup(strchr(screensaver_id, ' '));
+    char *s1, *s2, *s3, *s4;
+    s1 = (char *) strchr(v,  ' '); s1++;
+    s2 = (char *) strchr(s1, ' ');
+    s3 = (char *) strchr(v,  '('); s3++;
+    s4 = (char *) strchr(s3, ')');
+    *s2 = 0;
+    *s4 = 0;
+    sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)",
+            progclass, s1, s3);
+    free(v);
+  }
+
+  if (argc > 1)
+    {
+      const char *s;
+      int i;
+      int x = 18;
+      int end = 78;
+      Bool help_p = (!strcmp(argv[1], "-help") ||
+                     !strcmp(argv[1], "--help"));
+      fprintf (stderr, "%s\n", version);
+      for (s = progclass; *s; s++) fprintf(stderr, " ");
+      fprintf (stderr, "  http://www.jwz.org/xscreensaver/\n\n");
+
+      if (!help_p)
+       fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
+      fprintf (stderr, "Options include: ");
+      for (i = 0; i < merged_options_size; i++)
+       {
+         char *sw = merged_options [i].option;
+         Bool argp = (merged_options [i].argKind == XrmoptionSepArg);
+         int size = strlen (sw) + (argp ? 6 : 0) + 2;
+         if (x + size >= end)
+           {
+             fprintf (stderr, "\n\t\t ");
+             x = 18;
+           }
+         x += size;
+         fprintf (stderr, "%s", sw);
+         if (argp) fprintf (stderr, " <arg>");
+         if (i != merged_options_size - 1) fprintf (stderr, ", ");
+       }
+
+      fprintf (stderr, ".\n");
+
+#if 0
+      if (help_p)
+        {
+          fprintf (stderr, "\nResources:\n\n");
+          for (i = 0; i < merged_options_size; i++)
+            {
+              const char *opt = merged_options [i].option;
+              const char *res = merged_options [i].specifier + 1;
+              const char *val = merged_options [i].value;
+              char *s = get_string_resource (dpy, (char *) res, (char *) res);
+
+              if (s)
+                {
+                  int L = strlen(s);
+                while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
+                  s[--L] = 0;
+                }
+
+              fprintf (stderr, "    %-16s %-18s ", opt, res);
+              if (merged_options [i].argKind == XrmoptionSepArg)
+                {
+                  fprintf (stderr, "[%s]", (s ? s : "?"));
+                }
+              else
+                {
+                  fprintf (stderr, "%s", (val ? val : "(null)"));
+                  if (val && s && !strcasecmp (val, s))
+                    fprintf (stderr, " [default]");
+                }
+              fprintf (stderr, "\n");
+            }
+          fprintf (stderr, "\n");
+        }
+#endif
+
+      exit (help_p ? 0 : 1);
+    }
+
+  free (merged_options);
+  free (merged_defaults);
+  merged_options = 0;
+  merged_defaults = 0;
+
+  dont_clear = get_boolean_resource (dpy, "dontClearRoot", "Boolean");
+  mono_p = get_boolean_resource (dpy, "mono", "Boolean");
+  if (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
+    mono_p = True;
+
+  root_p = get_boolean_resource (dpy, "root", "Boolean");
+
+  {
+    char *s = get_string_resource (dpy, "windowID", "WindowID");
+    if (s && *s)
+      on_window = get_integer_resource (dpy, "windowID", "WindowID");
+    if (s) free (s);
+  }
+
+  if (on_window)
+    {
+      window = (Window) on_window;
+      XtDestroyWidget (toplevel);
+      XGetWindowAttributes (dpy, window, &xgwa);
+      visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, True);
+
+      /* Select KeyPress and resize events on the external window.
+       */
+      xgwa.your_event_mask |= KeyPressMask | StructureNotifyMask;
+      XSelectInput (dpy, window, xgwa.your_event_mask);
+
+      /* Select ButtonPress and ButtonRelease events on the external window,
+         if no other app has already selected them (only one app can select
+         ButtonPress at a time: BadAccess results.)
+       */
+      if (! (xgwa.all_event_masks & (ButtonPressMask | ButtonReleaseMask)))
+        XSelectInput (dpy, window,
+                      (xgwa.your_event_mask |
+                       ButtonPressMask | ButtonReleaseMask));
+    }
+  else if (root_p)
+    {
+      window = VirtualRootWindowOfScreen (XtScreen (toplevel));
+      XtDestroyWidget (toplevel);
+      XGetWindowAttributes (dpy, window, &xgwa);
+      /* With RANDR, the root window can resize! */
+      XSelectInput (dpy, window, xgwa.your_event_mask | StructureNotifyMask);
+      visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, False);
+    }
+  else
+    {
+      Widget new = make_shell (XtScreen (toplevel), toplevel,
+                               toplevel->core.width,
+                               toplevel->core.height);
+      if (new != toplevel)
+        {
+          XtDestroyWidget (toplevel);
+          toplevel = new;
+        }
+
+      init_window (dpy, toplevel, version);
+      window = XtWindow (toplevel);
+      XGetWindowAttributes (dpy, window, &xgwa);
+
+# ifdef DEBUG_PAIR
+      if (get_boolean_resource (dpy, "pair", "Boolean"))
+        {
+          toplevel2 = make_shell (xgwa.screen, 0,
+                                  toplevel->core.width,
+                                  toplevel->core.height);
+          init_window (dpy, toplevel2, version);
+          window2 = XtWindow (toplevel2);
+        }
+# endif /* DEBUG_PAIR */
+    }
+
+  if (!dont_clear)
+    {
+      unsigned int bg = get_pixel_resource (dpy, xgwa.colormap,
+                                            "background", "Background");
+      XSetWindowBackground (dpy, window, bg);
+      XClearWindow (dpy, window);
+# ifdef DEBUG_PAIR
+      if (window2)
+        {
+          XSetWindowBackground (dpy, window2, bg);
+          XClearWindow (dpy, window2);
+        }
+# endif
+    }
+
+  if (!root_p && !on_window)
+    /* wait for it to be mapped */
+    XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
+
+  XSync (dpy, False);
+
+  /* This is the one and only place that the random-number generator is
+     seeded in any screenhack.  You do not need to seed the RNG again,
+     it is done for you before your code is invoked. */
+# undef ya_rand_init
+  ya_rand_init (0);
+
+  run_screenhack_table (dpy, window, 
+# ifdef DEBUG_PAIR
+                        window2,
+# endif
+                        ft);
+
+  XtDestroyWidget (toplevel);
+  XtDestroyApplicationContext (app);
+
+  return 0;
+}
diff --git a/hacks/screenhack.h b/hacks/screenhack.h
new file mode 100644 (file)
index 0000000..1f9a561
--- /dev/null
@@ -0,0 +1,61 @@
+/* xscreensaver, Copyright (c) 1992-2008 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __SCREENHACK_H__
+#define __SCREENHACK_H__
+
+#include "screenhackI.h"
+
+/* In an Xlib world, we define two global symbols here:
+   a struct in `MODULENAME_xscreensaver_function_table',
+   and a pointer to that in `xscreensaver_function_table'.
+
+   In a Cocoa world, we only define the prefixed symbol;
+   the un-prefixed symbol does not exist.
+ */
+#ifdef HAVE_COCOA
+# define XSCREENSAVER_LINK(NAME)
+#else
+# define XSCREENSAVER_LINK(NAME) \
+   struct xscreensaver_function_table *xscreensaver_function_table = &NAME;
+#endif
+
+
+#if defined(HAVE_COCOA) && !defined(__XLOCKMORE_INTERNAL_H__)
+  /* this is one enormous kludge... */
+# undef ya_rand_init
+  static void
+  xscreensaver_common_setup(struct xscreensaver_function_table *xsft, void *a)
+  { ya_rand_init(0); }
+#else
+# define xscreensaver_common_setup 0
+#endif
+
+
+#define XSCREENSAVER_MODULE_2(CLASS,NAME,PREFIX)               \
+  struct xscreensaver_function_table                           \
+        NAME ## _xscreensaver_function_table = {               \
+          CLASS,                                               \
+          PREFIX ## _defaults,                                 \
+          PREFIX ## _options,                                  \
+          xscreensaver_common_setup, 0,                        \
+          PREFIX ## _init,                                     \
+          PREFIX ## _draw,                                     \
+          PREFIX ## _reshape,                                  \
+          PREFIX ## _event,                                    \
+          PREFIX ## _free,                                     \
+           0, 0, 0 };                                          \
+  XSCREENSAVER_LINK (NAME ## _xscreensaver_function_table)
+
+#define XSCREENSAVER_MODULE(CLASS,PREFIX)                      \
+      XSCREENSAVER_MODULE_2(CLASS,PREFIX,PREFIX)
+
+#endif /* __SCREENHACK_H__ */
diff --git a/hacks/screenhackI.h b/hacks/screenhackI.h
new file mode 100644 (file)
index 0000000..f25e7ab
--- /dev/null
@@ -0,0 +1,138 @@
+/* xscreensaver, Copyright (c) 1992-2008 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+/* Found in Don Hopkins' .plan file:
+ *
+ *   The color situation is a total flying circus.  The X approach to
+ *   device independence is to treat everything like a MicroVax framebuffer
+ *   on acid.  A truely portable X application is required to act like the
+ *   persistent customer in the Monty Python ``Cheese Shop'' sketch.  Even
+ *   the simplest applications must answer many difficult questions, like:
+ *
+ *   WHAT IS YOUR DISPLAY?
+ *       display = XOpenDisplay("unix:0");
+ *   WHAT IS YOUR ROOT?
+ *       root = RootWindow(display, DefaultScreen(display));
+ *   AND WHAT IS YOUR WINDOW?
+ *       win = XCreateSimpleWindow(display, root, 0, 0, 256, 256, 1,
+ *                                 BlackPixel(display, DefaultScreen(display)),
+ *                                 WhitePixel(display, DefaultScreen(display)))
+ *   OH ALL RIGHT, YOU CAN GO ON.
+ *
+ *   WHAT IS YOUR DISPLAY?
+ *         display = XOpenDisplay("unix:0");
+ *   WHAT IS YOUR COLORMAP?
+ *         cmap = DefaultColormap(display, DefaultScreen(display));
+ *   AND WHAT IS YOUR FAVORITE COLOR?
+ *         favorite_color = 0; / * Black. * /
+ *         / * Whoops! No, I mean: * /
+ *         favorite_color = BlackPixel(display, DefaultScreen(display));
+ *         / * AAAYYYYEEEEE!! (client dumps core & falls into the chasm) * /
+ *
+ *   WHAT IS YOUR DISPLAY?
+ *         display = XOpenDisplay("unix:0");
+ *   WHAT IS YOUR VISUAL?
+ *         struct XVisualInfo vinfo;
+ *         if (XMatchVisualInfo(display, DefaultScreen(display),
+ *                              8, PseudoColor, &vinfo) != 0)
+ *            visual = vinfo.visual;
+ *   AND WHAT IS THE NET SPEED VELOCITY OF AN XConfigureWindow REQUEST?
+ *         / * Is that a SubStructureRedirectMask or a ResizeRedirectMask? * /
+ *   WHAT?! HOW AM I SUPPOSED TO KNOW THAT?
+ *   AAAAUUUGGGHHH!!!! (server dumps core & falls into the chasm)
+ */
+
+#ifndef __SCREENHACK_I_H__
+#define __SCREENHACK_I_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef __hpux
+ /* Which of the ten billion standards does values.h belong to?
+    What systems always have it? */
+# include <values.h>
+#endif
+
+#ifdef HAVE_COCOA
+# include "jwxyz.h"
+#else  /* !HAVE_COCOA -- real X11 */
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/Xresource.h>
+# include <X11/Xos.h>
+#endif /* !HAVE_COCOA */
+
+/* M_PI ought to have been defined in math.h, but... */
+#ifndef M_PI
+# define M_PI 3.1415926535
+#endif
+
+#ifndef M_PI_2
+# define M_PI_2 1.5707963267
+#endif
+
+#ifndef Button6
+# define Button6 6
+# define Button7 7
+#endif
+
+#include "yarandom.h"
+#include "usleep.h"
+#include "resources.h"
+#include "hsv.h"
+#include "colors.h"
+#include "grabscreen.h"
+#include "visual.h"
+#include "fps.h"
+
+/* Be Posixly correct */
+#undef  bzero
+#define bzero  __ERROR_use_memset_not_bzero_in_xscreensaver__
+#undef  bcopy
+#define bcopy  __ERROR_use_memcpy_not_bcopy_in_xscreensaver__
+#undef  ftime
+#define ftime  __ERROR_use_gettimeofday_not_ftime_in_xscreensaver__
+#undef  sleep
+#define sleep  __ERROR_do_not_sleep_in_xscreensaver__
+
+extern Bool mono_p;
+
+struct xscreensaver_function_table {
+
+  const char *progclass;
+  const char * const *defaults;
+  const XrmOptionDescRec *options;
+
+  void           (*setup_cb)   (struct xscreensaver_function_table *, void *);
+  void *         setup_arg;
+
+  void *         (*init_cb)    (Display *, Window);
+  unsigned long  (*draw_cb)    (Display *, Window, void *);
+  void           (*reshape_cb) (Display *, Window, void *,
+                                unsigned int w, unsigned int h);
+  Bool           (*event_cb)   (Display *, Window, void *, XEvent *);
+  void           (*free_cb)    (Display *, Window, void *);
+  void           (*fps_cb)     (Display *, Window, fps_state *, void *);
+
+  Visual *       (*pick_visual_hook) (Screen *);
+  Bool           (*validate_visual_hook) (Screen *, const char *, Visual *);
+
+};
+
+extern const char *progname;
+
+#endif /* __SCREENHACK_I_H__ */
diff --git a/utils/colors.h b/utils/colors.h
new file mode 100644 (file)
index 0000000..61421cf
--- /dev/null
@@ -0,0 +1,140 @@
+/* xscreensaver, Copyright (c) 1992, 1997 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __COLORS_H__
+#define __COLORS_H__
+
+/* Like XFreeColors, but works on `XColor *' instead of `unsigned long *'
+ */
+extern void free_colors (Display *, Colormap, XColor *, int ncolors);
+
+
+/* Allocates writable, non-contiguous color cells.  The number requested is
+   passed in *ncolorsP, and the number actually allocated is returned there.
+   (Unlike XAllocColorCells(), this will allocate as many as it can, instead
+   of failing if they can't all be allocated.)
+ */
+extern void allocate_writable_colors (Display *dpy, Colormap cmap,
+                                     unsigned long *pixels, int *ncolorsP);
+
+
+/* Generates a sequence of colors evenly spaced between the given pair
+   of HSV coordinates.
+
+   If closed_p is true, the colors will go from the first point to the
+   second then back to the first.
+
+   If allocate_p is true, the colors will be allocated from the map;
+   if enough colors can't be allocated, we will try for less, and the
+   result will be returned to ncolorsP.
+
+   If writable_p is true, writable color cells will be allocated;
+   otherwise, read-only cells will be allocated.
+ */
+extern void make_color_ramp (Display *dpy, Colormap cmap,
+                            int h1, double s1, double v1,
+                            int h2, double s2, double v2,
+                            XColor *colors, int *ncolorsP,
+                            Bool closed_p,
+                            Bool allocate_p,
+                            Bool writable_p);
+
+/* Generates a sequence of colors evenly spaced around the triangle
+   indicated by the thee HSV coordinates.
+
+   If allocate_p is true, the colors will be allocated from the map;
+   if enough colors can't be allocated, we will try for less, and the
+   result will be returned to ncolorsP.
+
+   If writable_p is true, writable color cells will be allocated;
+   otherwise, read-only cells will be allocated.
+ */
+extern void make_color_loop (Display *, Colormap,
+                            int h1, double s1, double v1,
+                            int h2, double s2, double v2,
+                            int h3, double s3, double v3,
+                            XColor *colors, int *ncolorsP,
+                            Bool allocate_p,
+                            Bool writable_p);
+
+
+/* Allocates a hopefully-interesting colormap, which will be a closed loop
+   without any sudden transitions.
+
+   If allocate_p is true, the colors will be allocated from the map;
+   if enough colors can't be allocated, we will try for less, and the
+   result will be returned to ncolorsP.  An error message will be
+   printed on stderr (if verbose_p).
+
+   If *writable_pP is true, writable color cells will be allocated;
+   otherwise, read-only cells will be allocated.  If no writable cells
+   cannot be allocated, we will try to allocate unwritable cells
+   instead, and print a message on stderr to that effect (if verbose_p).
+ */
+extern void make_smooth_colormap (Display *dpy, Visual *visual,
+                                 Colormap cmap,
+                                 XColor *colors, int *ncolorsP,
+                                 Bool allocate_p,
+                                 Bool *writable_pP,
+                                 Bool verbose_p);
+
+/* Allocates a uniform colormap which touches each hue of the spectrum,
+   evenly spaced.  The saturation and intensity are chosen randomly, but
+   will be high enough to be visible.
+
+   If allocate_p is true, the colors will be allocated from the map;
+   if enough colors can't be allocated, we will try for less, and the
+   result will be returned to ncolorsP.  An error message will be
+   printed on stderr (if verbose_p).
+
+   If *writable_pP is true, writable color cells will be allocated;
+   otherwise, read-only cells will be allocated.  If no writable cells
+   cannot be allocated, we will try to allocate unwritable cells
+   instead, and print a message on stderr to that effect (if verbose_p).
+ */
+extern void make_uniform_colormap (Display *dpy, Visual *visual,
+                                  Colormap cmap,
+                                  XColor *colors, int *ncolorsP,
+                                  Bool allocate_p,
+                                  Bool *writable_pP,
+                                  Bool verbose_p);
+
+/* Allocates a random colormap (the colors are unrelated to one another.)
+   If `bright_p' is false, the colors will be completely random; if it is
+   true, all of the colors will be bright enough to see on a black background.
+
+   If allocate_p is true, the colors will be allocated from the map;
+   if enough colors can't be allocated, we will try for less, and the
+   result will be returned to ncolorsP.  An error message will be
+   printed on stderr (if verbose_p).
+
+   If *writable_pP is true, writable color cells will be allocated;
+   otherwise, read-only cells will be allocated.  If no writable cells
+   cannot be allocated, we will try to allocate unwritable cells
+   instead, and print a message on stderr to that effect (if verbose_p).
+ */
+extern void make_random_colormap (Display *dpy, Visual *visual,
+                                 Colormap cmap,
+                                 XColor *colors, int *ncolorsP,
+                                 Bool bright_p,
+                                 Bool allocate_p,
+                                 Bool *writable_pP,
+                                 Bool verbose_p);
+
+
+/* Assuming that the array of colors indicates the current state of a set
+   of writable color cells, this rotates the contents of the array by
+   `distance' steps, moving the colors of cell N to cell (N - distance).
+ */
+extern void rotate_colors (Display *, Colormap,
+                          XColor *, int ncolors, int distance);
+
+#endif /* __COLORS_H__ */
diff --git a/utils/grabscreen.h b/utils/grabscreen.h
new file mode 100644 (file)
index 0000000..2f680e0
--- /dev/null
@@ -0,0 +1,94 @@
+/* xscreensaver, Copyright (c) 1992-2006 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __GRABSCREEN_H__
+#define __GRABSCREEN_H__
+
+/* This will write an image onto the given Drawable.
+   The Drawable (arg 3) may be a Window or a Pixmap.
+
+   The Window must be the top-level window.  The image *may or may not*
+   be written to the window, though it will definitely be written to
+   the drawable.  It's fine for args 2 and 3 to be the same window, or
+   for arg 2 to be a Window, and arg 3 to be a Pixmap.
+
+   The loaded image might be from a file, or from a screen shot of the
+   desktop, or from the system's video input, depending on user
+   preferences.
+
+   When the callback is called, the image data will have been loaded
+   into the given drawable.  Copy `name' if you want to keep it.
+
+   If it is from a file, then the `filename' argument will be the name
+   of the file.  It may be NULL.  If you want to keep this string, copy it.
+
+   The size and position of the image is in the `geometry' arg.
+   The image will generally have been scaled up to fit the window, but
+   if a loaded file had a different aspect ratio than the window, it
+   will have been centered, and the returned coords will describe that.
+
+   Many colors may be allocated from the window's colormap.
+ */
+extern void load_image_async (Screen *, Window, Drawable,
+                              void (*callback) (Screen *, Window,
+                                                Drawable,
+                                                const char *name,
+                                                XRectangle *geometry,
+                                                void *closure),
+                              void *closure);
+
+/* A utility wrapper around load_image_async() that is simpler if you
+   are only loading a single image at a time: just keep calling it
+   periodically until it returns NULL.  When it does, the image has
+   been loaded.
+ */
+typedef struct async_load_state async_load_state;
+extern async_load_state *load_image_async_simple (async_load_state *,
+                                                  Screen *,
+                                                  Window top_level,
+                                                  Drawable target, 
+                                                  char **filename_ret,
+                                                  XRectangle *geometry_ret);
+
+
+/* Whether one should use GCSubwindowMode when drawing on this window
+   (assuming a screen image has been grabbed onto it.)  Yes, this is a
+   total kludge. */
+extern Bool use_subwindow_mode_p(Screen *screen, Window window);
+
+/* Whether the given window is:
+   - the real root window;
+   - the virtual root window;
+   - a direct child of the root window;
+   - a direct child of the window manager's decorations.
+ */
+extern Bool top_level_window_p(Screen *screen, Window window);
+
+
+/* Don't call this: this is for the "xscreensaver-getimage" program only. */
+extern void grab_screen_image_internal (Screen *, Window);
+
+/* Don't use these: this is how "xscreensaver-getimage" and "grabclient.c"
+   pass the file name around. */
+#define XA_XSCREENSAVER_IMAGE_FILENAME "_SCREENSAVER_IMAGE_FILENAME"
+#define XA_XSCREENSAVER_IMAGE_GEOMETRY "_SCREENSAVER_IMAGE_GEOMETRY"
+
+/* For debugging: turn on verbosity. */
+extern void grabscreen_verbose (void);
+
+#ifdef HAVE_COCOA
+/* Don't use these: internal interface of grabclient.c. */
+extern void osx_grab_desktop_image (Screen *, Window, Drawable);
+extern Bool osx_load_image_file (Screen *, Window, Drawable,
+                                 const char *filename, XRectangle *geom_ret);
+#endif /* HAVE_COCOA */
+
+#endif /* __GRABSCREEN_H__ */
diff --git a/utils/hsv.h b/utils/hsv.h
new file mode 100644 (file)
index 0000000..e0fdfb0
--- /dev/null
@@ -0,0 +1,27 @@
+/* xscreensaver, Copyright (c) 1992, 1997 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __HSV_H__
+#define __HSV_H__
+
+/* Converts between RGB and HSV color spaces.
+   R, G, and B are in the range 0 - 65535;
+   H is in the range 0 - 360;
+   S and V are in the range 0.0 - 1.0.
+ */
+extern void hsv_to_rgb (int h, double s, double v,
+                       unsigned short *r,
+                       unsigned short *g,
+                       unsigned short *b);
+extern void rgb_to_hsv (unsigned short r, unsigned short g, unsigned short b,
+                       int *h, double *s, double *v);
+
+#endif /* __HSV_H__ */
diff --git a/utils/resources.c b/utils/resources.c
new file mode 100644 (file)
index 0000000..19b2cb6
--- /dev/null
@@ -0,0 +1,265 @@
+/* xscreensaver, Copyright (c) 1992, 1997, 1998, 2001, 2003, 2006
+ *  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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#include "utils.h"
+#include "resources.h"
+
+extern char *progname;
+
+
+#ifndef HAVE_COCOA
+
+#include <X11/Xresource.h>
+
+/* These are the Xlib/Xrm versions of these functions.
+   The Cocoa versions are on OSX/XScreenSaverView.m.
+ */
+
+extern char *progclass;
+extern XrmDatabase XtDatabase (Display *);
+
+static unsigned int get_time_resource (Display *dpy, 
+                                       char *res_name, char *res_class,
+                                      Bool sec_p);
+
+#ifndef isupper
+# define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef _tolower
+# define _tolower(c)  ((c) - 'A' + 'a')
+#endif
+
+char *
+get_string_resource (Display *dpy, char *res_name, char *res_class)
+{
+  XrmValue value;
+  char *type;
+  char full_name [1024], full_class [1024];
+  strcpy (full_name, progname);
+  strcat (full_name, ".");
+  strcat (full_name, res_name);
+  strcpy (full_class, progclass);
+  strcat (full_class, ".");
+  strcat (full_class, res_class);
+  if (XrmGetResource (XtDatabase (dpy), full_name, full_class, &type, &value))
+    {
+      char *str = (char *) malloc (value.size + 1);
+      strncpy (str, (char *) value.addr, value.size);
+      str [value.size] = 0;
+      return str;
+    }
+  return 0;
+}
+
+Bool 
+get_boolean_resource (Display *dpy, char *res_name, char *res_class)
+{
+  char *tmp, buf [100];
+  char *s = get_string_resource (dpy, res_name, res_class);
+  char *os = s;
+  if (! s) return 0;
+  for (tmp = buf; *s; s++)
+    *tmp++ = isupper (*s) ? _tolower (*s) : *s;
+  *tmp = 0;
+  free (os);
+
+  while (*buf &&
+        (buf[strlen(buf)-1] == ' ' ||
+         buf[strlen(buf)-1] == '\t'))
+    buf[strlen(buf)-1] = 0;
+
+  if (!strcmp (buf, "on") || !strcmp (buf, "true") || !strcmp (buf, "yes"))
+    return 1;
+  if (!strcmp (buf,"off") || !strcmp (buf, "false") || !strcmp (buf,"no"))
+    return 0;
+  fprintf (stderr, "%s: %s must be boolean, not %s.\n",
+          progname, res_name, buf);
+  return 0;
+}
+
+int 
+get_integer_resource (Display *dpy, char *res_name, char *res_class)
+{
+  int val;
+  char c, *s = get_string_resource (dpy, res_name, res_class);
+  char *ss = s;
+  if (!s) return 0;
+
+  while (*ss && *ss <= ' ') ss++;                      /* skip whitespace */
+
+  if (ss[0] == '0' && (ss[1] == 'x' || ss[1] == 'X'))  /* 0x: parse as hex */
+    {
+      if (1 == sscanf (ss+2, "%x %c", (unsigned int *) &val, &c))
+       {
+         free (s);
+         return val;
+       }
+    }
+  else                                                 /* else parse as dec */
+    {
+      if (1 == sscanf (ss, "%d %c", &val, &c))
+       {
+         free (s);
+         return val;
+       }
+    }
+
+  fprintf (stderr, "%s: %s must be an integer, not %s.\n",
+          progname, res_name, s);
+  free (s);
+  return 0;
+}
+
+double
+get_float_resource (Display *dpy, char *res_name, char *res_class)
+{
+  double val;
+  char c, *s = get_string_resource (dpy, res_name, res_class);
+  if (! s) return 0.0;
+  if (1 == sscanf (s, " %lf %c", &val, &c))
+    {
+      free (s);
+      return val;
+    }
+  fprintf (stderr, "%s: %s must be a float, not %s.\n",
+          progname, res_name, s);
+  free (s);
+  return 0.0;
+}
+
+#endif /* !HAVE_COCOA */
+
+
+/* These functions are the same with Xlib and Cocoa:
+ */
+
+
+unsigned int
+get_pixel_resource (Display *dpy, Colormap cmap,
+                    char *res_name, char *res_class)
+{
+  XColor color;
+  char *s = get_string_resource (dpy, res_name, res_class);
+  char *s2;
+  Bool ok = True;
+  if (!s) goto DEFAULT;
+
+  for (s2 = s + strlen(s) - 1; s2 > s; s2--)
+    if (*s2 == ' ' || *s2 == '\t')
+      *s2 = 0;
+    else
+      break;
+
+  if (! XParseColor (dpy, cmap, s, &color))
+    {
+      fprintf (stderr, "%s: can't parse color %s", progname, s);
+      ok = False;
+      goto DEFAULT;
+    }
+  if (! XAllocColor (dpy, cmap, &color))
+    {
+      fprintf (stderr, "%s: couldn't allocate color %s", progname, s);
+      ok = False;
+      goto DEFAULT;
+    }
+  free (s);
+  return color.pixel;
+ DEFAULT:
+  if (s) free (s);
+
+  {
+    Bool black_p = (strlen(res_class) >= 10 &&
+                    !strcasecmp ("Background",
+                                 res_class + strlen(res_class) - 10));
+    if (!ok)
+      fprintf (stderr, ": using %s.\n", (black_p ? "black" : "white"));
+    color.flags = DoRed|DoGreen|DoBlue;
+    color.red = color.green = color.blue = (black_p ? 0 : 0xFFFF);
+    if (XAllocColor (dpy, cmap, &color))
+      return color.pixel;
+    else
+      {
+        fprintf (stderr, "%s: couldn't allocate %s either!\n", progname,
+                 (black_p ? "black" : "white"));
+        /* We can't use BlackPixel/WhitePixel here, because we don't know
+           what screen we're allocating on (only an issue when running inside
+           the xscreensaver daemon: for hacks, DefaultScreen is fine.)
+         */
+        return 0;
+      }
+  }
+}
+
+
+int
+parse_time (const char *string, Bool seconds_default_p, Bool silent_p)
+{
+  unsigned int h, m, s;
+  char c;
+  if (3 == sscanf (string,   " %u : %2u : %2u %c", &h, &m, &s, &c))
+    ;
+  else if (2 == sscanf (string, " : %2u : %2u %c", &m, &s, &c) ||
+          2 == sscanf (string,    " %u : %2u %c", &m, &s, &c))
+    h = 0;
+  else if (1 == sscanf (string,       " : %2u %c", &s, &c))
+    h = m = 0;
+  else if (1 == sscanf (string,          " %u %c",
+                       (seconds_default_p ? &s : &m), &c))
+    {
+      h = 0;
+      if (seconds_default_p) m = 0;
+      else s = 0;
+    }
+  else
+    {
+      if (! silent_p)
+       fprintf (stderr, "%s: invalid time interval specification \"%s\".\n",
+                progname, string);
+      return -1;
+    }
+  if (s >= 60 && (h != 0 || m != 0))
+    {
+      if (! silent_p)
+       fprintf (stderr, "%s: seconds > 59 in \"%s\".\n", progname, string);
+      return -1;
+    }
+  if (m >= 60 && h > 0)
+    {
+      if (! silent_p)
+       fprintf (stderr, "%s: minutes > 59 in \"%s\".\n", progname, string);
+      return -1;
+    }
+  return ((h * 60 * 60) + (m * 60) + s);
+}
+
+static unsigned int 
+get_time_resource (Display *dpy, char *res_name, char *res_class, Bool sec_p)
+{
+  int val;
+  char *s = get_string_resource (dpy, res_name, res_class);
+  if (!s) return 0;
+  val = parse_time (s, sec_p, False);
+  free (s);
+  return (val < 0 ? 0 : val);
+}
+
+unsigned int 
+get_seconds_resource (Display *dpy, char *res_name, char *res_class)
+{
+  return get_time_resource (dpy, res_name, res_class, True);
+}
+
+unsigned int 
+get_minutes_resource (Display *dpy, char *res_name, char *res_class)
+{
+  return get_time_resource (dpy, res_name, res_class, False);
+}
diff --git a/utils/resources.h b/utils/resources.h
new file mode 100644 (file)
index 0000000..231fe23
--- /dev/null
@@ -0,0 +1,33 @@
+/* xscreensaver, Copyright (c) 1992, 1997, 2001, 2003, 2006
+ *  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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __XSCREENSAVER_RESOURCES_H__
+#define __XSCREENSAVER_RESOURCES_H__
+
+extern char *get_string_resource (Display*,char*,char*);
+extern Bool get_boolean_resource (Display*,char*,char*);
+extern int get_integer_resource (Display*,char*,char*);
+extern double get_float_resource (Display*,char*,char*);
+extern unsigned int get_pixel_resource (Display*,Colormap,char*,char*);
+extern unsigned int get_minutes_resource (Display*,char*,char*);
+extern unsigned int get_seconds_resource (Display*,char*,char*);
+extern int parse_time (const char *string, Bool seconds_default_p,
+                       Bool silent_p);
+extern Pixmap
+xscreensaver_logo (Screen *screen, Visual *visual,
+                   Drawable drawable, Colormap cmap,
+                   unsigned long background_color,
+                   unsigned long **pixels_ret, int *npixels_ret,
+                   Pixmap *mask_ret,
+                   Bool big_p);
+
+#endif /* __XSCREENSAVER_RESOURCES_H__ */
diff --git a/utils/usleep.c b/utils/usleep.c
new file mode 100644 (file)
index 0000000..f065729
--- /dev/null
@@ -0,0 +1,64 @@
+/* xscreensaver, Copyright (c) 1992, 1996, 1997, 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#else  /* !HAVE_CONFIG_H */
+# ifndef NO_SELECT
+#  define HAVE_SELECT
+# endif
+#endif /* !HAVE_CONFIG_H */
+
+#ifdef __STDC__
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if defined(VMS)
+# include <descrip.h>
+# include <stdio.h>
+# include <lib$routines.h>
+#elif defined(HAVE_SELECT)
+# include <sys/time.h>         /* for struct timeval */
+#endif
+
+
+#ifdef __SCREENHACK_USLEEP_H__
+ERROR, do not include that here
+#endif
+
+extern void screenhack_usleep (unsigned long usecs); /* suppress warning */
+
+void
+screenhack_usleep (unsigned long usecs)
+{
+# if defined(VMS)
+  float seconds = ((float) usecs)/1000000.0;
+  unsigned long int statvms = lib$wait(&seconds);
+
+#elif defined(HAVE_SELECT)
+  /* usleep() doesn't exist everywhere, and select() is faster anyway. */
+  struct timeval tv;
+  tv.tv_sec  = usecs / 1000000L;
+  tv.tv_usec = usecs % 1000000L;
+  (void) select (0, 0, 0, 0, &tv);
+
+#else /* !VMS && !HAVE_SELECT */
+  /* If you don't have select() or usleep(), I guess you lose...
+     Maybe you have napms() instead?  Let me know. */
+  usleep (usecs);
+
+#endif /* !VMS && !HAVE_SELECT */
+}
diff --git a/utils/usleep.h b/utils/usleep.h
new file mode 100644 (file)
index 0000000..c40363e
--- /dev/null
@@ -0,0 +1,20 @@
+/* xscreensaver, Copyright (c) 1992, 1996 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __SCREENHACK_USLEEP_H__
+#define __SCREENHACK_USLEEP_H__
+
+extern void screenhack_usleep (unsigned long usecs);
+
+#undef usleep
+#define usleep(usecs) screenhack_usleep(usecs)
+
+#endif /* __SCREENHACK_USLEEP_H__ */
diff --git a/utils/utils.h b/utils/utils.h
new file mode 100644 (file)
index 0000000..5df4ac9
--- /dev/null
@@ -0,0 +1,27 @@
+/* xscreensaver, Copyright (c) 1997, 2006 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_COCOA
+# include "jwxyz.h"
+#else /* !HAVE_COCOA - real X11 */
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/Xos.h>
+#endif /* !HAVE_COCOA */
diff --git a/utils/visual.c b/utils/visual.c
new file mode 100644 (file)
index 0000000..7c89f5a
--- /dev/null
@@ -0,0 +1,544 @@
+/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2003, 2006
+ * 
+ * 
+ *  by 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+/* This file contains some code for intelligently picking the best visual
+   (where "best" is biased in the direction of either: high color counts;
+   or: having writable color cells...)
+ */
+
+#include "utils.h"
+#include "resources.h"  /* for get_string_resource() */
+#include "visual.h"
+
+#include <string.h>
+#include <X11/Xutil.h>
+
+extern char *progname;
+
+
+#ifndef isupper
+# define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef _tolower
+# define _tolower(c)  ((c) - 'A' + 'a')
+#endif
+
+
+static Visual *pick_best_visual (Screen *, Bool, Bool);
+static Visual *pick_mono_visual (Screen *);
+static Visual *pick_best_visual_of_class (Screen *, int);
+static Visual *pick_best_gl_visual (Screen *);
+
+
+#define DEFAULT_VISUAL -1
+#define BEST_VISUAL    -2
+#define MONO_VISUAL    -3
+#define GRAY_VISUAL    -4
+#define COLOR_VISUAL   -5
+#define GL_VISUAL      -6
+#define SPECIFIC_VISUAL        -7
+
+Visual *
+get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
+           Bool verbose_p)
+{
+  char *v = (string ? strdup(string) : 0);
+  char c, *tmp;
+  int vclass;
+  unsigned long id;
+  Visual *result = 0;
+
+  if (v)
+    for (tmp = v; *tmp; tmp++)
+      if (isupper (*tmp)) *tmp = _tolower (*tmp);
+
+  if (!v || !*v)                                 vclass = BEST_VISUAL;
+  else if (!strcmp (v, "default"))               vclass = DEFAULT_VISUAL;
+  else if (!strcmp (v, "best"))                  vclass = BEST_VISUAL;
+  else if (!strcmp (v, "mono"))                  vclass = MONO_VISUAL;
+  else if (!strcmp (v, "monochrome"))            vclass = MONO_VISUAL;
+  else if (!strcmp (v, "gray"))                  vclass = GRAY_VISUAL;
+  else if (!strcmp (v, "grey"))                  vclass = GRAY_VISUAL;
+  else if (!strcmp (v, "color"))                 vclass = COLOR_VISUAL;
+  else if (!strcmp (v, "gl"))                    vclass = GL_VISUAL;
+  else if (!strcmp (v, "staticgray"))            vclass = StaticGray;
+  else if (!strcmp (v, "staticcolor"))           vclass = StaticColor;
+  else if (!strcmp (v, "truecolor"))             vclass = TrueColor;
+  else if (!strcmp (v, "grayscale"))             vclass = GrayScale;
+  else if (!strcmp (v, "greyscale"))             vclass = GrayScale;
+  else if (!strcmp (v, "pseudocolor"))           vclass = PseudoColor;
+  else if (!strcmp (v, "directcolor"))           vclass = DirectColor;
+  else if (1 == sscanf (v, " %lu %c", &id, &c))          vclass = SPECIFIC_VISUAL;
+  else if (1 == sscanf (v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL;
+  else
+    {
+      fprintf (stderr, "%s: unrecognized visual \"%s\".\n", progname, v);
+      vclass = DEFAULT_VISUAL;
+    }
+
+  if (vclass == DEFAULT_VISUAL)
+    result = DefaultVisualOfScreen (screen);
+  else if (vclass == BEST_VISUAL)
+    result = pick_best_visual (screen, prefer_writable_cells, False);
+  else if (vclass == MONO_VISUAL)
+    {
+      result = pick_mono_visual (screen);
+      if (!result && verbose_p)
+       fprintf (stderr, "%s: no monochrome visuals.\n", progname);
+    }
+  else if (vclass == GRAY_VISUAL)
+    {
+      if (prefer_writable_cells)
+       result = pick_best_visual_of_class (screen, GrayScale);
+      if (!result)
+       result = pick_best_visual_of_class (screen, StaticGray);
+      if (!result)
+       result = pick_best_visual_of_class (screen, GrayScale);
+      if (!result && verbose_p)
+       fprintf (stderr, "%s: no GrayScale or StaticGray visuals.\n",
+                progname);
+    }
+  else if (vclass == COLOR_VISUAL)
+    {
+      int class;
+      /* First see if the default visual will do. */
+      result = DefaultVisualOfScreen (screen);
+      class = visual_class(screen, result);
+      if (class != TrueColor &&
+         class != PseudoColor &&
+         class != DirectColor &&
+         class != StaticColor)
+       result = 0;
+      if (result && visual_depth(screen, result) <= 1)
+       result = 0;
+
+      /* Else, find the best non-default color visual */
+      if (!result)
+       result = pick_best_visual (screen, prefer_writable_cells, True);
+
+      if (!result && verbose_p)
+       fprintf (stderr, "%s: no color visuals.\n", progname);
+    }
+  else if (vclass == GL_VISUAL)
+    {
+      Visual *visual = pick_best_gl_visual (screen);
+      if (visual)
+       result = visual;
+      else if (verbose_p)
+       fprintf (stderr, "%s: no visual suitable for GL.\n", progname);
+    }
+  else if (vclass == SPECIFIC_VISUAL)
+    {
+      result = id_to_visual (screen, id);
+      if (!result && verbose_p)
+       fprintf (stderr, "%s: no visual with id 0x%x.\n", progname,
+                (unsigned int) id);
+    }
+  else
+    {
+      Visual *visual = pick_best_visual_of_class (screen, vclass);
+      if (visual)
+       result = visual;
+      else if (verbose_p)
+       fprintf (stderr, "%s: no visual of class %s.\n", progname, v);
+    }
+
+  if (v) free (v);
+  return result;
+}
+
+Visual *
+get_visual_resource (Screen *screen, char *name, char *class,
+                    Bool prefer_writable_cells)
+{
+  char *string = get_string_resource (DisplayOfScreen (screen), name, class);
+  Visual *v = get_visual (screen, string, prefer_writable_cells, True);
+  if (string)
+    free(string);
+  if (v)
+    return v;
+  else
+    return DefaultVisualOfScreen (screen);
+}
+
+
+static Visual *
+pick_best_visual (Screen *screen, Bool prefer_writable_cells, Bool color_only)
+{
+  Visual *visual;
+
+  if (!prefer_writable_cells)
+    {
+      /* If we don't prefer writable cells, then the "best" visual is the one
+        on which we can allocate the largest range and number of colors.
+
+        Therefore, a TrueColor visual which is at least 16 bits deep is best.
+        (The assumption here being that a TrueColor of less than 16 bits is
+        really just a PseudoColor visual with a pre-allocated color cube.)
+
+        The next best thing is a PseudoColor visual of any type.  After that
+        come the non-colormappable visuals, and non-color visuals.
+       */
+      if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
+         visual_depth (screen, visual) >= 16)
+       return visual;
+    }
+
+#define TRY_CLASS(CLASS) \
+  if ((visual = pick_best_visual_of_class (screen, CLASS)) && \
+      (!color_only || visual_depth(screen, visual) > 1)) \
+    return visual
+  TRY_CLASS(PseudoColor);
+  TRY_CLASS(TrueColor);
+  TRY_CLASS(DirectColor);
+  TRY_CLASS(StaticColor);
+  if (!color_only)
+    {
+      TRY_CLASS(GrayScale);
+      TRY_CLASS(StaticGray);
+    }
+#undef TRY_CLASS
+
+  visual = DefaultVisualOfScreen (screen);
+  if (!color_only || visual_depth(screen, visual) > 1)
+    return visual;
+  else
+    return 0;
+}
+
+static Visual *
+pick_mono_visual (Screen *screen)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+
+  vi_in.depth = 1;
+  vi_in.screen = screen_number (screen);
+  vi_out = XGetVisualInfo (dpy, (VisualDepthMask | VisualScreenMask),
+                          &vi_in, &out_count);
+  if (vi_out)
+    {
+      Visual *v = (out_count > 0 ? vi_out [0].visual : 0);
+      if (v && vi_out[0].depth != 1)
+       v = 0;
+      XFree ((char *) vi_out);
+      return v;
+    }
+  else
+    return 0;
+}
+
+
+static Visual *
+pick_best_visual_of_class (Screen *screen, int visual_class)
+{
+  /* The best visual of a class is the one which on which we can allocate
+     the largest range and number of colors, which means the one with the
+     greatest depth and number of cells.
+
+     (But actually, for XDaliClock, all visuals of the same class are
+     probably equivalent - either we have writable cells or we don't.)
+   */
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+
+  vi_in.class = visual_class;
+  vi_in.screen = screen_number (screen);
+  vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
+                          &vi_in, &out_count);
+  if (vi_out)
+    {
+      /* choose the 'best' one, if multiple */
+      int i, best;
+      Visual *visual;
+/*      for (i = 0, best = 0; i < out_count; i++) */
+      for (i = out_count-1, best = i; i >= 0; i--) /* go backwards */
+       /* It's better if it's deeper, or if it's the same depth with
+          more cells (does that ever happen?  Well, it could...) */
+       if ((vi_out [i].depth > vi_out [best].depth) ||
+           ((vi_out [i].depth == vi_out [best].depth) &&
+            (vi_out [i].colormap_size > vi_out [best].colormap_size)))
+         best = i;
+      visual = (best < out_count ? vi_out [best].visual : 0);
+      XFree ((char *) vi_out);
+      return visual;
+    }
+  else
+    return 0;
+}
+
+static Visual *
+pick_best_gl_visual (Screen *screen)
+{
+  /* The best visual for GL is a TrueColor visual that is half as deep as
+     the screen.  If such a thing doesn't exist, then TrueColor is best.
+     Failing that, the deepest available color visual is best.
+
+     Compare this function to get_gl_visual() in visual-gl.c.
+     This function tries to find the best GL visual using Xlib calls,
+     whereas that function does the same thing using GLX calls.
+   */
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+  Visual *result = 0;
+
+  int ndepths = 0;
+  int *depths = XListDepths (dpy, screen_number (screen), &ndepths);
+  int screen_depth = depths[ndepths];
+  XFree (depths);
+
+  vi_in.class = TrueColor;
+  vi_in.screen = screen_number (screen);
+  vi_in.depth = screen_depth / 2;
+  vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
+                                 VisualDepthMask),
+                          &vi_in, &out_count);
+  if (out_count > 0)
+    result = vi_out[0].visual;
+
+  if (vi_out)
+    XFree ((char *) vi_out);
+
+  if (!result && screen_depth > 24)
+    {
+      /* If it's a 32-deep screen and we didn't find a depth-16 visual,
+         see if there's a depth-12 visual. */
+      vi_in.class = TrueColor;
+      vi_in.screen = screen_number (screen);
+      vi_in.depth = 12;
+      vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
+                                     VisualDepthMask),
+                               &vi_in, &out_count);
+      if (out_count > 0)
+        result = vi_out[0].visual;
+    }
+
+  if (!result)
+    /* No half-depth TrueColor?  Ok, try for any TrueColor (the deepest.) */
+    result = pick_best_visual_of_class (screen, TrueColor);
+
+  if (!result)
+    /* No TrueColor?  Ok, try for anything. */
+    result = pick_best_visual (screen, False, False);
+
+  return result;
+}
+
+
+Visual *
+id_to_visual (Screen *screen, int id)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+  vi_in.screen = screen_number (screen);
+  vi_in.visualid = id;
+  vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
+                          &vi_in, &out_count);
+  if (vi_out)
+    {
+      Visual *v = vi_out[0].visual;
+      XFree ((char *) vi_out);
+      return v;
+    }
+  return 0;
+}
+
+int
+visual_depth (Screen *screen, Visual *visual)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count, d;
+  vi_in.screen = screen_number (screen);
+  vi_in.visualid = XVisualIDFromVisual (visual);
+  vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+                          &vi_in, &out_count);
+  if (! vi_out) abort ();
+  d = vi_out [0].depth;
+  XFree ((char *) vi_out);
+  return d;
+}
+
+
+#if 0
+/* You very probably don't want to be using this.
+   Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
+   the depth of protocol-level on-the-wire pixmap data, that is, XImages.
+   To get this info, you should be looking at XImage->bits_per_pixel
+   instead.  (And allocating the data for your XImage structures by
+   multiplying ximage->bytes_per_line by ximage->height.)
+ */
+int
+visual_pixmap_depth (Screen *screen, Visual *visual)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  int vdepth = visual_depth (screen, visual);
+  int pdepth = vdepth;
+  int i, pfvc = 0;
+  XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
+
+  /* Return the first matching depth in the pixmap formats.  If there are no
+     matching pixmap formats (which shouldn't be able to happen at all) then
+     return the visual depth instead. */
+  for (i = 0; i < pfvc; i++)
+    if (pfv[i].depth == vdepth)
+      {
+       pdepth = pfv[i].bits_per_pixel;
+       break;
+      }
+  if (pfv)
+    XFree (pfv);
+  return pdepth;
+}
+#endif /* 0 */
+
+
+int
+visual_class (Screen *screen, Visual *visual)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count, c;
+  vi_in.screen = screen_number (screen);
+  vi_in.visualid = XVisualIDFromVisual (visual);
+  vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+                          &vi_in, &out_count);
+  if (! vi_out) abort ();
+  c = vi_out [0].class;
+  XFree ((char *) vi_out);
+  return c;
+}
+
+Bool
+has_writable_cells (Screen *screen, Visual *visual)
+{
+  switch (visual_class (screen, visual))
+    {
+    case GrayScale:    /* Mappable grays. */
+    case PseudoColor:  /* Mappable colors. */
+    case DirectColor:  /* Like TrueColor, but with three colormaps:
+                           one each for red, green, and blue. */
+      return True;
+    case StaticGray:   /* Fixed grays. */
+    case TrueColor:    /* Fixed colors. */
+    case StaticColor:  /* Like PseudoColor with an unmodifiable colormap. */
+      return False;
+    default:
+      abort();
+      return False;
+    }
+}
+
+void
+describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
+{
+  char n[10];
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count;
+  vi_in.screen = screen_number (screen);
+  vi_in.visualid = XVisualIDFromVisual (visual);
+  vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
+                          &vi_in, &out_count);
+  if (! vi_out) abort ();
+  if (private_cmap_p)
+    sprintf(n, "%3d", vi_out->colormap_size);
+  else
+    strcpy(n, "default");
+
+  fprintf (f, "0x%02x (%s depth: %2d, cmap: %s)\n",
+          (unsigned int) vi_out->visualid,
+          (vi_out->class == StaticGray  ? "StaticGray, " :
+           vi_out->class == StaticColor ? "StaticColor," :
+           vi_out->class == TrueColor   ? "TrueColor,  " :
+           vi_out->class == GrayScale   ? "GrayScale,  " :
+           vi_out->class == PseudoColor ? "PseudoColor," :
+           vi_out->class == DirectColor ? "DirectColor," :
+                                          "UNKNOWN:    "),
+          vi_out->depth, n);
+  XFree ((char *) vi_out);
+}
+
+int
+screen_number (Screen *screen)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  int i;
+  for (i = 0; i < ScreenCount (dpy); i++)
+    if (ScreenOfDisplay (dpy, i) == screen)
+      return i;
+  abort ();
+  return 0;
+}
+
+int
+visual_cells (Screen *screen, Visual *visual)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  int out_count, c;
+  vi_in.screen = screen_number (screen);
+  vi_in.visualid = XVisualIDFromVisual (visual);
+  vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+                          &vi_in, &out_count);
+  if (! vi_out) abort ();
+  c = vi_out [0].colormap_size;
+  XFree ((char *) vi_out);
+  return c;
+}
+
+Visual *
+find_similar_visual(Screen *screen, Visual *old_visual)
+{
+  Display *dpy = DisplayOfScreen (screen);
+  XVisualInfo vi_in, *vi_out;
+  Visual *result = 0;
+  int out_count;
+
+  vi_in.screen = screen_number (screen);
+  vi_in.class  = visual_class (screen, old_visual);
+  vi_in.depth  = visual_depth (screen, old_visual);
+
+  /* Look for a visual of the same class and depth.
+   */
+  vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
+                                VisualDepthMask),
+                          &vi_in, &out_count);
+  if (vi_out && out_count > 0)
+    result = vi_out[0].visual;
+  if (vi_out) XFree (vi_out);
+  vi_out = 0;
+
+  /* Failing that, look for a visual of the same class.
+   */
+  if (!result)
+    {
+      vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
+                              &vi_in, &out_count);
+      if (vi_out && out_count > 0)
+       result = vi_out[0].visual;
+      if (vi_out) XFree (vi_out);
+      vi_out = 0;
+    }
+
+  /* Failing that, return the default visual. */
+  if (!result)
+    result = DefaultVisualOfScreen (screen);
+
+  return result;
+}
diff --git a/utils/visual.h b/utils/visual.h
new file mode 100644 (file)
index 0000000..863b1a1
--- /dev/null
@@ -0,0 +1,32 @@
+/* xscreensaver, Copyright (c) 1993-2000 by 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __VISUAL_H__
+#define __VISUAL_H__
+
+extern Visual *get_visual (Screen *, const char *name, Bool, Bool);
+extern Visual *get_visual_resource (Screen *, char *, char *, Bool);
+extern int visual_depth (Screen *, Visual *);
+/* extern int visual_pixmap_depth (Screen *, Visual *); */
+extern int visual_class (Screen *, Visual *);
+extern int visual_cells (Screen *, Visual *);
+extern int screen_number (Screen *);
+extern Visual *find_similar_visual (Screen *, Visual *old);
+extern void describe_visual (FILE *f, Screen *, Visual *, Bool private_cmap_p);
+extern Visual *get_overlay_visual (Screen *, unsigned long *pixel_return);
+extern Bool has_writable_cells (Screen *, Visual *);
+extern Visual *id_to_visual (Screen *, int);
+
+extern Visual *get_gl_visual (Screen *);
+extern void describe_gl_visual (FILE *, Screen *, Visual *, Bool priv_cmap_p);
+extern Bool validate_gl_visual (FILE *, Screen *, const char *, Visual *);
+
+#endif /* __VISUAL_H__ */
diff --git a/utils/vroot.h b/utils/vroot.h
new file mode 100644 (file)
index 0000000..65097b8
--- /dev/null
@@ -0,0 +1,156 @@
+/* -*- Mode: C; tab-width: 2 -*-                                             */
+/*****************************************************************************/
+/**                   Copyright 1991 by Andreas Stolcke                     **/
+/**               Copyright 1990 by Solbourne Computer Inc.                 **/
+/**                          Longmont, Colorado                             **/
+/**                                                                         **/
+/**                           All Rights Reserved                           **/
+/**                                                                         **/
+/**    Permission to use, copy, modify, and distribute this software and    **/
+/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
+/**    granted, provided that the above copyright notice appear  in  all    **/
+/**    copies and that both  that  copyright  notice  and  this  permis-    **/
+/**    sion  notice appear in supporting  documentation,  and  that  the    **/
+/**    name of Solbourne not be used in advertising                         **/
+/**    in publicity pertaining to distribution of the  software  without    **/
+/**    specific, written prior permission.                                  **/
+/**                                                                         **/
+/**    ANDREAS STOLCKE AND SOLBOURNE COMPUTER INC. DISCLAIMS ALL WARRANTIES **/
+/**    WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF    **/
+/**    MERCHANTABILITY  AND  FITNESS,  IN  NO  EVENT SHALL ANDREAS STOLCKE  **/
+/**    OR SOLBOURNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL    **/
+/**    DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA   **/
+/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
+/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
+/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
+/*****************************************************************************/
+/*
+ * vroot.h -- Virtual Root Window handling header file
+ *
+ * This header file redefines the X11 macros RootWindow and DefaultRootWindow,
+ * making them look for a virtual root window as provided by certain `virtual'
+ * window managers like swm and tvtwm. If none is found, the ordinary root
+ * window is returned, thus retaining backward compatibility with standard
+ * window managers.
+ * The function implementing the virtual root lookup remembers the result of
+ * its last invocation to avoid overhead in the case of repeated calls
+ * on the same display and screen arguments. 
+ * The lookup code itself is taken from Tom LaStrange's ssetroot program.
+ *
+ * Most simple root window changing X programs can be converted to using
+ * virtual roots by just including
+ *
+ * #include <X11/vroot.h>
+ *
+ * after all the X11 header files.  It has been tested on such popular
+ * X clients as xphoon, xfroot, xloadimage, and xaqua.
+ * It also works with the core clients xprop, xwininfo, xwd, and editres
+ * (and is necessary to get those clients working under tvtwm).
+ * It does NOT work with xsetroot; get the xsetroot replacement included in
+ * the tvtwm distribution instead.
+ *
+ * Andreas Stolcke <stolcke@ICSI.Berkeley.EDU>, 9/7/90
+ * - replaced all NULL's with properly cast 0's, 5/6/91
+ * - free children list (suggested by Mark Martin <mmm@cetia.fr>), 5/16/91
+ * - include X11/Xlib.h and support RootWindowOfScreen, too 9/17/91
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 28-Apr-1997
+ * - use ANSI C
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 3-Sep-2003
+ * - if the environment variable "XSCREENSAVER_WINDOW" is set, use that
+ *   as the root window instead of searching for __SWM_VROOT.
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 14-Aug-2004
+ * - changes to get gcc to stop whining about "type punning".
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 16-Dec-2004
+ * - fixed that last fix.
+ */
+
+#ifndef _VROOT_H_
+#define _VROOT_H_
+#define _XSCREENSAVER_VROOT_H_
+
+#if !defined(lint) && !defined(SABER)
+static const char vroot_rcsid[] =
+ "#Id: vroot.h,v 1.8 2004/12/16 05:33:54 jwz Exp #" "\n"
+ "#Id: vroot.h,v 1.4 1991/09/30 19:23:16 stolcke Exp stolcke #";
+#endif
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+
+static Window
+#ifdef __STDC__ /* ANSIfication added by jwz, to avoid superfluous warnings. */
+VirtualRootWindowOfScreen(Screen *screen)
+#else /* !__STDC__ */
+VirtualRootWindowOfScreen(screen) Screen *screen;
+#endif /* !__STDC__ */
+{
+       static Screen *save_screen = (Screen *)0;
+       static Window root = (Window)0;
+
+       if (screen != save_screen) {
+               Display *dpy = DisplayOfScreen(screen);
+               Atom __SWM_VROOT = None;
+               int i;
+               Window rootReturn, parentReturn, *children;
+               unsigned int numChildren;
+
+    /* first check for a hex or decimal window ID in the environment */
+    const char *xss_id = getenv("XSCREENSAVER_WINDOW");
+    if (xss_id && *xss_id) {
+      unsigned long id = 0;
+      char c;
+      if (1 == sscanf (xss_id, " 0x%lx %c", &id, &c) ||
+          1 == sscanf (xss_id, " %lu %c",   &id, &c)) {
+        root = (Window) id;
+        save_screen = screen;
+        return root;
+      }
+    }
+
+               root = RootWindowOfScreen(screen);
+
+               /* go look for a virtual root */
+               __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
+               if (XQueryTree(dpy, root, &rootReturn, &parentReturn,
+                                &children, &numChildren)) {
+                       for (i = 0; i < numChildren; i++) {
+                               Atom actual_type;
+                               int actual_format;
+                               unsigned long nitems, bytesafter;
+                               unsigned char *newRoot = 0;
+
+                               if (XGetWindowProperty(dpy, children[i],
+                                       __SWM_VROOT, 0, 1, False, XA_WINDOW,
+                                       &actual_type, &actual_format,
+                                       &nitems, &bytesafter,
+                                       &newRoot) == Success
+                                   && newRoot) {
+                                   root = *((Window *) newRoot);
+                                   break;
+                               }
+                       }
+                       if (children)
+                               XFree((char *)children);
+               }
+
+               save_screen = screen;
+       }
+
+       return root;
+}
+
+#undef RootWindowOfScreen
+#define RootWindowOfScreen(s) VirtualRootWindowOfScreen(s)
+
+#undef RootWindow
+#define RootWindow(dpy,screen) VirtualRootWindowOfScreen(ScreenOfDisplay(dpy,screen))
+
+#undef DefaultRootWindow
+#define DefaultRootWindow(dpy) VirtualRootWindowOfScreen(DefaultScreenOfDisplay(dpy))
+
+#endif /* _VROOT_H_ */
diff --git a/utils/xmu.h b/utils/xmu.h
new file mode 100644 (file)
index 0000000..48084f7
--- /dev/null
@@ -0,0 +1,14 @@
+/* This file contains compatibility routines for systems without Xmu.
+ * You would be better served by installing Xmu on your machine or
+ * yelling at your vendor to ship it.
+ */
+
+#ifndef __XMU_H__
+#define __XMU_H__
+
+#include <X11/Xlib.h>
+#include <stdio.h>
+
+int XmuPrintDefaultErrorMessage (Display *dpy, XErrorEvent *event, FILE *fp);
+
+#endif /* __XMU_H__ */
diff --git a/utils/yarandom.c b/utils/yarandom.c
new file mode 100644 (file)
index 0000000..cc38895
--- /dev/null
@@ -0,0 +1,125 @@
+/* yarandom.c -- Yet Another Random Number Generator.
+ * Copyright (c) 1997, 1998, 2003 by 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+/* The unportable mess that is rand(), random(), drand48() and friends led me
+   to ask Phil Karlton <karlton@netscape.com> what the Right Thing to Do was.
+   He responded with this.  It is non-cryptographically secure, reasonably
+   random (more so than anything that is in any C library), and very fast.
+
+   I don't understand how it works at all, but he says "look at Knuth,
+   Vol. 2 (original edition), page 26, Algorithm A.  In this case n=55,
+   k=24 and m=2^32."
+
+   So there you have it.
+
+   ---------------------------
+   Note: xlockmore 4.03a10 uses this very simple RNG:
+
+       if ((seed = seed % 44488 * 48271 - seed / 44488 * 3399) < 0)
+         seed += 2147483647;
+       return seed-1;
+
+   of which it says
+
+       ``Dr. Park's algorithm published in the Oct. '88 ACM  "Random Number
+         Generators: Good Ones Are Hard To Find" His version available at
+         ftp://cs.wm.edu/pub/rngs.tar Present form by many authors.''
+
+   Karlton says: ``the usual problem with that kind of RNG turns out to
+   be unexepected short cycles for some word lengths.''
+
+   Karlton's RNG is faster, since it does three adds and two stores, while the
+   xlockmore RNG does two multiplies, two divides, three adds, and one store.
+
+   Compiler optimizations make a big difference here:
+       gcc -O:     difference is 1.2x.
+       gcc -O2:    difference is 1.4x.
+       gcc -O3:    difference is 1.5x.
+       SGI cc -O:  difference is 2.4x.
+       SGI cc -O2: difference is 2.4x.
+       SGI cc -O3: difference is 5.1x.
+   Irix 6.2; Indy r5k; SGI cc version 6; gcc version 2.7.2.1.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>  /* for getpid() */
+#endif
+#include <sys/time.h> /* for gettimeofday() */
+
+#include "yarandom.h"
+# undef ya_rand_init
+
+
+/* The following 'random' numbers are taken from CRC, 18th Edition, page 622.
+   Each array element was taken from the corresponding line in the table,
+   except that a[0] was from line 100. 8s and 9s in the table were simply
+   skipped. The high order digit was taken mod 4.
+ */
+#define VectorSize 55
+static unsigned int a[VectorSize] = {
+ 035340171546, 010401501101, 022364657325, 024130436022, 002167303062, /*  5 */
+ 037570375137, 037210607110, 016272055420, 023011770546, 017143426366, /* 10 */
+ 014753657433, 021657231332, 023553406142, 004236526362, 010365611275, /* 14 */
+ 007117336710, 011051276551, 002362132524, 001011540233, 012162531646, /* 20 */
+ 007056762337, 006631245521, 014164542224, 032633236305, 023342700176, /* 25 */
+ 002433062234, 015257225043, 026762051606, 000742573230, 005366042132, /* 30 */
+ 012126416411, 000520471171, 000725646277, 020116577576, 025765742604, /* 35 */
+ 007633473735, 015674255275, 017555634041, 006503154145, 021576344247, /* 40 */
+ 014577627653, 002707523333, 034146376720, 030060227734, 013765414060, /* 45 */
+ 036072251540, 007255221037, 024364674123, 006200353166, 010126373326, /* 50 */
+ 015664104320, 016401041535, 016215305520, 033115351014, 017411670323  /* 55 */
+};
+
+static int i1, i2;
+
+unsigned int
+ya_random (void)
+{
+  register int ret = a[i1] + a[i2];
+  a[i1] = ret;
+  if (++i1 >= VectorSize) i1 = 0;
+  if (++i2 >= VectorSize) i2 = 0;
+  return ret;
+}
+
+void
+ya_rand_init(unsigned int seed)
+{
+  int i;
+  if (seed == 0)
+    {
+      struct timeval tp;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+      struct timezone tzp;
+      gettimeofday(&tp, &tzp);
+#else
+      gettimeofday(&tp);
+#endif
+      /* ignore overflow */
+      seed = (999*tp.tv_sec) + (1001*tp.tv_usec) + (1003 * getpid());
+    }
+
+  a[0] += seed;
+  for (i = 1; i < VectorSize; i++)
+    {
+      seed = a[i-1]*1001 + seed*999;
+      a[i] += seed;
+    }
+
+  i1 = a[0] % VectorSize;
+  i2 = (i1 + 24) % VectorSize;
+}
diff --git a/utils/yarandom.h b/utils/yarandom.h
new file mode 100644 (file)
index 0000000..eb560a2
--- /dev/null
@@ -0,0 +1,65 @@
+/* xscreensaver, Copyright (c) 1997, 1998, 2003 by 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ */
+
+#ifndef __YARANDOM_H__
+#define __YARANDOM_H__
+
+#undef random
+#undef rand
+#undef drand48
+#undef srandom
+#undef srand
+#undef srand48
+#undef frand
+#undef RAND_MAX
+
+#ifdef VMS
+# include "vms-gtod.h"
+#endif
+
+extern unsigned int ya_random (void);
+extern void ya_rand_init (unsigned int);
+
+#define random()   ya_random()
+#define RAND_MAX   0xFFFFFFFF
+
+/*#define srandom(i) ya_rand_init(0)*/
+
+/* Define these away to keep people from using the wrong APIs in xscreensaver.
+ */
+#define rand          __ERROR_use_random_not_rand_in_xscreensaver__
+#define drand48       __ERROR_use_frand_not_drand48_in_xscreensaver__
+#define srandom       __ERROR_do_not_call_srandom_in_xscreensaver__
+#define srand         __ERROR_do_not_call_srand_in_xscreensaver__
+#define srand48       __ERROR_do_not_call_srand48_in_xscreensaver__
+#define ya_rand_init  __ERROR_do_not_call_ya_rand_init_in_xscreensaver__
+
+
+#if defined (__GNUC__) && (__GNUC__ >= 2)
+ /* Implement frand using GCC's statement-expression extension. */
+
+# define frand(f)                                                      \
+  __extension__                                                                \
+  ({ double tmp = ((((double) random()) * ((double) (f))) /            \
+                  ((double) ((unsigned int)~0)));                      \
+     tmp < 0 ? (-tmp) : tmp; })
+
+#else /* not GCC2 - implement frand using a global variable.*/
+
+static double _frand_tmp_;
+# define frand(f)                                                      \
+  (_frand_tmp_ = ((((double) random()) * ((double) (f))) /             \
+                 ((double) ((unsigned int)~0))),                       \
+   _frand_tmp_ < 0 ? (-_frand_tmp_) : _frand_tmp_)
+
+#endif /* not GCC2 */
+
+#endif /* __YARANDOM_H__ */