http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / deluxe.c
index 75b9832900956d7d6369d2fbbe3bb87e997e3840..7b0ac3b4f6ec427786df17f5a0cc670cf672d50a 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1999, 2001, 2002 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1999-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
 #define countof(x) (sizeof(x)/sizeof(*(x)))
 #define ABS(x) ((x)<0?-(x):(x))
 
-static Bool transparent_p;
-static int nplanes;
-static unsigned long base_pixel, *plane_masks;
+struct state {
+  Display *dpy;
+  Window window;
+
+  Bool transparent_p;
+  int nplanes;
+  unsigned long base_pixel, *plane_masks;
+
+  int count;
+  int delay;
+  int ncolors;
+  Bool dbuf;
+  XColor *colors;
+  GC erase_gc;
+  struct throbber **throbbers;
+  XWindowAttributes xgwa;
+  Pixmap b, ba, bb;    /* double-buffer to reduce flicker */
+
+# ifdef HAVE_DOUBLE_BUFFER_EXTENSION
+  Bool dbeclear_p;
+  XdbeBackBuffer backb;
+# endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
+};
 
 struct throbber {
   int x, y;
@@ -32,11 +52,12 @@ struct throbber {
   int speed;
   int fuse;
   GC gc;
-  void (*draw) (Display *, Drawable, struct throbber *);
+  void (*draw) (struct state *, Drawable, struct throbber *);
 };
 
+
 static void
-draw_star (Display *dpy, Drawable w, struct throbber *t)
+draw_star (struct state *st, Drawable w, struct throbber *t)
 {
   XPoint points[11];
   int x = t->x;
@@ -58,13 +79,13 @@ draw_star (Display *dpy, Drawable w, struct throbber *t)
   points[9].x = x + s2 * cos(o + 0.9*c); points[9].y = y + s2 * sin(o + 0.9*c);
   points[10] = points[0];
 
-  XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
+  XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
 }
 
 static void
-draw_circle (Display *dpy, Drawable w, struct throbber *t)
+draw_circle (struct state *st, Drawable w, struct throbber *t)
 {
-  XDrawArc (dpy, w, t->gc,
+  XDrawArc (st->dpy, w, t->gc,
             t->x - t->size / 2,
             t->y - t->size / 2,
             t->size, t->size,
@@ -72,29 +93,29 @@ draw_circle (Display *dpy, Drawable w, struct throbber *t)
 }
 
 static void
-draw_hlines (Display *dpy, Drawable w, struct throbber *t)
+draw_hlines (struct state *st, Drawable w, struct throbber *t)
 {
-  XDrawLine (dpy, w, t->gc, 0,
+  XDrawLine (st->dpy, w, t->gc, 0,
              t->y - t->size, t->max_size,
              t->y - t->size);
-  XDrawLine (dpy, w, t->gc, 0,
+  XDrawLine (st->dpy, w, t->gc, 0,
              t->y + t->size, t->max_size,
              t->y + t->size);
 }
 
 static void
-draw_vlines (Display *dpy, Drawable w, struct throbber *t)
+draw_vlines (struct state *st, Drawable w, struct throbber *t)
 {
-  XDrawLine (dpy, w, t->gc,
+  XDrawLine (st->dpy, w, t->gc,
              t->x - t->size, 0,
              t->x - t->size, t->max_size);
-  XDrawLine (dpy, w, t->gc,
+  XDrawLine (st->dpy, w, t->gc,
              t->x + t->size, 0,
              t->x + t->size, t->max_size);
 }
 
 static void
-draw_corners (Display *dpy, Drawable w, struct throbber *t)
+draw_corners (struct state *st, Drawable w, struct throbber *t)
 {
   int s = (t->size + t->thickness) / 2;
   XPoint points[3];
@@ -102,27 +123,27 @@ draw_corners (Display *dpy, Drawable w, struct throbber *t)
   points[0].x = 0;        points[0].y = t->y - s;
   points[1].x = t->x - s; points[1].y = t->y - s;
   points[2].x = t->x - s; points[2].y = 0;
-  XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
+  XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
 
   points[0].x = 0;        points[0].y = t->y + s;
   points[1].x = t->x - s; points[1].y = t->y + s;
   points[2].x = t->x - s; points[2].y = t->max_size;
-  XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
+  XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
 
   points[0].x = t->x + s;    points[0].y = 0;
   points[1].x = t->x + s;    points[1].y = t->y - s;
   points[2].x = t->max_size; points[2].y = t->y - s;
-  XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
+  XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
 
   points[0].x = t->x + s;    points[0].y = t->max_size;
   points[1].x = t->x + s;    points[1].y = t->y + s;
   points[2].x = t->max_size; points[2].y = t->y + s;
-  XDrawLines (dpy, w, t->gc, points, countof(points), CoordModeOrigin);
+  XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
 }
 
 
 static struct throbber *
-make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
+make_throbber (struct state *st, Drawable d, int w, int h, unsigned long pixel)
 {
   XGCValues gcv;
   unsigned long flags;
@@ -130,9 +151,9 @@ make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
   t->x = w / 2;
   t->y = h / 2;
   t->max_size = w;
-  t->speed = get_integer_resource ("speed", "Speed");
+  t->speed = get_integer_resource (st->dpy, "speed", "Speed");
   t->fuse = 1 + (random() % 4);
-  t->thickness = get_integer_resource ("thickness", "Thickness");
+  t->thickness = get_integer_resource (st->dpy, "thickness", "Thickness");
 
   if (t->speed < 0) t->speed = -t->speed;
   t->speed += (((random() % t->speed) / 2) - (t->speed / 2));
@@ -144,24 +165,39 @@ make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
     t->size = t->thickness, t->speed = -t->speed;
 
   flags = GCForeground;
-  if (transparent_p)
+# ifndef HAVE_COCOA
+  if (st->transparent_p)
     {
       gcv.foreground = ~0L;
-      gcv.plane_mask = base_pixel | plane_masks[random() % nplanes];
+      gcv.plane_mask = st->base_pixel | st->plane_masks[random() % st->nplanes];
       flags |= GCPlaneMask;
     }
   else
+# endif /* !HAVE_COCOA */
     {
       gcv.foreground = pixel;
     }
 
   gcv.line_width = t->thickness;
-  gcv.line_style = LineSolid;
   gcv.cap_style = CapProjecting;
   gcv.join_style = JoinMiter;
 
-  flags |= (GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle);
-  t->gc = XCreateGC (dpy, d, flags, &gcv);
+  flags |= (GCLineWidth | GCCapStyle | GCJoinStyle);
+  t->gc = XCreateGC (st->dpy, d, flags, &gcv);
+
+# ifdef HAVE_COCOA
+  if (st->transparent_p)
+    {
+      /* give a non-opaque alpha to the color */
+      unsigned long pixel = gcv.foreground;
+      unsigned long amask = BlackPixelOfScreen (st->xgwa.screen);
+      unsigned long a = (0xCCCCCCCC & amask);
+      pixel = (pixel & (~amask)) | a;
+
+      jwxyz_XSetAlphaAllowed (st->dpy, t->gc, True);
+      XSetForeground (st->dpy, t->gc, pixel);
+    }
+# endif /* HAVE_COCOA */
 
   switch (random() % 11) {
   case 0: case 1: case 2: case 3: t->draw = draw_star; break;
@@ -176,7 +212,7 @@ make_throbber (Display *dpy, Drawable d, int w, int h, unsigned long pixel)
 }
 
 static int
-throb (Display *dpy, Drawable window, struct throbber *t)
+throb (struct state *st, Drawable window, struct throbber *t)
 {
   t->size += t->speed;
   if (t->size <= (t->thickness / 2))
@@ -193,180 +229,216 @@ throb (Display *dpy, Drawable window, struct throbber *t)
 
   if (t->fuse <= 0)
     {
-      XFreeGC (dpy, t->gc);
+      XFreeGC (st->dpy, t->gc);
       memset (t, 0, sizeof(*t));
       free (t);
       return -1;
     }
   else
     {
-      t->draw (dpy, window, t);
+      t->draw (st, window, t);
       return 0;
     }
 }
 
 
-\f
-char *progclass = "Deluxe";
-
-char *defaults [] = {
-  ".background:                black",
-  ".foreground:                white",
-  "*delay:             5000",
-  "*count:             5",
-  "*thickness:         50",
-  "*speed:             15",
-  "*ncolors:           20",
-  "*nlayers:           0",
-  "*transparent:       False",
-  "*doubleBuffer:      True",
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-  "*useDBE:            True",
-  "*useDBEClear:       True",
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-  0
-};
-
-XrmOptionDescRec options [] = {
-  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
-  { "-thickness",      ".thickness",   XrmoptionSepArg, 0 },
-  { "-count",          ".count",       XrmoptionSepArg, 0 },
-  { "-ncolors",                ".ncolors",     XrmoptionSepArg, 0 },
-  { "-speed",          ".speed",       XrmoptionSepArg, 0 },
-  { "-transparent",    ".transparent",  XrmoptionNoArg,  "True" },
-  { "-opaque",         ".transparent",  XrmoptionNoArg,  "False" },
-  { "-db",             ".doubleBuffer", XrmoptionNoArg,  "True" },
-  { "-no-db",          ".doubleBuffer", XrmoptionNoArg,  "False" },
-  { 0, 0, 0, 0 }
-};
-
-void
-screenhack (Display *dpy, Window window)
+static void *
+deluxe_init (Display *dpy, Window window)
 {
-  int count = get_integer_resource ("count", "Integer");
-  int delay = get_integer_resource ("delay", "Integer");
-  int ncolors = get_integer_resource ("ncolors", "Integer");
-  Bool dbuf = get_boolean_resource ("doubleBuffer", "Boolean");
-  Bool dbeclear_p = get_boolean_resource ("useDBEClear", "Boolean");
-  XColor *colors = 0;
+  struct state *st = (struct state *) calloc (1, sizeof(*st));
   XGCValues gcv;
-  GC erase_gc = 0;
   int i;
-  struct throbber **throbbers;
-  XWindowAttributes xgwa;
-  Pixmap b=0, ba=0, bb=0;      /* double-buffer to reduce flicker */
-#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-  XdbeBackBuffer backb = 0;
-#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
+  st->dpy = dpy;
+  st->window = window;
+  st->count = get_integer_resource (st->dpy, "count", "Integer");
+  st->delay = get_integer_resource (st->dpy, "delay", "Integer");
+  st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
+  st->dbuf = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean");
+
+# ifdef HAVE_DOUBLE_BUFFER_EXTENSION
+  st->dbeclear_p = get_boolean_resource (st->dpy, "useDBEClear", "Boolean");
+#endif
+
+# ifdef HAVE_COCOA     /* Don't second-guess Quartz's double-buffering */
+  st->dbuf = False;
+# endif
 
-  XGetWindowAttributes (dpy, window, &xgwa);
+  XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
 
-  transparent_p = get_boolean_resource("transparent", "Transparent");
+  st->transparent_p = get_boolean_resource(st->dpy, "transparent", "Transparent");
 
-  colors = (XColor *) calloc (sizeof(*colors), ncolors);
+  st->colors = (XColor *) calloc (sizeof(*st->colors), st->ncolors);
 
-  if (get_boolean_resource("mono", "Boolean"))
+  if (get_boolean_resource(st->dpy, "mono", "Boolean"))
     {
     MONO:
-      ncolors = 1;
-      colors[0].pixel = get_pixel_resource("foreground", "Foreground",
-                                           dpy, xgwa.colormap);
+      st->ncolors = 1;
+      st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap,
+                                           "foreground", "Foreground");
     }
-  else if (transparent_p)
+#ifndef HAVE_COCOA
+  else if (st->transparent_p)
     {
-      nplanes = get_integer_resource ("planes", "Planes");
-      if (nplanes <= 0)
-        nplanes = (random() % (xgwa.depth-2)) + 2;
-
-      allocate_alpha_colors (xgwa.screen, xgwa.visual, xgwa.colormap,
-                             &nplanes, True, &plane_masks,
-                            &base_pixel);
-      if (nplanes <= 1)
+      st->nplanes = get_integer_resource (st->dpy, "planes", "Planes");
+      if (st->nplanes <= 0)
+        st->nplanes = (random() % (st->xgwa.depth-2)) + 2;
+
+      allocate_alpha_colors (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
+                             &st->nplanes, True, &st->plane_masks,
+                            &st->base_pixel);
+      if (st->nplanes <= 1)
        {
+# if 0
          fprintf (stderr,
          "%s: couldn't allocate any color planes; turning transparency off.\n",
                   progname);
-          transparent_p = False;
+# endif
+          st->transparent_p = False;
          goto COLOR;
        }
     }
+#endif /* !HAVE_COCOA */
   else
     {
+#ifndef HAVE_COCOA
     COLOR:
-      make_random_colormap (dpy, xgwa.visual, xgwa.colormap,
-                            colors, &ncolors, True, True, 0, True);
-      if (ncolors < 2)
+#endif
+      make_random_colormap (st->dpy, st->xgwa.visual, st->xgwa.colormap,
+                            st->colors, &st->ncolors, True, True, 0, True);
+      if (st->ncolors < 2)
         goto MONO;
     }
 
-  if (dbuf)
+  if (st->dbuf)
     {
 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-      if (dbeclear_p)
-        b = xdbe_get_backbuffer (dpy, window, XdbeBackground);
+      if (st->dbeclear_p)
+        st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeBackground);
       else
-        b = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
-      backb = b;
+        st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
+      st->backb = st->b;
 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
 
-      if (!b)
+      if (!st->b)
         {
-          ba = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
-          bb = XCreatePixmap (dpy, window, xgwa.width, xgwa.height,xgwa.depth);
-          b = ba;
+          st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
+          st->bb = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
+          st->b = st->ba;
         }
     }
   else
     {
-      b = window;
+      st->b = st->window;
     }
 
-  throbbers = (struct throbber **) calloc (count, sizeof(struct throbber *));
-  for (i = 0; i < count; i++)
-    throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
-                                  colors[random() % ncolors].pixel);
+  st->throbbers = (struct throbber **) calloc (st->count, sizeof(struct throbber *));
+  for (i = 0; i < st->count; i++)
+    st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
+                                  st->colors[random() % st->ncolors].pixel);
 
-  gcv.foreground = get_pixel_resource ("background", "Background",
-                                       dpy, xgwa.colormap);
-  erase_gc = XCreateGC (dpy, b, GCForeground, &gcv);
+  gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
+                                       "background", "Background");
+  st->erase_gc = XCreateGC (st->dpy, st->b, GCForeground, &gcv);
 
-  if (ba) XFillRectangle (dpy, ba, erase_gc, 0, 0, xgwa.width, xgwa.height);
-  if (bb) XFillRectangle (dpy, bb, erase_gc, 0, 0, xgwa.width, xgwa.height);
+  if (st->ba) XFillRectangle (st->dpy, st->ba, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
+  if (st->bb) XFillRectangle (st->dpy, st->bb, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
 
-  while (1)
-    {
-      if (!dbeclear_p
+  return st;
+}
+
+static unsigned long
+deluxe_draw (Display *dpy, Window window, void *closure)
+{
+  struct state *st = (struct state *) closure;
+  int i;
 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-          || !backb
+  if (!st->dbeclear_p || !st->backb)
 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-          )
-        XFillRectangle (dpy, b, erase_gc, 0, 0, xgwa.width, xgwa.height);
+    XFillRectangle (st->dpy, st->b, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
 
-      for (i = 0; i < count; i++)
-        if (throb (dpy, b, throbbers[i]) < 0)
-          throbbers[i] = make_throbber (dpy, b, xgwa.width, xgwa.height,
-                                        colors[random() % ncolors].pixel);
+  for (i = 0; i < st->count; i++)
+    if (throb (st, st->b, st->throbbers[i]) < 0)
+      st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
+                                    st->colors[random() % st->ncolors].pixel);
 
 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
-      if (backb)
-        {
-          XdbeSwapInfo info[1];
-          info[0].swap_window = window;
-          info[0].swap_action = (dbeclear_p ? XdbeBackground : XdbeUndefined);
-          XdbeSwapBuffers (dpy, info, 1);
-        }
-      else
+  if (st->backb)
+    {
+      XdbeSwapInfo info[1];
+      info[0].swap_window = st->window;
+      info[0].swap_action = (st->dbeclear_p ? XdbeBackground : XdbeUndefined);
+      XdbeSwapBuffers (st->dpy, info, 1);
+    }
+  else
 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
-      if (dbuf)
-        {
-          XCopyArea (dpy, b, window, erase_gc, 0, 0,
-                     xgwa.width, xgwa.height, 0, 0);
-          b = (b == ba ? bb : ba);
-        }
+    if (st->dbuf)
+      {
+        XCopyArea (st->dpy, st->b, st->window, st->erase_gc, 0, 0,
+                   st->xgwa.width, st->xgwa.height, 0, 0);
+        st->b = (st->b == st->ba ? st->bb : st->ba);
+      }
+
+  return st->delay;
+}
 
-      XSync (dpy, False);
-      screenhack_handle_events (dpy);
-      if (delay)
-        usleep (delay);
-    }
+static void
+deluxe_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+  struct state *st = (struct state *) closure;
+  if (! st->dbuf) {   /* #### more complicated if we have a back buffer... */
+    int i;
+    XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+    XClearWindow (dpy, window);
+    for (i = 0; i < st->count; i++)
+      if (st->throbbers[i])
+        st->throbbers[i]->fuse = 0;
+  }
 }
+
+static Bool
+deluxe_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
+}
+
+static void
+deluxe_free (Display *dpy, Window window, void *closure)
+{
+}
+
+
+static const char *deluxe_defaults [] = {
+  ".background:                black",
+  ".foreground:                white",
+  "*delay:             5000",
+  "*count:             5",
+  "*thickness:         50",
+  "*speed:             15",
+  "*ncolors:           20",
+  "*transparent:       True",
+  "*doubleBuffer:      True",
+#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
+  "*useDBE:            True",
+  "*useDBEClear:       True",
+#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
+  0
+};
+
+static XrmOptionDescRec deluxe_options [] = {
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { "-thickness",      ".thickness",   XrmoptionSepArg, 0 },
+  { "-count",          ".count",       XrmoptionSepArg, 0 },
+  { "-ncolors",                ".ncolors",     XrmoptionSepArg, 0 },
+  { "-speed",          ".speed",       XrmoptionSepArg, 0 },
+  { "-transparent",    ".transparent",  XrmoptionNoArg,  "True"  },
+  { "-no-transparent", ".transparent",  XrmoptionNoArg,  "False" },
+  { "-opaque",         ".transparent",  XrmoptionNoArg,  "False" },
+  { "-no-opaque",      ".transparent",  XrmoptionNoArg,  "True"  },
+  { "-db",             ".doubleBuffer", XrmoptionNoArg,  "True"  },
+  { "-no-db",          ".doubleBuffer", XrmoptionNoArg,  "False" },
+  { 0, 0, 0, 0 }
+};
+
+
+XSCREENSAVER_MODULE ("Deluxe", deluxe)