1 /* xscreensaver, Copyright (c) 1999-2012 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)
65 int s = t->size / 0.383; /* trial and error, I forget how to derive this */
70 points[0].x = x + s * cos(o + 0.0*c); points[0].y = y + s * sin(o + 0.0*c);
71 points[1].x = x + s2 * cos(o + 0.1*c); points[1].y = y + s2 * sin(o + 0.1*c);
72 points[2].x = x + s * cos(o + 0.2*c); points[2].y = y + s * sin(o + 0.2*c);
73 points[3].x = x + s2 * cos(o + 0.3*c); points[3].y = y + s2 * sin(o + 0.3*c);
74 points[4].x = x + s * cos(o + 0.4*c); points[4].y = y + s * sin(o + 0.4*c);
75 points[5].x = x + s2 * cos(o + 0.5*c); points[5].y = y + s2 * sin(o + 0.5*c);
76 points[6].x = x + s * cos(o + 0.6*c); points[6].y = y + s * sin(o + 0.6*c);
77 points[7].x = x + s2 * cos(o + 0.7*c); points[7].y = y + s2 * sin(o + 0.7*c);
78 points[8].x = x + s * cos(o + 0.8*c); points[8].y = y + s * sin(o + 0.8*c);
79 points[9].x = x + s2 * cos(o + 0.9*c); points[9].y = y + s2 * sin(o + 0.9*c);
80 points[10] = points[0];
82 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
86 draw_circle (struct state *st, Drawable w, struct throbber *t)
88 XDrawArc (st->dpy, w, t->gc,
96 draw_hlines (struct state *st, Drawable w, struct throbber *t)
98 XDrawLine (st->dpy, w, t->gc, 0,
99 t->y - t->size, t->max_size,
101 XDrawLine (st->dpy, w, t->gc, 0,
102 t->y + t->size, t->max_size,
107 draw_vlines (struct state *st, Drawable w, struct throbber *t)
109 XDrawLine (st->dpy, w, t->gc,
111 t->x - t->size, t->max_size);
112 XDrawLine (st->dpy, w, t->gc,
114 t->x + t->size, t->max_size);
118 draw_corners (struct state *st, Drawable w, struct throbber *t)
120 int s = (t->size + t->thickness) / 2;
125 points[0].x = 0; points[0].y = t->y - s;
126 points[1].x = t->x - s; points[1].y = t->y - s;
127 points[2].x = t->x - s; points[2].y = 0;
128 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
130 points[0].x = t->x + s; points[0].y = 0;
131 points[1].x = t->x + s; points[1].y = t->y - s;
132 points[2].x = t->max_size; points[2].y = t->y - s;
133 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
138 points[0].x = 0; points[0].y = t->y + s;
139 points[1].x = t->x - s; points[1].y = t->y + s;
140 points[2].x = t->x - s; points[2].y = t->max_size;
141 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
143 points[0].x = t->x + s; points[0].y = t->max_size;
144 points[1].x = t->x + s; points[1].y = t->y + s;
145 points[2].x = t->max_size; points[2].y = t->y + s;
146 XDrawLines (st->dpy, w, t->gc, points, countof(points), CoordModeOrigin);
151 static struct throbber *
152 make_throbber (struct state *st, Drawable d, int w, int h, unsigned long pixel)
156 struct throbber *t = (struct throbber *) malloc (sizeof (*t));
159 t->max_size = (w > h ? w : h);
160 t->speed = get_integer_resource (st->dpy, "speed", "Speed");
161 t->fuse = 1 + (random() % 4);
162 t->thickness = get_integer_resource (st->dpy, "thickness", "Thickness");
164 if (t->speed < 0) t->speed = -t->speed;
165 t->speed += (((random() % t->speed) / 2) - (t->speed / 2));
166 if (t->speed > 0) t->speed = -t->speed;
168 flags = GCForeground;
170 if (st->transparent_p)
172 gcv.foreground = ~0L;
173 gcv.plane_mask = st->base_pixel | st->plane_masks[random() % st->nplanes];
174 flags |= GCPlaneMask;
177 # endif /* !HAVE_COCOA */
179 gcv.foreground = pixel;
182 gcv.line_width = t->thickness;
183 gcv.cap_style = CapProjecting;
184 gcv.join_style = JoinMiter;
186 flags |= (GCLineWidth | GCCapStyle | GCJoinStyle);
187 t->gc = XCreateGC (st->dpy, d, flags, &gcv);
190 if (st->transparent_p)
192 /* give a non-opaque alpha to the color */
193 unsigned long pixel = gcv.foreground;
194 unsigned long amask = BlackPixelOfScreen (st->xgwa.screen);
195 unsigned long a = (0xCCCCCCCC & amask);
196 pixel = (pixel & (~amask)) | a;
198 jwxyz_XSetAlphaAllowed (st->dpy, t->gc, True);
199 XSetForeground (st->dpy, t->gc, pixel);
201 # endif /* HAVE_COCOA */
203 switch (random() % 11) {
204 case 0: case 1: case 2: case 3: t->draw = draw_star; break;
205 case 4: case 5: case 6: case 7: t->draw = draw_circle; break;
206 case 8: t->draw = draw_hlines; break;
207 case 9: t->draw = draw_vlines; break;
208 case 10: t->draw = draw_corners; break;
209 default: abort(); break;
212 if (t->draw == draw_circle)
216 t->size = t->max_size;
218 t->size = t->thickness, t->speed = -t->speed;
224 throb (struct state *st, Drawable window, struct throbber *t)
227 if (t->size <= (t->thickness / 2))
229 t->speed = -t->speed;
230 t->size += (t->speed * 2);
232 else if (t->size > t->max_size)
234 t->speed = -t->speed;
235 t->size += (t->speed * 2);
241 XFreeGC (st->dpy, t->gc);
242 memset (t, 0, sizeof(*t));
248 t->draw (st, window, t);
255 deluxe_init (Display *dpy, Window window)
257 struct state *st = (struct state *) calloc (1, sizeof(*st));
262 st->count = get_integer_resource (st->dpy, "count", "Integer");
263 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
264 st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
265 st->dbuf = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean");
267 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
268 st->dbeclear_p = get_boolean_resource (st->dpy, "useDBEClear", "Boolean");
271 # ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
275 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
277 st->transparent_p = get_boolean_resource(st->dpy, "transparent", "Transparent");
279 st->colors = (XColor *) calloc (sizeof(*st->colors), st->ncolors);
281 if (get_boolean_resource(st->dpy, "mono", "Boolean"))
285 st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap,
286 "foreground", "Foreground");
289 else if (st->transparent_p)
291 st->nplanes = get_integer_resource (st->dpy, "planes", "Planes");
292 if (st->nplanes <= 0)
293 st->nplanes = (random() % (st->xgwa.depth-2)) + 2;
295 allocate_alpha_colors (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
296 &st->nplanes, True, &st->plane_masks,
298 if (st->nplanes <= 1)
302 "%s: couldn't allocate any color planes; turning transparency off.\n",
305 st->transparent_p = False;
309 #endif /* !HAVE_COCOA */
315 make_random_colormap (st->dpy, st->xgwa.visual, st->xgwa.colormap,
316 st->colors, &st->ncolors, True, True, 0, True);
323 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
325 st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeBackground);
327 st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
329 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
333 st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
334 st->bb = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
343 st->throbbers = (struct throbber **) calloc (st->count, sizeof(struct throbber *));
344 for (i = 0; i < st->count; i++)
345 st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
346 st->colors[random() % st->ncolors].pixel);
348 gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
349 "background", "Background");
350 st->erase_gc = XCreateGC (st->dpy, st->b, GCForeground, &gcv);
352 if (st->ba) XFillRectangle (st->dpy, st->ba, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
353 if (st->bb) XFillRectangle (st->dpy, st->bb, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
359 deluxe_draw (Display *dpy, Window window, void *closure)
361 struct state *st = (struct state *) closure;
363 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
364 if (!st->dbeclear_p || !st->backb)
365 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
366 XFillRectangle (st->dpy, st->b, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
368 for (i = 0; i < st->count; i++)
369 if (throb (st, st->b, st->throbbers[i]) < 0)
370 st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
371 st->colors[random() % st->ncolors].pixel);
373 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
376 XdbeSwapInfo info[1];
377 info[0].swap_window = st->window;
378 info[0].swap_action = (st->dbeclear_p ? XdbeBackground : XdbeUndefined);
379 XdbeSwapBuffers (st->dpy, info, 1);
382 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
385 XCopyArea (st->dpy, st->b, st->window, st->erase_gc, 0, 0,
386 st->xgwa.width, st->xgwa.height, 0, 0);
387 st->b = (st->b == st->ba ? st->bb : st->ba);
394 deluxe_reshape (Display *dpy, Window window, void *closure,
395 unsigned int w, unsigned int h)
397 struct state *st = (struct state *) closure;
398 if (! st->dbuf) { /* #### more complicated if we have a back buffer... */
400 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
401 XClearWindow (dpy, window);
402 for (i = 0; i < st->count; i++)
403 if (st->throbbers[i])
404 st->throbbers[i]->fuse = 0;
409 deluxe_event (Display *dpy, Window window, void *closure, XEvent *event)
415 deluxe_free (Display *dpy, Window window, void *closure)
420 static const char *deluxe_defaults [] = {
421 ".background: black",
422 ".foreground: white",
428 "*transparent: True",
429 "*doubleBuffer: True",
430 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
432 "*useDBEClear: True",
433 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
437 static XrmOptionDescRec deluxe_options [] = {
438 { "-delay", ".delay", XrmoptionSepArg, 0 },
439 { "-thickness", ".thickness", XrmoptionSepArg, 0 },
440 { "-count", ".count", XrmoptionSepArg, 0 },
441 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
442 { "-speed", ".speed", XrmoptionSepArg, 0 },
443 { "-transparent", ".transparent", XrmoptionNoArg, "True" },
444 { "-no-transparent", ".transparent", XrmoptionNoArg, "False" },
445 { "-opaque", ".transparent", XrmoptionNoArg, "False" },
446 { "-no-opaque", ".transparent", XrmoptionNoArg, "True" },
447 { "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
448 { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
453 XSCREENSAVER_MODULE ("Deluxe", deluxe)