1 /* xscreensaver, Copyright (c) 1999-2018 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 (st->xgwa.width > 2560) t->thickness *= 3; /* Retina displays */
173 if (t->speed < 0) t->speed = -t->speed;
174 t->speed += (((random() % t->speed) / 2) - (t->speed / 2));
175 if (t->speed > 0) t->speed = -t->speed;
177 flags = GCForeground;
179 if (st->transparent_p)
181 gcv.foreground = ~0L;
182 gcv.plane_mask = st->base_pixel | st->plane_masks[random() % st->nplanes];
183 flags |= GCPlaneMask;
186 # endif /* !HAVE_JWXYZ */
188 gcv.foreground = pixel;
191 gcv.line_width = t->thickness;
192 gcv.cap_style = CapProjecting;
193 gcv.join_style = JoinMiter;
195 flags |= (GCLineWidth | GCCapStyle | GCJoinStyle);
196 t->gc = XCreateGC (st->dpy, d, flags, &gcv);
199 if (st->transparent_p)
201 /* give a non-opaque alpha to the color */
202 unsigned long pixel = gcv.foreground;
203 unsigned long amask = BlackPixelOfScreen (st->xgwa.screen);
204 unsigned long a = (0xCCCCCCCC & amask);
205 pixel = (pixel & (~amask)) | a;
207 jwxyz_XSetAlphaAllowed (st->dpy, t->gc, True);
208 XSetForeground (st->dpy, t->gc, pixel);
210 # endif /* HAVE_JWXYZ */
212 switch (random() % 11) {
213 case 0: case 1: case 2: case 3: t->draw = draw_star; break;
214 case 4: case 5: case 6: case 7: t->draw = draw_circle; break;
215 case 8: t->draw = draw_hlines; break;
216 case 9: t->draw = draw_vlines; break;
217 case 10: t->draw = draw_corners; break;
218 default: abort(); break;
221 if (t->draw == draw_circle)
225 t->size = t->max_size;
227 t->size = t->thickness, t->speed = -t->speed;
233 throb (struct state *st, Drawable window, struct throbber *t)
236 if (t->size <= (t->thickness / 2))
238 t->speed = -t->speed;
239 t->size += (t->speed * 2);
241 else if (t->size > t->max_size)
243 t->speed = -t->speed;
244 t->size += (t->speed * 2);
250 XFreeGC (st->dpy, t->gc);
251 memset (t, 0, sizeof(*t));
257 t->draw (st, window, t);
264 deluxe_init (Display *dpy, Window window)
266 struct state *st = (struct state *) calloc (1, sizeof(*st));
271 st->count = get_integer_resource (st->dpy, "count", "Integer");
272 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
273 st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
274 st->dbuf = get_boolean_resource (st->dpy, "doubleBuffer", "Boolean");
276 # ifdef HAVE_DOUBLE_BUFFER_EXTENSION
277 st->dbeclear_p = get_boolean_resource (st->dpy, "useDBEClear", "Boolean");
280 # ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */
284 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
286 st->transparent_p = get_boolean_resource(st->dpy, "transparent", "Transparent");
288 st->colors = (XColor *) calloc (sizeof(*st->colors), st->ncolors);
290 if (get_boolean_resource(st->dpy, "mono", "Boolean"))
294 st->colors[0].pixel = get_pixel_resource(st->dpy, st->xgwa.colormap,
295 "foreground", "Foreground");
298 else if (st->transparent_p)
300 st->nplanes = get_integer_resource (st->dpy, "planes", "Planes");
301 if (st->nplanes <= 0)
302 st->nplanes = (random() % (st->xgwa.depth-2)) + 2;
304 allocate_alpha_colors (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
305 &st->nplanes, True, &st->plane_masks,
307 if (st->nplanes <= 1)
311 "%s: couldn't allocate any color planes; turning transparency off.\n",
314 st->transparent_p = False;
318 #endif /* !HAVE_JWXYZ */
324 make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
325 st->colors, &st->ncolors, True, True, 0, True);
332 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
334 st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeBackground);
336 st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
338 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
342 st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
343 st->bb = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height,st->xgwa.depth);
352 st->throbbers = (struct throbber **) calloc (st->count, sizeof(struct throbber *));
353 for (i = 0; i < st->count; i++)
354 st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
355 st->colors[random() % st->ncolors].pixel);
357 gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
358 "background", "Background");
359 st->erase_gc = XCreateGC (st->dpy, st->b, GCForeground, &gcv);
361 if (st->ba) XFillRectangle (st->dpy, st->ba, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
362 if (st->bb) XFillRectangle (st->dpy, st->bb, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
368 deluxe_draw (Display *dpy, Window window, void *closure)
370 struct state *st = (struct state *) closure;
372 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
373 if (!st->dbeclear_p || !st->backb)
374 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
375 XFillRectangle (st->dpy, st->b, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height);
377 for (i = 0; i < st->count; i++)
378 if (throb (st, st->b, st->throbbers[i]) < 0)
379 st->throbbers[i] = make_throbber (st, st->b, st->xgwa.width, st->xgwa.height,
380 st->colors[random() % st->ncolors].pixel);
382 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
385 XdbeSwapInfo info[1];
386 info[0].swap_window = st->window;
387 info[0].swap_action = (st->dbeclear_p ? XdbeBackground : XdbeUndefined);
388 XdbeSwapBuffers (st->dpy, info, 1);
391 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
394 XCopyArea (st->dpy, st->b, st->window, st->erase_gc, 0, 0,
395 st->xgwa.width, st->xgwa.height, 0, 0);
396 st->b = (st->b == st->ba ? st->bb : st->ba);
403 deluxe_reshape (Display *dpy, Window window, void *closure,
404 unsigned int w, unsigned int h)
406 struct state *st = (struct state *) closure;
407 if (! st->dbuf) { /* #### more complicated if we have a back buffer... */
409 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
410 XClearWindow (dpy, window);
411 for (i = 0; i < st->count; i++)
412 if (st->throbbers[i])
413 st->throbbers[i]->fuse = 0;
418 deluxe_event (Display *dpy, Window window, void *closure, XEvent *event)
424 deluxe_free (Display *dpy, Window window, void *closure)
429 static const char *deluxe_defaults [] = {
430 ".background: black",
431 ".foreground: white",
437 "*transparent: True",
438 "*doubleBuffer: True",
439 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
441 "*useDBEClear: True",
442 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
444 "*ignoreRotation: True",
449 static XrmOptionDescRec deluxe_options [] = {
450 { "-delay", ".delay", XrmoptionSepArg, 0 },
451 { "-thickness", ".thickness", XrmoptionSepArg, 0 },
452 { "-count", ".count", XrmoptionSepArg, 0 },
453 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
454 { "-speed", ".speed", XrmoptionSepArg, 0 },
455 { "-transparent", ".transparent", XrmoptionNoArg, "True" },
456 { "-no-transparent", ".transparent", XrmoptionNoArg, "False" },
457 { "-opaque", ".transparent", XrmoptionNoArg, "False" },
458 { "-no-opaque", ".transparent", XrmoptionNoArg, "True" },
459 { "-db", ".doubleBuffer", XrmoptionNoArg, "True" },
460 { "-no-db", ".doubleBuffer", XrmoptionNoArg, "False" },
465 XSCREENSAVER_MODULE ("Deluxe", deluxe)