1 /* xscreensaver, Copyright (c) 1999-2013 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
13 #include "screenhack.h"
16 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
18 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
20 #define countof(x) (sizeof(x)/sizeof(*(x)))
21 #define ABS(x) ((x)<0?-(x):(x))
29 unsigned long base_pixel, *plane_masks;
37 struct throbber **throbbers;
38 XWindowAttributes xgwa;
39 Pixmap b, ba, bb; /* double-buffer to reduce flicker */
41 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
44 # endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
55 void (*draw) (struct state *, Drawable, struct throbber *);
60 draw_star (struct state *st, Drawable w, struct throbber *t)
67 The following constant is really:
68 sqrt(5 - sqrt(5)) / sqrt(25 - 11 * sqrt(5))
70 Reference: http://mathworld.wolfram.com/Pentagram.html
72 int s = t->size * 2.6180339887498985;
77 points[0].x = x + s * cos(o + 0.0*c); points[0].y = y + s * sin(o + 0.0*c);
78 points[1].x = x + s2 * cos(o + 0.1*c); points[1].y = y + s2 * sin(o + 0.1*c);
79 points[2].x = x + s * cos(o + 0.2*c); points[2].y = y + s * sin(o + 0.2*c);
80 points[3].x = x + s2 * cos(o + 0.3*c); points[3].y = y + s2 * sin(o + 0.3*c);
81 points[4].x = x + s * cos(o + 0.4*c); points[4].y = y + s * sin(o + 0.4*c);
82 points[5].x = x + s2 * cos(o + 0.5*c); points[5].y = y + s2 * sin(o + 0.5*c);
83 points[6].x = x + s * cos(o + 0.6*c); points[6].y = y + s * sin(o + 0.6*c);
84 points[7].x = x + s2 * cos(o + 0.7*c); points[7].y = y + s2 * sin(o + 0.7*c);
85 points[8].x = x + s * cos(o + 0.8*c); points[8].y = y + s * sin(o + 0.8*c);
86 points[9].x = x + s2 * cos(o + 0.9*c); points[9].y = y + s2 * sin(o + 0.9*c);
87 points[10] = points[0];
89 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
93 draw_circle (struct state *st, Drawable w, struct throbber *t)
95 XDrawArc (st->dpy, w, t->gc,
103 draw_hlines (struct state *st, Drawable w, struct throbber *t)
105 XDrawLine (st->dpy, w, t->gc, 0,
106 t->y - t->size, t->max_size,
108 XDrawLine (st->dpy, w, t->gc, 0,
109 t->y + t->size, t->max_size,
114 draw_vlines (struct state *st, Drawable w, struct throbber *t)
116 XDrawLine (st->dpy, w, t->gc,
118 t->x - t->size, t->max_size);
119 XDrawLine (st->dpy, w, t->gc,
121 t->x + t->size, t->max_size);
125 draw_corners (struct state *st, Drawable w, struct throbber *t)
127 int s = (t->size + t->thickness) / 2;
132 points[0].x = 0; points[0].y = t->y - s;
133 points[1].x = t->x - s; points[1].y = t->y - s;
134 points[2].x = t->x - s; points[2].y = 0;
135 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
137 points[0].x = t->x + s; points[0].y = 0;
138 points[1].x = t->x + s; points[1].y = t->y - s;
139 points[2].x = t->max_size; points[2].y = t->y - s;
140 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
145 points[0].x = 0; points[0].y = t->y + s;
146 points[1].x = t->x - s; points[1].y = t->y + s;
147 points[2].x = t->x - s; points[2].y = t->max_size;
148 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
150 points[0].x = t->x + s; points[0].y = t->max_size;
151 points[1].x = t->x + s; points[1].y = t->y + s;
152 points[2].x = t->max_size; points[2].y = t->y + s;
153 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
158 static struct throbber *
159 make_throbber (struct state *st, Drawable d, int w, int h, unsigned long pixel)
163 struct throbber *t = (struct throbber *) malloc (sizeof (*t));
166 t->max_size = (w > h ? w : h);
167 t->speed = get_integer_resource (st->dpy, "speed", "Speed");
168 t->fuse = 1 + (random() % 4);
169 t->thickness = get_integer_resource (st->dpy, "thickness", "Thickness");
171 if (t->speed < 0) t->speed = -t->speed;
172 t->speed += (((random() % t->speed) / 2) - (t->speed / 2));
173 if (t->speed > 0) t->speed = -t->speed;
175 flags = GCForeground;
177 if (st->transparent_p)
179 gcv.foreground = ~0L;
180 gcv.plane_mask = st->base_pixel | st->plane_masks[random() % st->nplanes];
181 flags |= GCPlaneMask;
184 # endif /* !HAVE_COCOA */
186 gcv.foreground = pixel;
189 gcv.line_width = t->thickness;
190 gcv.cap_style = CapProjecting;
191 gcv.join_style = JoinMiter;
193 flags |= (GCLineWidth | GCCapStyle | GCJoinStyle);
194 t->gc = XCreateGC (st->dpy, d, flags, &gcv);
197 if (st->transparent_p)
199 /* give a non-opaque alpha to the color */
200 unsigned long pixel = gcv.foreground;
201 unsigned long amask = BlackPixelOfScreen (st->xgwa.screen);
202 unsigned long a = (0xCCCCCCCC & amask);
203 pixel = (pixel & (~amask)) | a;
205 jwxyz_XSetAlphaAllowed (st->dpy, t->gc, True);
206 XSetForeground (st->dpy, t->gc, pixel);
208 # endif /* HAVE_COCOA */
210 switch (random() % 11) {
211 case 0: case 1: case 2: case 3: t->draw = draw_star; break;
212 case 4: case 5: case 6: case 7: t->draw = draw_circle; break;
213 case 8: t->draw = draw_hlines; break;
214 case 9: t->draw = draw_vlines; break;
215 case 10: t->draw = draw_corners; break;
216 default: abort(); break;
219 if (t->draw == draw_circle)
223 t->size = t->max_size;
225 t->size = t->thickness, t->speed = -t->speed;
231 throb (struct state *st, Drawable window, struct throbber *t)
234 if (t->size <= (t->thickness / 2))
236 t->speed = -t->speed;
237 t->size += (t->speed * 2);
239 else if (t->size > t->max_size)
241 t->speed = -t->speed;
242 t->size += (t->speed * 2);
248 XFreeGC (st->dpy, t->gc);
249 memset (t, 0, sizeof(*t));
255 t->draw (st, window, t);
262 deluxe_init (Display *dpy, Window window)
264 struct state *st = (struct state *) calloc (1, sizeof(*st));
269 st->count = get_integer_resource (st->dpy, "count", "Integer");
270 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
271 st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
272 st->dbuf = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean");
274 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
275 st->dbeclear_p = get_boolean_resource (st->dpy, "useDBEClear", "Boolean");
278 # ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
282 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
284 st->transparent_p = get_boolean_resource(st->dpy, "transparent", "Transparent");
286 st->colors = (XColor *) calloc (sizeof(*st->colors), st->ncolors);
288 if (get_boolean_resource(st->dpy, "mono", "Boolean"))
292 st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap,
293 "foreground", "Foreground");
296 else if (st->transparent_p)
298 st->nplanes = get_integer_resource (st->dpy, "planes", "Planes");
299 if (st->nplanes <= 0)
300 st->nplanes = (random() % (st->xgwa.depth-2)) + 2;
302 allocate_alpha_colors (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
303 &st->nplanes, True, &st->plane_masks,
305 if (st->nplanes <= 1)
309 "%s: couldn't allocate any color planes; turning transparency off.\n",
312 st->transparent_p = False;
316 #endif /* !HAVE_COCOA */
322 make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
323 st->colors, &st->ncolors, True, True, 0, True);
330 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
332 st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeBackground);
334 st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
336 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
340 st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
341 st->bb = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
350 st->throbbers = (struct throbber **) calloc (st->count, sizeof(struct throbber *));
351 for (i = 0; i < st->count; i++)
352 st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
353 st->colors[random() % st->ncolors].pixel);
355 gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
356 "background", "Background");
357 st->erase_gc = XCreateGC (st->dpy, st->b, GCForeground, &gcv);
359 if (st->ba) XFillRectangle (st->dpy, st->ba, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
360 if (st->bb) XFillRectangle (st->dpy, st->bb, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
366 deluxe_draw (Display *dpy, Window window, void *closure)
368 struct state *st = (struct state *) closure;
370 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
371 if (!st->dbeclear_p || !st->backb)
372 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
373 XFillRectangle (st->dpy, st->b, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
375 for (i = 0; i < st->count; i++)
376 if (throb (st, st->b, st->throbbers[i]) < 0)
377 st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
378 st->colors[random() % st->ncolors].pixel);
380 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
383 XdbeSwapInfo info[1];
384 info[0].swap_window = st->window;
385 info[0].swap_action = (st->dbeclear_p ? XdbeBackground : XdbeUndefined);
386 XdbeSwapBuffers (st->dpy, info, 1);
389 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
392 XCopyArea (st->dpy, st->b, st->window, st->erase_gc, 0, 0,
393 st->xgwa.width, st->xgwa.height, 0, 0);
394 st->b = (st->b == st->ba ? st->bb : st->ba);
401 deluxe_reshape (Display *dpy, Window window, void *closure,
402 unsigned int w, unsigned int h)
404 struct state *st = (struct state *) closure;
405 if (! st->dbuf) { /* #### more complicated if we have a back buffer... */
407 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
408 XClearWindow (dpy, window);
409 for (i = 0; i < st->count; i++)
410 if (st->throbbers[i])
411 st->throbbers[i]->fuse = 0;
416 deluxe_event (Display *dpy, Window window, void *closure, XEvent *event)
422 deluxe_free (Display *dpy, Window window, void *closure)
427 static const char *deluxe_defaults [] = {
428 ".background: black",
429 ".foreground: white",
435 "*transparent: True",
436 "*doubleBuffer: True",
437 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
439 "*useDBEClear: True",
440 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
442 "*ignoreRotation: True",
447 static XrmOptionDescRec deluxe_options [] = {
448 { "-delay", ".delay", XrmoptionSepArg, 0 },
449 { "-thickness", ".thickness", XrmoptionSepArg, 0 },
450 { "-count", ".count", XrmoptionSepArg, 0 },
451 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
452 { "-speed", ".speed", XrmoptionSepArg, 0 },
453 { "-transparent", ".transparent", XrmoptionNoArg, "True" },
454 { "-no-transparent", ".transparent", XrmoptionNoArg, "False" },
455 { "-opaque", ".transparent", XrmoptionNoArg, "False" },
456 { "-no-opaque", ".transparent", XrmoptionNoArg, "True" },
457 { "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
458 { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
463 XSCREENSAVER_MODULE ("Deluxe", deluxe)