1 /* xscreensaver, Copyright (c) 1997, 1998, 2002, 2006
2 * Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
12 * Concept snarfed from Michael D. Bayne in
13 * http://www.go2net.com/internet/deep/1997/04/16/body.html
15 * Changes by Lars Huttar, http://www.huttar.net:
16 * - allow use of golden ratio for dividing rectangles instead of 1/2.
17 * - allow smooth colors instead of random
18 * - added line thickness setting
19 * - added "Mondrian" mode
21 * - allow recomputing the colormap on each new frame (especially useful
22 * when ncolors is low)
25 #include "screenhack.h"
41 XWindowAttributes xgwa;
47 * Suppose you're dividing a rectangle of length A+B
48 * into two parts, of length A and B respectively. You want the ratio of
49 * A to B to be the same as the ratio of the whole (A+B) to A. The golden
50 * ratio (phi) is that ratio. Supposed to be visually pleasing. */
52 #define PHI1 (1.0/PHI)
53 #define PHI2 (1.0 - PHI1)
55 /* copied from make_random_colormap in colors.c */
57 make_mondrian_colormap (Display *dpy, Visual *visual, Colormap cmap,
58 XColor *colors, int *ncolorsP,
63 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
66 Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */
68 if (*ncolorsP <= 0) return;
70 /* If this visual doesn't support writable cells, don't bother trying. */
71 if (wanted_writable && !has_writable_cells(screen, visual))
74 for (i = 0; i < ncolors; i++)
76 colors[i].flags = DoRed|DoGreen|DoBlue;
82 case 0: case 1: case 2: case 3: case 7: /* white */
83 colors[i].red = 0xE800;
84 colors[i].green = 0xE800;
85 colors[i].blue = 0xE800;
88 colors[i].red = 0xCFFF; break; /* red */
90 colors[i].red = 0x2000;
91 colors[i].blue = 0xCFFF; break; /* blue */
93 colors[i].red = 0xDFFF; /* yellow */
94 colors[i].green = 0xCFFF; break;
102 if (writable_pP && *writable_pP)
104 unsigned long *pixels = (unsigned long *)
105 malloc(sizeof(*pixels) * (ncolors + 1));
107 allocate_writable_colors (dpy, cmap, pixels, &ncolors);
109 for (i = 0; i < ncolors; i++)
110 colors[i].pixel = pixels[i];
113 XStoreColors (dpy, cmap, colors, ncolors);
117 for (i = 0; i < ncolors; i++)
121 if (!XAllocColor (dpy, cmap, &color))
123 colors[i].pixel = color.pixel;
128 /* If we tried for writable cells and got none, try for non-writable. */
129 if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
132 *writable_pP = False;
133 goto RETRY_NON_WRITABLE;
137 /* I don't think we need to bother copying or linking to the complain
140 complain(*ncolorsP, ncolors, wanted_writable,
141 wanted_writable && *writable_pP);
148 mondrian_set_sizes (struct state *st, int w, int h)
151 st->line_width = w/50;
152 st->min_height = st->min_width = w/8;
154 st->line_width = h/50;
155 st->min_height = st->min_width = h/8;
160 deco (Display *dpy, Window window, struct state *st,
161 int x, int y, int w, int h, int depth)
163 if (((random() % st->max_depth) < depth) || (w < st->min_width) || (h < st->min_height))
167 if (++st->current_color >= st->ncolors)
168 st->current_color = 0;
169 XSetForeground(dpy, st->bgc, st->colors[st->current_color].pixel);
171 XFillRectangle (dpy, window, st->bgc, x, y, w, h);
172 XDrawRectangle (dpy, window, st->fgc, x, y, w, h);
176 if ((st->goldenRatio || st->mondrian) ? (w > h) : (random() & 1))
177 { /* Divide the rectangle side-by-side */
178 int wnew = (st->goldenRatio ? (w * (random() & 1 ? PHI1 : PHI2)) : w/2);
179 deco (dpy, window, st, x, y, wnew, h, depth+1);
180 deco (dpy, window, st, x+wnew, y, w-wnew, h, depth+1);
183 { /* Divide the rectangle top-to-bottom */
184 int hnew = (st->goldenRatio ? (h * (random() & 1 ? PHI1 : PHI2)) : h/2);
185 deco (dpy, window, st, x, y, w, hnew, depth+1);
186 deco (dpy, window, st, x, y+hnew, w, h-hnew, depth+1);
192 deco_init (Display *dpy, Window window)
194 struct state *st = (struct state *) calloc (1, sizeof(*st));
197 st->delay = get_integer_resource (dpy, "delay", "Integer");
199 st->smoothColors = get_boolean_resource(dpy, "smoothColors", "Boolean");
200 st->old_line_width = 1;
202 st->goldenRatio = get_boolean_resource (dpy, "goldenRatio", "Boolean");
204 st->max_depth = get_integer_resource (dpy, "maxDepth", "Integer");
205 if (st->max_depth < 1) st->max_depth = 1;
206 else if (st->max_depth > 1000) st->max_depth = 1000;
208 st->min_width = get_integer_resource (dpy, "minWidth", "Integer");
209 if (st->min_width < 2) st->min_width = 2;
210 st->min_height = get_integer_resource (dpy, "minHeight", "Integer");
211 if (st->min_height < 2) st->min_height = 2;
213 st->line_width = get_integer_resource (dpy, "lineWidth", "Integer");
215 XGetWindowAttributes (dpy, window, &st->xgwa);
217 st->ncolors = get_integer_resource (dpy, "ncolors", "Integer");
219 gcv.foreground = get_pixel_resource(dpy, st->xgwa.colormap,
220 "foreground", "Foreground");
221 st->fgc = XCreateGC (dpy, window, GCForeground, &gcv);
223 gcv.foreground = get_pixel_resource(dpy, st->xgwa.colormap,
224 "background", "Background");
225 st->bgc = XCreateGC (dpy, window, GCForeground, &gcv);
227 if (st->ncolors <= 2)
237 st->mondrian = get_boolean_resource(dpy, "mondrian", "Boolean");
239 /* Mondrian, if true, overrides several other options. */
240 mondrian_set_sizes(st, st->xgwa.width, st->xgwa.height);
242 /** set up red-yellow-blue-black-white colormap and fgc **/
243 make_mondrian_colormap(dpy, st->xgwa.visual, st->xgwa.colormap,
244 st->colors, &st->ncolors, True, 0, True);
246 /** put white in several cells **/
247 /** set min-height and min-width to about 10% of total w/h **/
249 else if (st->smoothColors)
250 make_smooth_colormap (dpy, st->xgwa.visual, st->xgwa.colormap,
251 st->colors, &st->ncolors, True, 0, True);
253 make_random_colormap (dpy, st->xgwa.visual, st->xgwa.colormap,
254 st->colors, &st->ncolors, False, True, 0, True);
256 gcv.line_width = st->old_line_width = st->line_width;
257 XChangeGC(dpy, st->fgc, GCLineWidth, &gcv);
263 deco_draw (Display *dpy, Window window, void *closure)
265 struct state *st = (struct state *) closure;
266 XFillRectangle (dpy, window, st->bgc, 0, 0, st->xgwa.width, st->xgwa.height);
268 mondrian_set_sizes(st, st->xgwa.width, st->xgwa.height);
269 if (st->line_width != st->old_line_width) {
270 XSetLineAttributes(dpy, st->fgc, st->line_width,
271 LineSolid, CapButt, JoinBevel);
272 st->old_line_width = st->line_width;
275 deco (dpy, window, st, 0, 0, st->xgwa.width, st->xgwa.height, 0);
276 return 1000000 * st->delay;
280 deco_reshape (Display *dpy, Window window, void *closure,
281 unsigned int w, unsigned int h)
283 struct state *st = (struct state *) closure;
289 deco_event (Display *dpy, Window window, void *closure, XEvent *event)
295 deco_free (Display *dpy, Window window, void *closure)
297 struct state *st = (struct state *) closure;
302 static const char *deco_defaults [] = {
303 ".background: black",
304 ".foreground: white",
311 "*goldenRatio: False",
312 "*smoothColors: False",
317 static XrmOptionDescRec deco_options [] = {
318 { "-max-depth", ".maxDepth", XrmoptionSepArg, 0 },
319 { "-min-width", ".minWidth", XrmoptionSepArg, 0 },
320 { "-min-height", ".minHeight", XrmoptionSepArg, 0 },
321 { "-line-width", ".lineWidth", XrmoptionSepArg, 0 },
322 { "-delay", ".delay", XrmoptionSepArg, 0 },
323 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
324 { "-golden-ratio", ".goldenRatio", XrmoptionNoArg, "True" },
325 { "-no-golden-ratio", ".goldenRatio", XrmoptionNoArg, "False" },
326 { "-smooth-colors", ".smoothColors",XrmoptionNoArg, "True" },
327 { "-no-smooth-colors",".smoothColors",XrmoptionNoArg, "False" },
328 { "-mondrian", ".mondrian", XrmoptionNoArg, "True" },
329 { "-no-mondrian", ".mondrian", XrmoptionNoArg, "False" },
333 XSCREENSAVER_MODULE ("Deco", deco)