ftp://netsw.org/x11/tools/desktop/xscreensaver-4.07.tar.gz
[xscreensaver] / hacks / popsquares.c
1 /* Copyright (c) 2003 Levi Burton <ldb@scoundrelz.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 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 \f
34 char *progclass = "popsquares";
35
36 char *defaults [] = {
37   ".background: blue",
38   ".foreground: blue4",
39   "*delay: 25000",
40   "*subdivision:  5",
41   "*border: 1",
42   "*ncolors: 128",
43   "*twitch: False",
44   "*doubleBuffer: False",
45 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
46   "*useDBE: True",
47   "*useDBEClear: True",
48 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
49   0
50 };
51
52 XrmOptionDescRec options [] = {
53   { "-fg", ".foreground", XrmoptionSepArg, 0},
54   { "-bg", ".background", XrmoptionSepArg, 0},
55   { "-delay",     ".delay", XrmoptionSepArg, 0 },
56   { "-subdivision", ".subdivision", XrmoptionSepArg, 0 },
57   { "-border", ".border", XrmoptionSepArg, 0},
58   { "-ncolors",   ".ncolors", XrmoptionSepArg, 0 },
59   { "-twitch",    ".twitch", XrmoptionNoArg, "True" },
60   { "-no-twitch", ".twitch", XrmoptionNoArg, "False" },
61   { "-db",        ".doubleBuffer", XrmoptionNoArg, "True" },
62   { "-no-db",     ".doubleBuffer", XrmoptionNoArg, "False" },
63   { 0, 0, 0, 0 }
64 };
65
66 void 
67 screenhack (Display *dpy, Window window)
68 {
69   int delay = get_integer_resource ("delay", "Integer");
70   int subdivision = get_integer_resource("subdivision", "Integer");
71   int border = get_integer_resource("border", "Integer");
72   int ncolors = get_integer_resource("ncolors", "Integer");
73   Bool twitch = get_boolean_resource("twitch", "Boolean");
74   Bool dbuf = get_boolean_resource("doubleBuffer", "Boolean");
75   int x, y;
76   int sw, sh, gw, gh, nsquares = 0;
77   double s1, v1, s2, v2 = 0;
78   int h1, h2 = 0;
79   /* Not sure how to use DBEClear */
80   /* Bool dbeclear_p = get_boolean_resource("useDBEClear", "Boolean"); */
81   XColor *colors = 0;
82   XColor fg, bg;
83   XGCValues gcv;
84   GC gc; 
85   square *squares;
86   XWindowAttributes xgwa;
87   Pixmap b=0, ba=0, bb=0;
88 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
89   XdbeBackBuffer backb = 0;
90 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
91   
92   XGetWindowAttributes (dpy, window, &xgwa);
93
94   fg.pixel = get_pixel_resource ("foreground", "Foreground", dpy, xgwa.colormap);
95   bg.pixel = get_pixel_resource ("background", "Background", dpy, xgwa.colormap);
96
97   XQueryColor (dpy, xgwa.colormap, &fg);
98   XQueryColor (dpy, xgwa.colormap, &bg);
99
100   sw = xgwa.width / subdivision;
101   sh = xgwa.height / subdivision;
102   gw = xgwa.width / sw;
103   gh = xgwa.height / sh;
104   nsquares = gw * gh;
105
106   gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
107
108   colors = (XColor *) calloc (ncolors, sizeof(XColor));
109   squares = (square *) calloc (nsquares, sizeof(square));
110
111   rgb_to_hsv (fg.red, fg.green, fg.blue, &h1, &s1, &v1);
112   rgb_to_hsv (bg.red, bg.green, bg.blue, &h2, &s2, &v2);
113   make_color_ramp (dpy, xgwa.colormap,
114                    h1, s1, v1,
115                    h2, s2, v2,
116                    colors, &ncolors,  /* would this be considered a value-result argument? */
117                    True, True, False);
118   if (ncolors < 2)
119     {
120       fprintf (stderr, "%s: insufficient colors!\n", progname);
121       exit (1);
122     }
123
124   for (y = 0; y < gh; y++)
125     for (x = 0; x < gw; x++) 
126       {
127         square *s = (square *) &squares[gw * y + x];
128         s->w = sw;
129         s->h = sh;
130         s->x = x * sw;
131         s->y = y * sh;
132       }
133
134   randomize_square_colors(squares, nsquares, ncolors);
135
136   if (dbuf)
137     {
138 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
139       b = xdbe_get_backbuffer (dpy, window, XdbeUndefined);
140       backb = b;
141 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
142       if (!b)                      
143         {
144           ba = XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
145           bb = XCreatePixmap (dpy, window, xgwa.width, xgwa.height, xgwa.depth);
146           b = ba;
147         }
148     }
149   else 
150     {
151       b = window;
152     }
153
154   while (1) 
155     {
156       for (y = 0; y < gh; y++)
157         for (x = 0; x < gw; x++) 
158           {
159             square *s = (square *) &squares[gw * y + x];
160             XSetForeground (dpy, gc, colors[s->color].pixel);
161             XFillRectangle (dpy, b, gc, s->x, s->y, 
162                             border ? s->w - border : s->w, 
163                             border ? s->h - border : s->h);
164             s->color++;
165             if (s->color == ncolors)
166               {
167                 if (twitch && ((random() % 4) == 0))
168                   randomize_square_colors (squares, nsquares, ncolors);
169                 else
170                   s->color = random() % ncolors;
171               }
172           }
173 #ifdef HAVE_DOUBLE_BUFFER_EXTENSION
174       if (backb) 
175         {
176           XdbeSwapInfo info[1];
177           info[0].swap_window = window;
178           info[0].swap_action = XdbeUndefined;
179           XdbeSwapBuffers (dpy, info, 1);
180         }
181       else
182 #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
183         if (dbuf)
184           {
185             XCopyArea (dpy, b, window, gc, 0, 0, 
186                        xgwa.width, xgwa.height, 0, 0);
187             b = (b == ba ? bb : ba);
188           }
189
190       XSync (dpy, False);
191       screenhack_handle_events (dpy);
192       if (delay) 
193         usleep (delay);
194     }
195 }