c52d2236bc7207af9bf2707be974e64539500918
[xscreensaver] / hacks / moire.c
1 /* xscreensaver, Copyright (c) 1997, 1998, 2001, 2006
2  *  Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  *
12  * Concept snarfed from Michael D. Bayne in
13  * http://www.go2net.com/internet/deep/1997/04/16/body.html
14  */
15
16 #include "screenhack.h"
17
18 #undef HAVE_XSHM_EXTENSION  /* this is broken here at the moment */
19
20
21 #ifdef HAVE_XSHM_EXTENSION
22 # include "xshm.h"
23 #endif /* HAVE_XSHM_EXTENSION */
24
25 struct state {
26   Display *dpy;
27   Window window;
28 #ifdef HAVE_XSHM_EXTENSION
29   Bool use_shm;
30   XShmSegmentInfo shm_info;
31 #endif /* HAVE_XSHM_EXTENSION */
32
33   int delay;
34   int offset;
35   XColor *colors;
36   int ncolors;
37   GC gc;
38   unsigned long fg_pixel;
39   unsigned long bg_pixel;
40   int depth;
41
42   int draw_y, draw_xo, draw_yo;
43   int draw_factor;
44   XImage *draw_image;
45   XWindowAttributes xgwa;
46 };
47
48 static void
49 moire_init_1 (struct state *st)
50 {
51   int oncolors;
52   int i;
53   int fgh, bgh;
54   double fgs, fgv, bgs, bgv;
55   XWindowAttributes xgwa;
56   XColor fgc, bgc;
57   XGCValues gcv;
58
59   XGetWindowAttributes (st->dpy, st->window, &xgwa);
60
61   st->delay = get_integer_resource (st->dpy, "delay", "Integer");
62   st->offset = get_integer_resource (st->dpy, "offset", "Integer");
63   if (st->offset < 2) st->offset = 2;
64
65 #ifdef HAVE_XSHM_EXTENSION
66   st->use_shm = get_boolean_resource(st->dpy, "useSHM", "Boolean");
67 #endif /*  HAVE_XSHM_EXTENSION */
68
69  MONO:
70   if (st->colors)
71     {
72       for (i = 0; i < st->ncolors; i++)
73         XFreeColors (st->dpy, xgwa.colormap, &st->colors[i].pixel, 1, 0);
74       free(st->colors);
75       st->colors = 0;
76     }
77
78   if (mono_p)
79     {
80       st->fg_pixel = WhitePixelOfScreen (DefaultScreenOfDisplay(st->dpy));
81       st->bg_pixel = BlackPixelOfScreen (DefaultScreenOfDisplay(st->dpy));
82     }
83   else
84     {
85       st->fg_pixel = get_pixel_resource (st->dpy,
86                                      xgwa.colormap, "foreground", "Foreground");
87       st->bg_pixel = get_pixel_resource (st->dpy,
88                                      xgwa.colormap, "background", "Background");
89     }
90
91   if (mono_p)
92     {
93       st->offset *= 20;   /* compensate for lack of shading */
94       gcv.foreground = st->fg_pixel;
95     }
96   else
97     {
98       st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
99       if (st->ncolors < 2) st->ncolors = 2;
100       oncolors = st->ncolors;
101
102       fgc.flags = bgc.flags = DoRed|DoGreen|DoBlue;
103       if (get_boolean_resource(st->dpy, "random","Boolean"))
104         {
105           fgc.red   = random() & 0xFFFF;
106           fgc.green = random() & 0xFFFF;
107           fgc.blue  = random() & 0xFFFF;
108           bgc.red   = random() & 0xFFFF;
109           bgc.green = random() & 0xFFFF;
110           bgc.blue  = random() & 0xFFFF;
111         }
112       else
113         {
114           fgc.pixel = st->fg_pixel;
115           bgc.pixel = st->bg_pixel;
116           XQueryColor (st->dpy, xgwa.colormap, &fgc);
117           XQueryColor (st->dpy, xgwa.colormap, &bgc);
118         }
119       rgb_to_hsv (fgc.red, fgc.green, fgc.blue, &fgh, &fgs, &fgv);
120       rgb_to_hsv (bgc.red, bgc.green, bgc.blue, &bgh, &bgs, &bgv);
121
122       st->colors = (XColor *) malloc (sizeof (XColor) * (st->ncolors+2));
123       memset(st->colors, 0, (sizeof (XColor) * (st->ncolors+2)));
124       make_color_ramp (st->dpy, xgwa.colormap,
125                        fgh, fgs, fgv, bgh, bgs, bgv,
126                        st->colors, &st->ncolors,
127                        True, True, False);
128       if (st->ncolors != oncolors)
129         fprintf(stderr, "%s: got %d of %d requested colors.\n",
130                 progname, st->ncolors, oncolors);
131
132       if (st->ncolors <= 2)
133         {
134           mono_p = True;
135           goto MONO;
136         }
137
138       gcv.foreground = st->colors[0].pixel;
139     }
140   st->gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
141 }
142
143
144 static void *
145 moire_init (Display *dpy, Window window)
146 {
147   struct state *st = (struct state *) calloc (1, sizeof(*st));
148   st->dpy = dpy;
149   st->window = window;
150   moire_init_1 (st);
151   return st;
152 }
153
154
155 static unsigned long
156 moire_draw (Display *dpy, Window window, void *closure)
157 {
158   struct state *st = (struct state *) closure;
159   XGCValues gcv;
160   int chunk_size = 20, ii;
161
162   if (st->draw_y == 0) 
163     {
164       moire_init_1 (st);
165
166       XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
167
168       st->draw_xo = (random() % st->xgwa.width)  - st->xgwa.width/2;
169       st->draw_yo = (random() % st->xgwa.height) - st->xgwa.height/2;
170       st->draw_factor = (random() % st->offset) + 1;
171
172       st->depth = visual_depth(DefaultScreenOfDisplay(st->dpy), st->xgwa.visual);
173
174 # ifdef HAVE_XSHM_EXTENSION
175       if (st->use_shm)
176         {
177           st->draw_image = create_xshm_image(st->dpy, st->xgwa.visual, 
178                                              st->depth, ZPixmap, 0,
179                                              &st->shm_info, st->xgwa.width, 1);
180           if (!st->draw_image)
181             st->use_shm = False;
182         }
183 # endif /* HAVE_XSHM_EXTENSION */
184
185       if (!st->draw_image)
186         {
187           st->draw_image = XCreateImage (st->dpy, st->xgwa.visual,
188                                          st->depth, ZPixmap, 0,     /* depth, format, offset */
189                                          0, st->xgwa.width, 1, 8, 0); /* data, w, h, pad, bpl */
190           st->draw_image->data = (char *) calloc(st->draw_image->height, st->draw_image->bytes_per_line);
191         }
192     }
193
194   /* for (y = 0; y < st->xgwa.height; y++) */
195   for (ii = 0; ii < chunk_size; ii++)
196     {
197       int x;
198       for (x = 0; x < st->xgwa.width; x++)
199         {
200           double xx = x + st->draw_xo;
201           double yy = st->draw_y + st->draw_yo;
202           double i = ((xx * xx) + (yy * yy)) / (double) st->draw_factor;
203           if (mono_p)
204             gcv.foreground = ((((long) i) & 1) ? st->fg_pixel : st->bg_pixel);
205           else
206             gcv.foreground = st->colors[((long) i) % st->ncolors].pixel;
207           XPutPixel (st->draw_image, x, 0, gcv.foreground);
208         }
209
210 # ifdef HAVE_XSHM_EXTENSION
211       if (st->use_shm)
212         XShmPutImage(st->dpy, st->window, st->gc, st->draw_image, 0, 0, 0, st->draw_y, st->xgwa.width, 1, False);
213       else
214 # endif /*  HAVE_XSHM_EXTENSION */
215         XPutImage (st->dpy, st->window, st->gc, st->draw_image, 0, 0, 0, st->draw_y, st->xgwa.width, 1);
216
217       st->draw_y++;
218       if (st->draw_y >= st->xgwa.height)
219         break;
220     }
221
222
223     if (st->draw_y >= st->xgwa.height)
224       {
225         st->draw_y = 0;
226
227 # ifdef HAVE_XSHM_EXTENSION
228         if (!st->use_shm)
229 # endif /*  HAVE_XSHM_EXTENSION */
230           if (st->draw_image->data)
231             {
232               free(st->draw_image->data);
233               st->draw_image->data = 0;
234             }
235
236 # ifdef HAVE_XSHM_EXTENSION
237         if (st->use_shm)
238           destroy_xshm_image (st->dpy, st->draw_image, &st->shm_info);
239         else
240 # endif /*  HAVE_XSHM_EXTENSION */
241           XDestroyImage (st->draw_image);
242         st->draw_image = 0;
243
244         return st->delay * 1000000;
245       }
246
247   return st->delay * 10000;
248 }
249
250 \f
251 static const char *moire_defaults [] = {
252   ".background:         blue",
253   ".foreground:         red",
254   "*random:             true",
255   "*delay:              5",
256   "*ncolors:            64",
257   "*offset:             50",
258 #ifdef HAVE_XSHM_EXTENSION
259   "*useSHM:           True",
260 #else
261   "*useSHM:           False",
262 #endif
263   0
264 };
265
266 static XrmOptionDescRec moire_options [] = {
267   { "-random",          ".random",      XrmoptionNoArg, "True" },
268   { "-no-random",       ".random",      XrmoptionNoArg, "False" },
269   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
270   { "-ncolors",         ".ncolors",     XrmoptionSepArg, 0 },
271   { "-offset",          ".offset",      XrmoptionSepArg, 0 },
272   { "-shm",             ".useSHM",      XrmoptionNoArg, "True" },
273   { "-no-shm",          ".useSHM",      XrmoptionNoArg, "False" },
274   { 0, 0, 0, 0 }
275 };
276
277 static void
278 moire_reshape (Display *dpy, Window window, void *closure, 
279                  unsigned int w, unsigned int h)
280 {
281 }
282
283 static Bool
284 moire_event (Display *dpy, Window window, void *closure, XEvent *event)
285 {
286   return False;
287 }
288
289 static void
290 moire_free (Display *dpy, Window window, void *closure)
291 {
292 }
293
294 XSCREENSAVER_MODULE ("Moire", moire)