1 /* cynosure --- draw some rectangles
3 * 01-aug-96: written in Java by ozymandias G desiderata <ogd@organic.com>
4 * 25-dec-97: ported to C and XScreenSaver by Jamie Zawinski <jwz@jwz.org>
7 * http://www.organic.com/staff/ogd/java/cynosure.html
8 * http://www.organic.com/staff/ogd/java/source/cynosure/Cynosure-java.txt
10 * Original comments and copyright:
13 * A Java implementation of Stephen Linhart's Cynosure screen-saver as a
16 * Header: /home/ogd/lib/cvs/aoaioxxysz/graphics/Cynosure.java,v 1.2 1996/08/02 02:41:21 ogd Exp
18 * ozymandias G desiderata <ogd@organic.com>
23 * Copyright 1996 ozymandias G desiderata. Title, ownership rights, and
24 * intellectual property rights in and to this software remain with
25 * ozymandias G desiderata. This software may be copied, modified,
26 * or used as long as this copyright is retained. Use this code at your
31 * Log: Cynosure.java,v
32 * Revision 1.2 1996/08/02 02:41:21 ogd
33 * Added a few more comments, fixed messed-up header.
35 * Revision 1.1.1.1 1996/08/02 02:30:45 ogd
39 #include "screenhack.h"
42 static XColor *colors;
44 static int fg_pixel, bg_pixel;
45 static GC fg_gc, bg_gc, shadow_gc;
47 static void paint(void);
48 static int genNewColor(void);
49 static int genConstrainedColor(int base, int tweak);
50 static int c_tweak(int base, int tweak);
53 * The current color that is being tweaked to create the
59 * A variable used for the progression of the colors (yes, I know
60 * that's a lame explanation, but if your read the source, it should
61 * become obvious what I'm doing with this variable).
66 * The width of the right and bottom edges of the rectangles.
68 static int shadowWidth;
70 /* The offset of the dropshadow beneath the rectangles. */
74 * The approximate amount of time that will elapse before the base
75 * color is permanently changed.
82 * The counter of time left until the base color value used. This class
83 * variable is necessary because Java doesn't support static method
84 * variables (grr grr).
89 * The amount by which the color of the polygons drawn will vary.
96 * The smallest size for an individual cell.
98 #define MINCELLSIZE 16
101 * The narrowest a rectangle can be.
103 #define MINRECTSIZE 6
106 * The size of the grid that the rectangles are placed within.
111 * Every so often genNewColor() generates a completely random
112 * color. This variable sets how frequently that happens. It's
113 * currently set to happen 1% of the time.
117 #define THRESHOLD 100 /*0.01*/
120 char *progclass = "Cynosure";
121 char *defaults [] = {
122 ".background: black",
123 ".foreground: white",
135 XrmOptionDescRec options [] = {
136 { "-delay", ".delay", XrmoptionSepArg, 0 },
137 { "-ncolors", ".colors", XrmoptionSepArg, 0 },
138 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
143 void screenhack(Display *d, Window w)
145 XWindowAttributes xgwa;
155 shadowWidth = get_integer_resource ("shadowWidth", "Integer");
156 elevation = get_integer_resource ("elevation", "Integer");
157 sway = get_integer_resource ("sway", "Integer");
158 tweak = get_integer_resource ("tweak", "Integer");
159 gridSize = get_integer_resource ("gridSize", "Integer");
162 XGetWindowAttributes (dpy, window, &xgwa);
164 ncolors = get_integer_resource ("colors", "Colors");
165 if (ncolors < 2) ncolors = 2;
166 if (ncolors <= 2) mono_p = True;
171 colors = (XColor *) malloc(sizeof(*colors) * (ncolors+1));
176 make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
181 if (colors) free(colors);
186 bg_pixel = get_pixel_resource("background", "Background", dpy,
188 fg_pixel = get_pixel_resource("foreground", "Foreground", dpy,
191 gcv.foreground = fg_pixel;
192 fg_gc = XCreateGC(dpy, window, GCForeground, &gcv);
193 gcv.foreground = bg_pixel;
194 bg_gc = XCreateGC(dpy, window, GCForeground, &gcv);
196 gcv.fill_style = FillStippled;
197 gcv.stipple = XCreateBitmapFromData(dpy, window, "\125\252", 8, 2);
198 shadow_gc = XCreateGC(dpy, window, GCForeground|GCFillStyle|GCStipple, &gcv);
199 XFreePixmap(dpy, gcv.stipple);
201 delay = get_integer_resource ("delay", "Delay");
202 iterations = get_integer_resource ("iterations", "Iterations");
207 if (iterations > 0 && ++i >= iterations)
211 XSetWindowBackground(dpy, window,
212 colors[random() % ncolors].pixel);
213 XClearWindow(dpy, window);
217 screenhack_handle_events (dpy);
224 * paint adds a new layer of multicolored rectangles within a grid of
225 * randomly generated size. Each row of rectangles is the same color,
226 * but colors vary slightly from row to row. Each rectangle is placed
227 * within a regularly-sized cell, but each rectangle is sized and
228 * placed randomly within that cell.
230 * @param g the Graphics coordinate in which to draw
233 static void paint(void)
236 int cellsWide, cellsHigh, cellWidth, cellHeight;
237 static int width, height;
238 static int size_check = 1;
240 if (--size_check <= 0)
242 XWindowAttributes xgwa;
243 XGetWindowAttributes (dpy, window, &xgwa);
245 height = xgwa.height;
249 /* How many cells wide the grid is (equal to gridSize +/- (gridSize / 2))
251 cellsWide = c_tweak(gridSize, gridSize / 2);
252 /* How many cells high the grid is (equal to gridSize +/- (gridSize / 2))
254 cellsHigh = c_tweak(gridSize, gridSize / 2);
255 /* How wide each cell in the grid is */
256 cellWidth = width / cellsWide;
257 /* How tall each cell in the grid is */
258 cellHeight = height / cellsHigh;
260 /* Ensure that each cell is above a certain minimum size */
262 if (cellWidth < MINCELLSIZE) {
263 cellWidth = MINCELLSIZE;
264 cellsWide = width / cellWidth;
267 if (cellHeight < MINCELLSIZE) {
268 cellHeight = MINCELLSIZE;
269 cellsHigh = width / cellWidth;
272 /* fill the grid with randomly-generated cells */
273 for(i = 0; i < cellsHigh; i++) {
276 /* Each row is a different color, randomly generated (but constrained) */
279 int c = genNewColor();
280 XSetForeground(dpy, fg_gc, colors[c].pixel);
283 for(j = 0; j < cellsWide; j++) {
284 int curWidth, curHeight, curX, curY;
286 /* Generate a random height for a rectangle and make sure that */
287 /* it's above a certain minimum size */
288 curHeight = random() % (cellHeight - shadowWidth);
289 if (curHeight < MINRECTSIZE)
290 curHeight = MINRECTSIZE;
291 /* Generate a random width for a rectangle and make sure that
292 it's above a certain minimum size */
293 curWidth = random() % (cellWidth - shadowWidth);
294 if (curWidth < MINRECTSIZE)
295 curWidth = MINRECTSIZE;
296 /* Figure out a random place to locate the rectangle within the
298 curY = (i * cellHeight) + (random() % ((cellHeight - curHeight) -
300 curX = (j * cellWidth) + (random() % ((cellWidth - curWidth) -
303 /* Draw the shadow */
305 XFillRectangle(dpy, window, shadow_gc,
306 curX + elevation, curY + elevation,
307 curWidth, curHeight);
311 XFillRectangle(dpy, window, bg_gc,
312 curX + shadowWidth, curY + shadowWidth,
313 curWidth, curHeight);
315 XFillRectangle(dpy, window, fg_gc, curX, curY, curWidth, curHeight);
317 /* Draw a 1-pixel black border around the rectangle */
318 XDrawRectangle(dpy, window, bg_gc, curX, curY, curWidth, curHeight);
326 * genNewColor returns a new color, gradually mutating the colors and
327 * occasionally returning a totally random color, just for variety.
329 * @return the new color
331 static int genNewColor(void)
333 /* These lines handle "sway", or the gradual random changing of */
334 /* colors. After genNewColor() has been called a given number of */
335 /* times (specified by a random permutation of the tweak variable), */
336 /* take whatever color has been most recently randomly generated and */
337 /* make it the new base color. */
339 timeLeft = c_tweak(sway, sway / 3);
345 /* If a randomly generated number is less than the threshold value,
346 produce a "sport" color value that is completely unrelated to the
348 if (0 == (random() % THRESHOLD)) {
349 return (random() % ncolors);
351 curBase = genConstrainedColor(curColor, tweak);
358 * genConstrainedColor creates a random new color within a certain
359 * range of an existing color. Right now this works with RGB color
360 * values, but a future version of the program will most likely use HSV
361 * colors, which should generate a more pleasing progression of values.
363 * @param base the color on which the new color will be based
364 * @param tweak the amount that the new color can be tweaked
365 * @return a new constrained color
368 static int genConstrainedColor(int base, int tweak)
370 int i = 1 + (random() % tweak);
373 i = (base + i) % ncolors;
380 * Utility function to generate a tweaked color value
382 * @param base the byte value on which the color is based
383 * @param tweak the amount the value will be skewed
385 * @return the tweaked byte
387 static int c_tweak(int base, int tweak)
389 int ranTweak = (random() % (2 * tweak));
390 int n = (base + (ranTweak - tweak));
392 return (n < 255 ? n : 255);