ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-5.01.tar.gz
[xscreensaver] / hacks / goop.c
index 8619c9ffb88d0b7958c346d9e3de673aa091d81f..b7670e7cf3fbcb7176b20998f52b342eeabf7e63 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@netscape.com>
+/* 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
@@ -44,7 +44,6 @@
    blobs could have thickness, and curved edges with specular reflections...
  */
 
-
 #define SCALE       10000  /* fixed-point math, for sub-pixel motion */
 #define DEF_COUNT   12    /* When planes and count are 0, how many blobs. */
 
@@ -89,11 +88,14 @@ struct goop {
   Pixmap pixmap;
   GC pixmap_gc;
   GC window_gc;
+  Bool additive_p;
+  Bool cmap_p;
+  int delay;
 };
 
 
 static struct blob *
-make_blob (int maxx, int maxy, int size)
+make_blob (Display *dpy, int maxx, int maxy, int size)
 {
   struct blob *b = (struct blob *) calloc(1, sizeof(*b));
   int i;
@@ -109,9 +111,9 @@ make_blob (int maxx, int maxy, int size)
   if (b->min_r < (5*SCALE)) b->min_r = (5*SCALE);
   mid = ((b->min_r + b->max_r) / 2);
 
-  b->torque       = get_float_resource ("torque", "Torque");
-  b->elasticity   = SCALE * get_float_resource ("elasticity", "Elasticity");
-  b->max_velocity = SCALE * get_float_resource ("maxVelocity", "MaxVelocity");
+  b->torque       = get_float_resource (dpy, "torque", "Torque");
+  b->elasticity   = SCALE * get_float_resource (dpy, "elasticity", "Elasticity");
+  b->max_velocity = SCALE * get_float_resource (dpy, "maxVelocity", "MaxVelocity");
 
   b->x = RAND(maxx);
   b->y = RAND(maxy);
@@ -256,23 +258,28 @@ make_layer (Display *dpy, Window window, int width, int height, int nblobs)
 
   blob_max = (width < height ? width : height) / 2;
   blob_min = (blob_max * 2) / 3;
-  for (i = 0; i < layer->nblobs; i++)
-    layer->blobs[i] = make_blob (width, height,
-                                (random() % (blob_max-blob_min)) + blob_min);
+  for (i = 0; i < layer->nblobs; i++){
+    int j = blob_max - blob_min;
+    layer->blobs[i] = make_blob (dpy, width, height,
+                                (j ? random() % j : 0) + blob_min);
+  }
 
   layer->pixmap = XCreatePixmap (dpy, window, width, height, 1);
   layer->gc = XCreateGC (dpy, layer->pixmap, 0, &gcv);
 
+# ifdef HAVE_COCOA
+  jwxyz_XSetAlphaAllowed (dpy, layer->gc, True);
+# endif /* HAVE_COCOA */
+
   return layer;
 }
 
+
+#ifndef HAVE_COCOA
 static void
 draw_layer_plane (Display *dpy, struct layer *layer, int width, int height)
 {
   int i;
-  XSetForeground (dpy, layer->gc, 1L);
-  XFillRectangle (dpy, layer->pixmap, layer->gc, 0, 0, width, height);
-  XSetForeground (dpy, layer->gc, 0L);
   for (i = 0; i < layer->nblobs; i++)
     {
       throb_blob (layer->blobs[i]);
@@ -280,6 +287,7 @@ draw_layer_plane (Display *dpy, struct layer *layer, int width, int height)
       draw_blob (dpy, layer->pixmap, layer->gc, layer->blobs[i], True);
     }
 }
+#endif /* !HAVE_COCOA */
 
 
 static void
@@ -290,51 +298,64 @@ draw_layer_blobs (Display *dpy, Drawable drawable, GC gc,
   int i;
   for (i = 0; i < layer->nblobs; i++)
     {
+      draw_blob (dpy, drawable, gc, layer->blobs[i], fill_p);
       throb_blob (layer->blobs[i]);
       move_blob (layer->blobs[i], width, height);
-      draw_blob (dpy, drawable, gc, layer->blobs[i], fill_p);
     }
 }
 
 
 static struct goop *
-make_goop (Display *dpy, Window window, Colormap cmap,
+make_goop (Screen *screen, Visual *visual, Window window, Colormap cmap,
           int width, int height, long depth)
 {
+  Display *dpy = DisplayOfScreen (screen);
   int i;
   struct goop *goop = (struct goop *) calloc(1, sizeof(*goop));
   XGCValues gcv;
-  int nblobs = get_integer_resource ("count", "Count");
+  int nblobs = get_integer_resource (dpy, "count", "Count");
 
   unsigned long *plane_masks = 0;
+# ifndef HAVE_COCOA
   unsigned long base_pixel = 0;
+# endif
+  char *s;
+
+  s = get_string_resource (dpy, "mode", "Mode");
+  goop->mode = transparent;
+  if (!s || !*s || !strcasecmp (s, "transparent"))
+    ;
+  else if (!strcasecmp (s, "opaque"))
+    goop->mode = opaque;
+  else if (!strcasecmp (s, "xor"))
+    goop->mode = xor;
+  else
+    fprintf (stderr, "%s: bogus mode: \"%s\"\n", progname, s);
 
-  goop->mode = (get_boolean_resource("xor", "Xor")
-               ? xor
-               : (get_boolean_resource("transparent", "Transparent")
-                  ? transparent
-                  : opaque));
+  goop->delay = get_integer_resource (dpy, "delay", "Integer");
 
   goop->width = width;
   goop->height = height;
 
-
-  goop->nlayers = get_integer_resource ("planes", "Planes");
+  goop->nlayers = get_integer_resource (dpy, "planes", "Planes");
   if (goop->nlayers <= 0)
     goop->nlayers = (random() % (depth-2)) + 2;
   goop->layers = (struct layer **) malloc(sizeof(*goop->layers)*goop->nlayers);
 
+  goop->additive_p = get_boolean_resource (dpy, "additive", "Additive");
+  goop->cmap_p = has_writable_cells (screen, visual);
 
   if (mono_p && goop->mode == transparent)
     goop->mode = opaque;
 
+# ifndef HAVE_COCOA
   /* Try to allocate some color planes before committing to nlayers.
    */
   if (goop->mode == transparent)
     {
-      Bool additive_p = get_boolean_resource ("additive", "Additive");
       int nplanes = goop->nlayers;
-      allocate_alpha_colors (dpy, cmap, &nplanes, additive_p, &plane_masks,
+      allocate_alpha_colors (screen, visual, cmap,
+                             &nplanes, goop->additive_p, &plane_masks,
                             &base_pixel);
       if (nplanes > 1)
        goop->nlayers = nplanes;
@@ -346,6 +367,7 @@ make_goop (Display *dpy, Window window, Colormap cmap,
          goop->mode = opaque;
        }
     }
+# endif /* !HAVE_COCOA */
 
   {
     int lblobs[32];
@@ -360,22 +382,27 @@ make_goop (Display *dpy, Window window, Colormap cmap,
                                    (nblobs > 0 ? nblobs : lblobs[i]));
   }
 
+# ifndef HAVE_COCOA
   if (goop->mode == transparent && plane_masks)
     {
       for (i = 0; i < goop->nlayers; i++)
        goop->layers[i]->pixel = base_pixel | plane_masks[i];
       goop->background = base_pixel;
     }
+# endif /* !HAVE_COCOA */
+
   if (plane_masks)
     free (plane_masks);
 
+# ifndef HAVE_COCOA
   if (goop->mode != transparent)
+# endif /* !HAVE_COCOA */
     {
       XColor color;
       color.flags = DoRed|DoGreen|DoBlue;
 
       goop->background =
-       get_pixel_resource ("background", "Background", dpy,cmap);
+       get_pixel_resource (dpy,cmap, "background", "Background");
 
       for (i = 0; i < goop->nlayers; i++)
        {
@@ -388,6 +415,17 @@ make_goop (Display *dpy, Window window, Colormap cmap,
          else
            goop->layers[i]->pixel =
              WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
+# ifdef HAVE_COCOA
+          if (goop->mode == transparent)
+            {
+              /* give a non-opaque alpha to the color */
+              unsigned long pixel = goop->layers[i]->pixel;
+              unsigned long amask = BlackPixelOfScreen (0);
+              unsigned long a = (0xBBBBBBBB & amask);
+              pixel = (pixel & (~amask)) | a;
+              goop->layers[i]->pixel = pixel;
+            }
+# endif /* HAVE_COCOA */
        }
     }
 
@@ -395,50 +433,62 @@ make_goop (Display *dpy, Window window, Colormap cmap,
                                (goop->mode == xor ? 1L : depth));
 
   gcv.background = goop->background;
-  gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
-  gcv.line_width = get_integer_resource ("thickness","Thickness");
+  gcv.foreground = get_pixel_resource (dpy, cmap, "foreground", "Foreground");
+  gcv.line_width = get_integer_resource (dpy, "thickness","Thickness");
   goop->pixmap_gc = XCreateGC (dpy, goop->pixmap, GCLineWidth, &gcv);
   goop->window_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
 
+# ifdef HAVE_COCOA
+  jwxyz_XSetAlphaAllowed (dpy, goop->pixmap_gc, True);
+# endif /* HAVE_COCOA */
+  
   return goop;
 }
 
-static struct goop *
-init_goop (Display *dpy, Window window)
+static void *
+goop_init (Display *dpy, Window window)
 {
   XWindowAttributes xgwa;
   XGetWindowAttributes (dpy, window, &xgwa);
-
-  return make_goop (dpy, window, xgwa.colormap,
+  return make_goop (xgwa.screen, xgwa.visual, window, xgwa.colormap,
                    xgwa.width, xgwa.height, xgwa.depth);
 }
 
-static void
-run_goop (Display *dpy, Window window, struct goop *goop)
+static unsigned long
+goop_draw (Display *dpy, Window window, void *closure)
 {
+  struct goop *goop = (struct goop *) closure;
   int i;
 
   switch (goop->mode)
     {
+# ifndef HAVE_COCOA
     case transparent:
 
       for (i = 0; i < goop->nlayers; i++)
        draw_layer_plane (dpy, goop->layers[i], goop->width, goop->height);
 
       XSetForeground (dpy, goop->pixmap_gc, goop->background);
+      XSetFunction (dpy, goop->pixmap_gc, GXcopy);
       XSetPlaneMask (dpy, goop->pixmap_gc, AllPlanes);
       XFillRectangle (dpy, goop->pixmap, goop->pixmap_gc, 0, 0,
                      goop->width, goop->height);
+
       XSetForeground (dpy, goop->pixmap_gc, ~0L);
+
+      if (!goop->cmap_p && !goop->additive_p)
+        {
+          int j;
+          for (i = 0; i < goop->nlayers; i++)
+            for (j = 0; j < goop->layers[i]->nblobs; j++)
+              draw_blob (dpy, goop->pixmap, goop->pixmap_gc,
+                         goop->layers[i]->blobs[j], True);
+          XSetFunction (dpy, goop->pixmap_gc, GXclear);
+        }
+
       for (i = 0; i < goop->nlayers; i++)
        {
          XSetPlaneMask (dpy, goop->pixmap_gc, goop->layers[i]->pixel);
-/*
-         XSetForeground (dpy, goop->pixmap_gc, ~0L);
-         XFillRectangle (dpy, goop->pixmap, goop->pixmap_gc, 0, 0,
-                         goop->width, goop->height);
-         XSetForeground (dpy, goop->pixmap_gc, 0L);
- */
          draw_layer_blobs (dpy, goop->pixmap, goop->pixmap_gc,
                            goop->layers[i], goop->width, goop->height,
                            True);
@@ -446,6 +496,7 @@ run_goop (Display *dpy, Window window, struct goop *goop)
       XCopyArea (dpy, goop->pixmap, window, goop->window_gc, 0, 0,
                 goop->width, goop->height, 0, 0);
       break;
+#endif /* !HAVE_COCOA */
 
     case xor:
       XSetFunction (dpy, goop->pixmap_gc, GXcopy);
@@ -462,6 +513,9 @@ run_goop (Display *dpy, Window window, struct goop *goop)
                  goop->width, goop->height, 0, 0, 1L);
       break;
 
+# ifdef HAVE_COCOA
+    case transparent:
+# endif
     case opaque:
     case outline:
       XSetForeground (dpy, goop->pixmap_gc, goop->background);
@@ -482,37 +536,55 @@ run_goop (Display *dpy, Window window, struct goop *goop)
       abort ();
       break;
     }
+  return goop->delay;
+}
+
+static void
+goop_reshape (Display *dpy, Window window, void *closure, 
+                 unsigned int w, unsigned int h)
+{
+  /* #### write me */
+}
+
+static Bool
+goop_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+  return False;
 }
 
+static void
+goop_free (Display *dpy, Window window, void *closure)
+{
+}
+
+
 \f
-char *progclass = "Goop";
 
-char *defaults [] = {
+static const char *goop_defaults [] = {
   ".background:                black",
-  ".foreground:                white",
+  ".foreground:                yellow",
   "*delay:             12000",
-  "*transparent:       true",
   "*additive:          true",
-  "*xor:               false",
+  "*mode:              transparent",
   "*count:             0",
   "*planes:            0",
   "*thickness:         5",
   "*torque:            0.0075",
-  "*elasticity:                1.8",
-  "*maxVelocity:       1.2",
+  "*elasticity:                0.9",
+  "*maxVelocity:       0.5",
   0
 };
 
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec goop_options [] = {
   { "-delay",          ".delay",       XrmoptionSepArg, 0 },
   { "-count",          ".count",       XrmoptionSepArg, 0 },
   { "-planes",         ".planes",      XrmoptionSepArg, 0 },
-  { "-transparent",    ".transparent", XrmoptionNoArg, "True" },
-  { "-non-transparent",        ".transparent", XrmoptionNoArg, "False" },
+  { "-mode",           ".mode",        XrmoptionSepArg, 0 },
+  { "-xor",            ".mode",        XrmoptionNoArg, "xor" },
+  { "-transparent",    ".mode",        XrmoptionNoArg, "transparent" },
+  { "-opaque",         ".mode",        XrmoptionNoArg, "opaque" },
   { "-additive",       ".additive",    XrmoptionNoArg, "True" },
   { "-subtractive",    ".additive",    XrmoptionNoArg, "false" },
-  { "-xor",            ".xor",         XrmoptionNoArg, "true" },
-  { "-no-xor",         ".xor",         XrmoptionNoArg, "false" },
   { "-thickness",      ".thickness",   XrmoptionSepArg, 0 },
   { "-torque",         ".torque",      XrmoptionSepArg, 0 },
   { "-elasticity",     ".elasticity",  XrmoptionSepArg, 0 },
@@ -520,15 +592,4 @@ XrmOptionDescRec options [] = {
   { 0, 0, 0, 0 }
 };
 
-void
-screenhack (Display *dpy, Window window)
-{
-  struct goop *g = init_goop (dpy, window);
-  int delay = get_integer_resource ("delay", "Integer");
-  while (1)
-    {
-      run_goop (dpy, window, g);
-      XSync (dpy, True);
-      if (delay) usleep (delay);
-    }
-}
+XSCREENSAVER_MODULE ("Goop", goop)