-/* xscreensaver, Copyright (c) 1999, 2001, 2002 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1999-2013 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;
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;
int y = t->y;
- int s = t->size / 0.383; /* trial and error, I forget how to derive this */
+
+ /*
+ The following constant is really:
+ sqrt(5 - sqrt(5)) / sqrt(25 - 11 * sqrt(5))
+
+ Reference: http://mathworld.wolfram.com/Pentagram.html
+ */
+ int s = t->size * 2.6180339887498985;
int s2 = t->size;
double c = M_PI * 2;
double o = -M_PI / 2;
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,
}
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];
- 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);
-
- 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);
-
- 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);
-
- 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);
+ if (t->y > s)
+ {
+ 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 (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 (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
+ }
+
+ if (t->x > s)
+ {
+ 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 (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 (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;
struct throbber *t = (struct throbber *) malloc (sizeof (*t));
t->x = w / 2;
t->y = h / 2;
- t->max_size = w;
- t->speed = get_integer_resource ("speed", "Speed");
+ t->max_size = (w > h ? w : h);
+ 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));
if (t->speed > 0) t->speed = -t->speed;
- if (random() % 4)
- t->size = t->max_size;
- else
- 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;
default: abort(); break;
}
+ if (t->draw == draw_circle)
+ t->max_size *= 1.5;
+
+ if (random() % 4)
+ t->size = t->max_size;
+ else
+ t->size = t->thickness, t->speed = -t->speed;
+
return t;
}
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))
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
- XGetWindowAttributes (dpy, window, &xgwa);
+# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
+ st->dbuf = False;
+# endif
- transparent_p = get_boolean_resource("transparent", "Transparent");
+ XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
- colors = (XColor *) calloc (sizeof(*colors), ncolors);
+ st->transparent_p = get_boolean_resource(st->dpy, "transparent", "Transparent");
- if (get_boolean_resource("mono", "Boolean"))
+ st->colors = (XColor *) calloc (sizeof(*st->colors), st->ncolors);
+
+ 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->xgwa.screen, 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: 10000",
+ "*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 */
+#ifdef USE_IPHONE
+ "*ignoreRotation: True",
+#endif
+ 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)