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