From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / popsquares.c
1 /* Copyright (c) 2003 Levi Burton <donburton@sbcglobal.net>
2  *
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 
9  * implied warranty.
10  */
11
12 #include "screenhack.h"
13 #include "colors.h"
14
15 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
16 # include "xdbe.h"
17 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
18
19 typedef struct _square {
20   int x, y, w, h; 
21   int color;
22 } square;
23
24 static void
25 randomize_square_colors(square *squares, int nsquares, int ncolors)
26 {
27   int i;
28   square *s = squares;
29   for (i = 0; i < nsquares; i++) 
30     s[i].color = random() % ncolors;
31 }
32
33
34 struct state {
35   Display *dpy;
36   Window window;
37
38    int delay, subdivision, border, ncolors, twitch, dbuf;
39     XWindowAttributes xgwa;
40     GC gc; 
41     XColor *colors;
42     int sw, sh, gw, gh, nsquares;
43     square *squares;
44     Pixmap b, ba, bb;
45 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
46     XdbeBackBuffer backb;
47 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
48 };
49
50 static void *
51 popsquares_init (Display *dpy, Window window)
52 {
53   struct state *st = (struct state *) calloc (1, sizeof(*st));
54   int x, y;
55   double s1, v1, s2, v2 = 0;
56   int h1, h2 = 0;
57   /* Not sure how to use DBEClear */
58   /* Bool dbeclear_p = get_boolean_resource(dpy, "useDBEClear", "Boolean"); */
59   XColor fg, bg;
60   XGCValues gcv;
61   
62   st->dpy = dpy;
63   st->window = window;
64
65   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
66   st->subdivision = get_integer_resource(st->dpy, "subdivision", "Integer");
67   st->border = get_integer_resource(st->dpy, "border", "Integer");
68   st->ncolors = get_integer_resource(st->dpy, "ncolors", "Integer");
69   st->twitch = get_boolean_resource(st->dpy, "twitch", "Boolean");
70   st->dbuf = get_boolean_resource(st->dpy, "doubleBuffer", "Boolean");
71
72 # ifdef HAVE_JWXYZ      /* Don't second-guess Quartz's double-buffering */
73   st->dbuf = False;
74 # endif
75
76   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
77
78   fg.pixel = get_pixel_resource (st->dpy, st->xgwa.colormap, "foreground", "Foreground");
79   bg.pixel = get_pixel_resource (st->dpy, st->xgwa.colormap, "background", "Background");
80
81   XQueryColor (st->dpy, st->xgwa.colormap, &fg);
82   XQueryColor (st->dpy, st->xgwa.colormap, &bg);
83
84   st->sw = st->xgwa.width / st->subdivision;
85   st->sh = st->xgwa.height / st->subdivision;
86   st->gw = st->sw ? st->xgwa.width / st->sw : 0;
87   st->gh = st->sh ? st->xgwa.height / st->sh : 0;
88   st->nsquares = st->gw * st->gh;
89   if (st->nsquares < 1) st->nsquares = 1;
90   if (st->ncolors < 1) st->ncolors = 1;
91
92   gcv.foreground = fg.pixel;
93   gcv.background = bg.pixel;
94   st->gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv);
95
96   st->colors = (XColor *) calloc (st->ncolors, sizeof(XColor));
97   st->squares = (square *) calloc (st->nsquares, sizeof(square));
98
99   rgb_to_hsv (fg.red, fg.green, fg.blue, &h1, &s1, &v1);
100   rgb_to_hsv (bg.red, bg.green, bg.blue, &h2, &s2, &v2);
101   make_color_ramp (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap,
102                    h1, s1, v1,
103                    h2, s2, v2,
104                    st->colors, &st->ncolors,  /* would this be considered a value-result argument? */
105                    True, True, False);
106   if (st->ncolors < 2)
107     {
108       fprintf (stderr, "%s: insufficient colors!\n", progname);
109       exit (1);
110     }
111
112   for (y = 0; y < st->gh; y++)
113     for (x = 0; x < st->gw; x++) 
114       {
115         square *s = (square *) &st->squares[st->gw * y + x];
116         s->w = st->sw;
117         s->h = st->sh;
118         s->x = x * st->sw;
119         s->y = y * st->sh;
120       }
121
122   randomize_square_colors(st->squares, st->nsquares, st->ncolors);
123
124   if (st->dbuf)
125     {
126 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
127       st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
128       st->backb = st->b;
129 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
130       if (!st->b)                      
131         {
132           st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth);
133           st->bb = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth);
134           st->b = st->ba;
135         }
136     }
137   else 
138     {
139       st->b = st->window;
140     }
141
142   return st;
143 }
144
145 static unsigned long
146 popsquares_draw (Display *dpy, Window window, void *closure)
147 {
148   struct state *st = (struct state *) closure;
149   int x, y;
150   for (y = 0; y < st->gh; y++)
151     for (x = 0; x < st->gw; x++) 
152       {
153         square *s = (square *) &st->squares[st->gw * y + x];
154         XSetForeground (st->dpy, st->gc, st->colors[s->color].pixel);
155         XFillRectangle (st->dpy, st->b, st->gc, s->x, s->y, 
156                         st->border ? s->w - st->border : s->w, 
157                         st->border ? s->h - st->border : s->h);
158         s->color++;
159         if (s->color == st->ncolors)
160           {
161             if (st->twitch && ((random() % 4) == 0))
162               randomize_square_colors (st->squares, st->nsquares, st->ncolors);
163             else
164               s->color = random() % st->ncolors;
165           }
166       }
167 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
168   if (st->backb) 
169     {
170       XdbeSwapInfo info[1];
171       info[0].swap_window = st->window;
172       info[0].swap_action = XdbeUndefined;
173       XdbeSwapBuffers (st->dpy, info, 1);
174     }
175   else
176 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
177     if (st->dbuf)
178       {
179         XCopyArea (st->dpy, st->b, st->window, st->gc, 0, 0, 
180                    st->xgwa.width, st->xgwa.height, 0, 0);
181         st->b = (st->b == st->ba ? st->bb : st->ba);
182       }
183
184   return st->delay;
185 }
186
187
188 static void
189 popsquares_reshape (Display *dpy, Window window, void *closure, 
190                  unsigned int w, unsigned int h)
191 {
192   struct state *st = (struct state *) closure;
193   int x, y;
194   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
195   st->sw = st->xgwa.width / st->subdivision;
196   st->sh = st->xgwa.height / st->subdivision;
197   st->gw = st->sw ? st->xgwa.width / st->sw : 0;
198   st->gh = st->sh ? st->xgwa.height / st->sh : 0;
199   st->nsquares = st->gw * st->gh;
200   free (st->squares);
201   if (st->nsquares < 1) st->nsquares = 1;
202   st->squares = (square *) calloc (st->nsquares, sizeof(square));
203
204   for (y = 0; y < st->gh; y++)
205     for (x = 0; x < st->gw; x++) 
206       {
207         square *s = (square *) &st->squares[st->gw * y + x];
208         s->w = st->sw;
209         s->h = st->sh;
210         s->x = x * st->sw;
211         s->y = y * st->sh;
212       }
213
214   randomize_square_colors(st->squares, st->nsquares, st->ncolors);
215
216   if (st->dbuf) {
217     XFreePixmap (dpy, st->ba);
218     XFreePixmap (dpy, st->bb);
219     st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth);
220     st->bb = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth);
221     st->b = st->ba;
222   }
223 }
224
225 static Bool
226 popsquares_event (Display *dpy, Window window, void *closure, XEvent *event)
227 {
228   return False;
229 }
230
231 static void
232 popsquares_free (Display *dpy, Window window, void *closure)
233 {
234   struct state *st = (struct state *) closure;
235   free (st);
236 }
237
238
239 static const char *popsquares_defaults [] = {
240   ".background: #0000FF",
241   ".foreground: #00008B",
242   "*delay: 25000",
243   "*subdivision:  5",
244   "*border: 1",
245   "*ncolors: 128",
246   "*twitch: False",
247   "*doubleBuffer: False",
248 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
249   "*useDBE: True",
250   "*useDBEClear: True",
251 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
252 #ifdef HAVE_MOBILE
253   "*ignoreRotation: True",
254 #endif
255   0
256 };
257
258 static XrmOptionDescRec popsquares_options [] = {
259   { "-fg", ".foreground", XrmoptionSepArg, 0},
260   { "-bg", ".background", XrmoptionSepArg, 0},
261   { "-delay",     ".delay", XrmoptionSepArg, 0 },
262   { "-subdivision", ".subdivision", XrmoptionSepArg, 0 },
263   { "-border", ".border", XrmoptionSepArg, 0},
264   { "-ncolors",   ".ncolors", XrmoptionSepArg, 0 },
265   { "-twitch",    ".twitch", XrmoptionNoArg, "True" },
266   { "-no-twitch", ".twitch", XrmoptionNoArg, "False" },
267   { "-db",        ".doubleBuffer", XrmoptionNoArg, "True" },
268   { "-no-db",     ".doubleBuffer", XrmoptionNoArg, "False" },
269   { 0, 0, 0, 0 }
270 };
271
272
273 XSCREENSAVER_MODULE ("PopSquares", popsquares)