6c26165f6dc4cc6fdad76194c421b8d4e225c9fa
[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_COCOA      /* 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->xgwa.width / st->sw;
87   st->gh = st->xgwa.height / st->sh;
88   st->nsquares = st->gw * st->gh;
89
90   gcv.foreground = fg.pixel;
91   gcv.background = bg.pixel;
92   st->gc = XCreateGC (st->dpy, st->window, GCForeground|GCBackground, &gcv);
93
94   st->colors = (XColor *) calloc (st->ncolors, sizeof(XColor));
95   st->squares = (square *) calloc (st->nsquares, sizeof(square));
96
97   rgb_to_hsv (fg.red, fg.green, fg.blue, &h1, &s1, &v1);
98   rgb_to_hsv (bg.red, bg.green, bg.blue, &h2, &s2, &v2);
99   make_color_ramp (st->dpy, st->xgwa.colormap,
100                    h1, s1, v1,
101                    h2, s2, v2,
102                    st->colors, &st->ncolors,  /* would this be considered a value-result argument? */
103                    True, True, False);
104   if (st->ncolors < 2)
105     {
106       fprintf (stderr, "%s: insufficient colors!\n", progname);
107       exit (1);
108     }
109
110   for (y = 0; y < st->gh; y++)
111     for (x = 0; x < st->gw; x++) 
112       {
113         square *s = (square *) &st->squares[st->gw * y + x];
114         s->w = st->sw;
115         s->h = st->sh;
116         s->x = x * st->sw;
117         s->y = y * st->sh;
118       }
119
120   randomize_square_colors(st->squares, st->nsquares, st->ncolors);
121
122   if (st->dbuf)
123     {
124 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
125       st->b = xdbe_get_backbuffer (st->dpy, st->window, XdbeUndefined);
126       st->backb = st->b;
127 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
128       if (!st->b)                      
129         {
130           st->ba = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth);
131           st->bb = XCreatePixmap (st->dpy, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth);
132           st->b = st->ba;
133         }
134     }
135   else 
136     {
137       st->b = st->window;
138     }
139
140   return st;
141 }
142
143 static unsigned long
144 popsquares_draw (Display *dpy, Window window, void *closure)
145 {
146   struct state *st = (struct state *) closure;
147   int x, y;
148   for (y = 0; y < st->gh; y++)
149     for (x = 0; x < st->gw; x++) 
150       {
151         square *s = (square *) &st->squares[st->gw * y + x];
152         XSetForeground (st->dpy, st->gc, st->colors[s->color].pixel);
153         XFillRectangle (st->dpy, st->b, st->gc, s->x, s->y, 
154                         st->border ? s->w - st->border : s->w, 
155                         st->border ? s->h - st->border : s->h);
156         s->color++;
157         if (s->color == st->ncolors)
158           {
159             if (st->twitch && ((random() % 4) == 0))
160               randomize_square_colors (st->squares, st->nsquares, st->ncolors);
161             else
162               s->color = random() % st->ncolors;
163           }
164       }
165 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
166   if (st->backb) 
167     {
168       XdbeSwapInfo info[1];
169       info[0].swap_window = st->window;
170       info[0].swap_action = XdbeUndefined;
171       XdbeSwapBuffers (st->dpy, info, 1);
172     }
173   else
174 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
175     if (st->dbuf)
176       {
177         XCopyArea (st->dpy, st->b, st->window, st->gc, 0, 0, 
178                    st->xgwa.width, st->xgwa.height, 0, 0);
179         st->b = (st->b == st->ba ? st->bb : st->ba);
180       }
181
182   return st->delay;
183 }
184
185
186 static void
187 popsquares_reshape (Display *dpy, Window window, void *closure, 
188                  unsigned int w, unsigned int h)
189 {
190 }
191
192 static Bool
193 popsquares_event (Display *dpy, Window window, void *closure, XEvent *event)
194 {
195   return False;
196 }
197
198 static void
199 popsquares_free (Display *dpy, Window window, void *closure)
200 {
201   struct state *st = (struct state *) closure;
202   free (st);
203 }
204
205
206 static const char *popsquares_defaults [] = {
207   ".background: #0000FF",
208   ".foreground: #00008B",
209   "*delay: 25000",
210   "*subdivision:  5",
211   "*border: 1",
212   "*ncolors: 128",
213   "*twitch: False",
214   "*doubleBuffer: False",
215 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
216   "*useDBE: True",
217   "*useDBEClear: True",
218 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
219   0
220 };
221
222 static XrmOptionDescRec popsquares_options [] = {
223   { "-fg", ".foreground", XrmoptionSepArg, 0},
224   { "-bg", ".background", XrmoptionSepArg, 0},
225   { "-delay",     ".delay", XrmoptionSepArg, 0 },
226   { "-subdivision", ".subdivision", XrmoptionSepArg, 0 },
227   { "-border", ".border", XrmoptionSepArg, 0},
228   { "-ncolors",   ".ncolors", XrmoptionSepArg, 0 },
229   { "-twitch",    ".twitch", XrmoptionNoArg, "True" },
230   { "-no-twitch", ".twitch", XrmoptionNoArg, "False" },
231   { "-db",        ".doubleBuffer", XrmoptionNoArg, "True" },
232   { "-no-db",     ".doubleBuffer", XrmoptionNoArg, "False" },
233   { 0, 0, 0, 0 }
234 };
235
236
237 XSCREENSAVER_MODULE ("PopSquares", popsquares)