717689baef0454673ef9c290f91b9e462c4fcf5c
[xscreensaver] / hacks / xflame.c
1 /* xflame, Copyright (c) 1996-2002 Carsten Haitzler <raster@redhat.com>
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 /* Version history as near as I (jwz) can piece together:
13
14    * Carsten Haitzler <raster@redhat.com> wrote the first version in 1996.
15
16    * Rahul Jain <rahul@rice.edu> added support for TrueColor displays.
17
18    * Someone did a rough port of it to use the xscreensaver utility routines
19      instead of creating its own window by hand.
20
21    * Someone (probably Raster) came up with a subsequent version that had
22      a Red Hat logo hardcoded into it.
23
24    * Daniel Zahn <stumpy@religions.com> found that version in 1998, and 
25      hacked it to be able to load a different logo from a PGM (P5) file, 
26      with a single hardcoded pathname.
27
28    * Jamie Zawinski <jwz@jwz.org> found several versions of xflame in
29      March 1999, and pieced them together.  Changes:
30
31        - Correct and fault-tolerant use of the Shared Memory extension;
32          previous versions of xflame did not work when $DISPLAY was remote.
33
34        - Replaced PGM-reading code with code that can read arbitrary XBM
35          and XPM files (color ones will be converted to grayscale.)
36
37        - Command-line options all around -- no hardcoded pathnames or
38          behavioral constants.
39
40        - General cleanup and portability tweaks.
41
42    * 4-Oct-99, jwz: added support for packed-24bpp (versus 32bpp.)
43    * 16-Jan-2002, jwz: added gdk_pixbuf support.
44
45  */
46
47 /* portions by Daniel Zahn <stumpy@religions.com> */
48
49
50 #include "screenhack.h"
51 #include "xpm-pixmap.h"
52 #include <limits.h>
53
54 #undef countof
55 #define countof(x) (sizeof((x))/sizeof((*x)))
56
57 #ifdef HAVE_XSHM_EXTENSION
58 # include "xshm.h"
59 #endif /* HAVE_XSHM_EXTENSION */
60
61 #include "images/bob.xbm"
62
63 #define MAX_VAL             255
64
65 struct state {
66   Display *dpy;
67   Window window;
68   int             depth;
69   int             width;
70   int             height;
71   Colormap        colormap;
72   Visual          *visual;
73   Screen          *screen;
74   Bool            shared;
75   Bool            bloom;
76   XImage          *xim;
77 #ifdef HAVE_XSHM_EXTENSION
78   XShmSegmentInfo shminfo;
79 #endif /* HAVE_XSHM_EXTENSION */
80   GC              gc;
81   int             ctab[256];
82
83   unsigned char  *flame;
84   unsigned char  *theim;
85   int             fwidth;
86   int             fheight;
87   int             top;
88   int             hspread;
89   int             vspread;
90   int             residual;
91
92   int ihspread;
93   int ivspread;
94   int iresidual;
95   int variance;
96   int vartrend;
97
98   int delay;
99   int baseline;
100   int theimx, theimy;
101 };
102
103 static void
104 GetXInfo(struct state *st)
105 {
106   XWindowAttributes xwa;
107    
108   XGetWindowAttributes(st->dpy,st->window,&xwa);
109
110   st->colormap = xwa.colormap;
111   st->depth    = xwa.depth;
112   st->visual   = xwa.visual;
113   st->screen   = xwa.screen;
114   st->width    = xwa.width;
115   st->height   = xwa.height;
116
117   if (st->width%2)
118     st->width++;
119   if (st->height%2)
120     st->height++;
121 }
122
123 static void
124 MakeImage(struct state *st)
125 {
126   XGCValues gcv;
127
128 #ifdef HAVE_XSHM_EXTENSION
129   st->shared = True;
130   st->xim = create_xshm_image (st->dpy, st->visual, st->depth, ZPixmap, NULL,
131                            &st->shminfo, st->width, st->height);
132 #else  /* !HAVE_XSHM_EXTENSION */
133   st->xim = 0;
134 #endif /* !HAVE_XSHM_EXTENSION */
135
136   if (!st->xim)
137     {
138       st->shared = False;
139       st->xim = XCreateImage (st->dpy, st->visual, st->depth, ZPixmap, 0, NULL,
140                           st->width, st->height, 32, 0);
141       if (st->xim)
142         st->xim->data = (char *) calloc(st->xim->height, st->xim->bytes_per_line);
143       if (!st->xim || !st->xim->data)
144         {
145           fprintf(stderr,"%s: out of memory.\n", progname);
146           exit(1);
147         }
148     }
149
150   st->gc = XCreateGC(st->dpy,st->window,0,&gcv);
151   if (!st->gc) exit (1);
152 }
153
154
155 static void
156 InitColors(struct state *st)
157 {
158   int i = 0, j = 0, red = 0, green = 0, blue = 0;
159   XColor fg;
160
161   /* Make it possible to set the color of the flames, 
162      by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
163   */
164   fg.pixel = get_pixel_resource (st->dpy, st->colormap,
165                                  "foreground", "Foreground");
166   XQueryColor (st->dpy, st->colormap, &fg);
167
168   red   = 255 - (fg.red   >> 8);
169   green = 255 - (fg.green >> 8);
170   blue  = 255 - (fg.blue  >> 8);
171
172
173   for (i = 0; i < 256 * 2; i += 2)
174     {
175       XColor xcl;
176       int r = (i - red)   * 3;
177       int g = (i - green) * 3;
178       int b = (i - blue)  * 3;
179     
180       if (r < 0)   r = 0;
181       if (r > 255) r = 255;
182       if (g < 0)   g = 0;
183       if (g > 255) g = 255;
184       if (b < 0)   b = 0;
185       if (b > 255) b = 255;
186
187       xcl.red   = (unsigned short)((r << 8) | r);
188       xcl.green = (unsigned short)((g << 8) | g);
189       xcl.blue  = (unsigned short)((b << 8) | b);
190       xcl.flags = DoRed | DoGreen | DoBlue;
191
192       XAllocColor(st->dpy,st->colormap,&xcl);
193
194       st->ctab[j++] = (int)xcl.pixel;
195     }
196 }
197
198
199 static void
200 DisplayImage(struct state *st)
201 {
202 #ifdef HAVE_XSHM_EXTENSION
203   if (st->shared)
204     XShmPutImage(st->dpy, st->window, st->gc, st->xim, 0,(st->top - 1) << 1, 0,
205                  (st->top - 1) << 1, st->width, st->height - ((st->top - 1) << 1), False);
206   else
207 #endif /* HAVE_XSHM_EXTENSION */
208     XPutImage(st->dpy, st->window, st->gc, st->xim, 0, (st->top - 1) << 1, 0,
209               (st->top - 1) << 1, st->width, st->height - ((st->top - 1) << 1));
210 }
211
212
213 static void
214 InitFlame(struct state *st)
215 {
216   st->fwidth  = st->width / 2;
217   st->fheight = st->height / 2;
218   st->flame   = (unsigned char *) malloc((st->fwidth + 2) * (st->fheight + 2)
219                                      * sizeof(unsigned char));
220
221   if (!st->flame)
222     {
223       fprintf(stderr,"%s: out of memory\n", progname);
224       exit(1);
225     }
226
227   st->top      = 1;
228   st->ihspread  = get_integer_resource(st->dpy, "hspread", "Integer");
229   st->ivspread  = get_integer_resource(st->dpy, "vspread", "Integer");
230   st->iresidual = get_integer_resource(st->dpy, "residual", "Integer");
231   st->variance  = get_integer_resource(st->dpy, "variance", "Integer");
232   st->vartrend  = get_integer_resource(st->dpy, "vartrend", "Integer");
233   st->bloom     = get_boolean_resource(st->dpy, "bloom",    "Boolean");
234
235 # define THROTTLE(VAR,NAME) \
236   if (VAR < 0 || VAR > 255) { \
237     fprintf(stderr, "%s: %s must be in the range 0-255 (not %d).\n", \
238             progname, NAME, VAR); \
239     exit(1); }
240   THROTTLE (st->ihspread, "hspread");
241   THROTTLE (st->ivspread, "vspread");
242   THROTTLE (st->iresidual,"residual");
243   THROTTLE (st->variance, "variance");
244   THROTTLE (st->vartrend, "vartrend");
245 # undef THROTTLE
246
247
248
249   st->hspread = st->ihspread;
250   st->vspread = st->ivspread;
251   st->residual = st->iresidual;
252 }
253
254
255 static void
256 Flame2Image16(struct state *st)
257 {
258   int x,y;
259   unsigned short *ptr;
260   unsigned char *ptr1;
261   int v1,v2,v3,v4;
262
263   ptr  = (unsigned short *)st->xim->data;
264   ptr += (st->top << 1) * st->width;
265   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
266
267   for(y = st->top; y < st->fheight; y++)
268     {
269       for( x = 0; x < st->fwidth; x++)
270         {
271           v1 = (int)*ptr1;
272           v2 = (int)*(ptr1 + 1);
273           v3 = (int)*(ptr1 + st->fwidth + 2);
274           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
275           ptr1++;
276           *ptr++ = (unsigned short)st->ctab[v1];
277           *ptr   = (unsigned short)st->ctab[(v1 + v2) >> 1];
278           ptr   += st->width - 1;
279           *ptr++ = (unsigned short)st->ctab[(v1 + v3) >> 1];
280           *ptr   = (unsigned short)st->ctab[(v1 + v4) >> 1];
281           ptr   -= st->width - 1;
282         }
283       ptr  += st->width;
284       ptr1 += 2;
285     }
286 }
287
288 static void
289 Flame2Image32(struct state *st)
290 {
291   int x,y;
292   unsigned int *ptr;
293   unsigned char *ptr1;
294   int v1,v2,v3,v4;
295
296   ptr  = (unsigned int *)st->xim->data;
297   ptr += (st->top << 1) * st->width;
298   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
299
300   for( y = st->top; y < st->fheight; y++)
301     {
302       for( x = 0; x < st->fwidth; x++)
303         {
304           v1 = (int)*ptr1;
305           v2 = (int)*(ptr1 + 1);
306           v3 = (int)*(ptr1 + st->fwidth + 2);
307           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
308           ptr1++;
309           *ptr++ = (unsigned int)st->ctab[v1];
310           *ptr   = (unsigned int)st->ctab[(v1 + v2) >> 1];
311           ptr   += st->width - 1;
312           *ptr++ = (unsigned int)st->ctab[(v1 + v3) >> 1];
313           *ptr   = (unsigned int)st->ctab[(v1 + v4) >> 1];
314           ptr   -= st->width - 1;
315         }
316       ptr  += st->width;
317       ptr1 += 2;
318     }
319 }
320
321 static void
322 Flame2Image24(struct state *st)
323 {
324   int x,y;
325   unsigned char *ptr;
326   unsigned char *ptr1;
327   int v1,v2,v3,v4;
328
329   ptr  = (unsigned char *)st->xim->data;
330   ptr += (st->top << 1) * st->xim->bytes_per_line;
331   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
332
333   for( y = st->top; y < st->fheight; y++)
334     {
335       unsigned char *last_ptr = ptr;
336       for( x = 0; x < st->fwidth; x++)
337         {
338           v1 = (int)*ptr1;
339           v2 = (int)*(ptr1 + 1);
340           v3 = (int)*(ptr1 + st->fwidth + 2);
341           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
342           ptr1++;
343
344           ptr[2] = ((unsigned int)st->ctab[v1] & 0x00FF0000) >> 16;
345           ptr[1] = ((unsigned int)st->ctab[v1] & 0x0000FF00) >> 8;
346           ptr[0] = ((unsigned int)st->ctab[v1] & 0x000000FF);
347           ptr += 3;
348
349           ptr[2] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x00FF0000) >> 16;
350           ptr[1] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x0000FF00) >> 8;
351           ptr[0] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x000000FF);
352           ptr += ((st->width - 1) * 3);
353
354           ptr[2] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x00FF0000) >> 16;
355           ptr[1] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x0000FF00) >> 8;
356           ptr[0] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x000000FF);
357           ptr += 3;
358
359           ptr[2] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x00FF0000) >> 16;
360           ptr[1] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x0000FF00) >> 8;
361           ptr[0] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x000000FF);
362           ptr -= ((st->width - 1) * 3);
363         }
364
365       ptr = last_ptr + (st->xim->bytes_per_line << 1);
366       ptr1 += 2;
367     }
368 }
369
370 static void
371 Flame2Image8(struct state *st)
372 {
373   int x,y;
374   unsigned char *ptr;
375   unsigned char *ptr1;
376   int v1,v2,v3,v4;
377
378   ptr  = (unsigned char *)st->xim->data;
379   ptr += (st->top << 1) * st->width;
380   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
381
382   for(y=st->top;y<st->fheight;y++)
383     {
384       for(x=0;x<st->fwidth;x++)
385         {
386           v1 = (int)*ptr1;
387           v2 = (int)*(ptr1 + 1);
388           v3 = (int)*(ptr1 + st->fwidth + 2);
389           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
390           ptr1++;
391           *ptr++ = (unsigned char)st->ctab[v1];
392           *ptr   = (unsigned char)st->ctab[(v1 + v2) >> 1];
393           ptr   += st->width - 1;
394           *ptr++ = (unsigned char)st->ctab[(v1 + v3) >> 1];
395           *ptr   = (unsigned char)st->ctab[(v1 + v4) >> 1];
396           ptr   -= st->width - 1;
397         }
398       ptr  += st->width;
399       ptr1 += 2;
400     }
401 }
402
403 static void
404 Flame2Image1234567(struct state *st)
405 {
406   int x,y;
407   unsigned char *ptr1;
408   int v1,v2,v3,v4;
409
410   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
411
412   for( y = st->top; y < st->fheight; y++)
413     {
414       for( x = 0; x < st->fwidth; x++)
415         {
416           v1 = (int)*ptr1;
417           v2 = (int)*(ptr1 + 1);
418           v3 = (int)*(ptr1 + st->fwidth + 2);
419           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
420           ptr1++;
421           XPutPixel(st->xim,(x << 1),    (y << 1),    st->ctab[v1]);
422           XPutPixel(st->xim,(x << 1) + 1,(y << 1),    st->ctab[(v1 + v2) >> 1]);
423           XPutPixel(st->xim,(x << 1),    (y << 1) + 1,st->ctab[(v1 + v3) >> 1]);
424           XPutPixel(st->xim,(x << 1) + 1,(y << 1) + 1,st->ctab[(v1 + v4) >> 1]);
425         }
426     }
427 }
428
429 static void
430 Flame2Image(struct state *st)
431 {
432   switch (st->xim->bits_per_pixel)
433     {
434     case 32: Flame2Image32(st); break;
435     case 24: Flame2Image24(st); break;
436     case 16: Flame2Image16(st); break;
437     case 8:  Flame2Image8(st);  break;
438     default:
439       if (st->xim->bits_per_pixel <= 7)
440         Flame2Image1234567(st);
441       else
442         abort();
443       break;
444     }
445 }
446
447
448 static void
449 FlameActive(struct state *st)
450 {
451   int x,v1;
452   unsigned char *ptr1;
453    
454   ptr1 = st->flame + ((st->fheight + 1) * (st->fwidth + 2));
455
456   for (x = 0; x < st->fwidth + 2; x++)
457     {
458       v1      = *ptr1;
459       v1     += ((random() % st->variance) - st->vartrend);
460       *ptr1++ = v1 % 255;
461     }
462
463   if (st->bloom)
464     {
465       v1= (random() % 100);
466       if (v1 == 10)
467         st->residual += (random()%10);
468       else if (v1 == 20)
469         st->hspread += (random()%15);
470       else if (v1 == 30)
471         st->vspread += (random()%20);
472     }
473
474   st->residual = ((st->iresidual* 10) + (st->residual *90)) / 100;
475   st->hspread  = ((st->ihspread * 10) + (st->hspread  *90)) / 100;
476   st->vspread  = ((st->ivspread * 10) + (st->vspread  *90)) / 100;
477 }
478
479
480 static void
481 FlameAdvance(struct state *st)
482 {
483   int x,y;
484   unsigned char *ptr2;
485   int newtop = st->top;
486
487   for (y = st->fheight + 1; y >= st->top; y--)
488     {
489       int used = 0;
490       unsigned char *ptr1 = st->flame + 1 + (y * (st->fwidth + 2));
491       for (x = 0; x < st->fwidth; x++)
492         {
493           int v1 = (int)*ptr1;
494           int v2, v3;
495           if (v1 > 0)
496             {
497               used = 1;
498               ptr2 = ptr1 - st->fwidth - 2;
499               v3   = (v1 * st->vspread) >> 8;
500               v2   = (int)*(ptr2);
501               v2  += v3;
502               if (v2 > MAX_VAL) 
503                 v2 = MAX_VAL;
504
505               *(ptr2) = (unsigned char)v2;
506               v3  = (v1 * st->hspread) >> 8;
507               v2  = (int)*(ptr2 + 1);
508               v2 += v3;
509               if (v2 > MAX_VAL) 
510                 v2 = MAX_VAL;
511           
512               *(ptr2 + 1) = (unsigned char)v2;
513               v2          = (int)*(ptr2 - 1);
514               v2         += v3;
515               if (v2 > MAX_VAL) 
516                 v2 = MAX_VAL;
517           
518               *(ptr2 - 1) = (unsigned char)v2;
519         
520               if (y < st->fheight + 1)
521                 {
522                   v1    = (v1 * st->residual) >> 8;
523                   *ptr1 = (unsigned char)v1;
524                 }
525             }
526           ptr1++;
527           if (used) 
528             newtop = y - 1;
529         }
530  
531       /* clean up the right gutter */
532       {
533         int v1 = (int)*ptr1;
534         v1 = (v1 * st->residual) >> 8;
535         *ptr1 = (unsigned char)v1;
536       }
537     }
538
539   st->top = newtop - 1;
540
541   if (st->top < 1)
542     st->top = 1;
543 }
544
545
546 static void
547 FlameFill(struct state *st, int val)
548 {
549   int x, y;
550   for (y = 0; y < st->fheight + 1; y++)
551     {
552       unsigned char *ptr1 = st->flame + 1 + (y * (st->fwidth + 2));
553       for (x = 0; x < st->fwidth; x++)
554         {
555           *ptr1 = val;
556           ptr1++;
557         }
558     }
559 }
560
561
562 static void
563 FlamePasteData(struct state *st,
564                unsigned char *d, int xx, int yy, int w, int h)
565 {
566   unsigned char *ptr1,*ptr2;
567   ptr2 = d;
568
569   if (xx < 0) xx = 0;
570   if (yy < 0) yy = 0;
571
572   if ((xx >= 0) &&
573       (yy >= 0) &&
574       (xx + w <= st->fwidth) &&
575       (yy + h <= st->fheight))
576     {
577       int x, y;
578       for (y = 0; y < h; y++)
579         {
580           ptr1 = st->flame + 1 + xx + ((yy + y) * (st->fwidth + 2));
581           for (x = 0; x < w; x++)
582             {
583               if (*ptr2 / 24)
584                 *ptr1 += random() % (*ptr2 / 24);
585
586               ptr1++;
587               ptr2++;
588             }
589         }
590     }
591   else
592     {
593       static Bool warned = False;
594       if (!warned)
595         {
596           fprintf (stderr, "%s: st->window is %dx%d; image must be "
597                    "smaller than %dx%d (not %dx%d).\n",
598                    progname, st->width, st->height, st->fwidth, st->fheight, w, h);
599           warned = True;
600         }
601     }
602 }
603
604
605 static unsigned char *
606 loadBitmap(struct state *st, int *w, int *h)
607 {
608   char *bitmap_name = get_string_resource (st->dpy, "bitmap", "Bitmap");
609
610   if (!bitmap_name ||
611       !*bitmap_name ||
612       !strcmp(bitmap_name, "none"))
613     ;
614   else if (!strcmp(bitmap_name, "(default)"))   /* use the builtin */
615     {
616       XImage *ximage;
617       unsigned char *result, *o;
618       char *bits = (char *) malloc (sizeof(bob_bits));
619       int x, y;
620       int scale = ((st->width > bob_width * 11) ? 2 : 1);
621  
622       memcpy (bits, bob_bits, sizeof(bob_bits));
623       ximage = XCreateImage (st->dpy, st->visual, 1, XYBitmap, 0, bits,
624                              bob_width, bob_height, 8, 0);
625       ximage->byte_order = LSBFirst;
626       ximage->bitmap_bit_order = LSBFirst;
627       *w = ximage->width * scale;
628       *h = ximage->height * scale;
629       o = result = (unsigned char *) malloc ((*w * scale) * (*h * scale));
630       for (y = 0; y < *h; y++)
631         for (x = 0; x < *w; x++)
632           *o++ = (XGetPixel(ximage, x/scale, y/scale) ? 255 : 0);
633        
634       return result;
635     }
636   else  /* load a bitmap file */
637 #ifdef HAVE_COCOA
638     abort(); /* #### fix me */
639 #else
640    {
641       Pixmap pixmap =
642         xpm_file_to_pixmap (st->dpy, st->window, bitmap_name, &st->width, &st->height, 0);
643       XImage *image;
644       int x, y;
645       unsigned char *result, *o;
646       XColor colors[256];
647       Bool cmap_p = has_writable_cells (st->screen, st->visual);
648
649       if (cmap_p)
650         {
651           int i;
652           for (i = 0; i < countof (colors); i++)
653             colors[i].pixel = i;
654           XQueryColors (st->dpy, st->colormap, colors, countof (colors));
655         }
656
657       image = XGetImage (st->dpy, pixmap, 0, 0, st->width, st->height, ~0L, ZPixmap);
658       XFreePixmap(st->dpy, pixmap);
659
660       result = (unsigned char *) malloc (st->width * st->height);
661       o = result;
662       for (y = 0; y < st->height; y++)
663         for (x = 0; x < st->width; x++)
664           {
665             int rgba = XGetPixel (image, x, y);
666             int gray;
667             if (cmap_p)
668               gray = ((200 - ((((colors[rgba].red   >> 8) & 0xFF) +
669                               ((colors[rgba].green >> 8) & 0xFF) +
670                               ((colors[rgba].blue  >> 8) & 0xFF))
671                              >> 1))
672                       & 0xFF);
673             else
674               /* This is *so* not handling all the cases... */
675               gray = (image->depth > 16
676                       ? ((((rgba >> 24) & 0xFF) +
677                           ((rgba >> 16) & 0xFF) +
678                           ((rgba >>  8) & 0xFF) +
679                           ((rgba      ) & 0xFF)) >> 2)
680                       : ((((rgba >> 12) & 0x0F) +
681                           ((rgba >>  8) & 0x0F) +
682                           ((rgba >>  4) & 0x0F) +
683                           ((rgba      ) & 0x0F)) >> 1));
684
685             *o++ = 255 - gray;
686           }
687
688       XFree (image->data);
689       image->data = 0;
690       XDestroyImage (image);
691
692       *w = st->width;
693       *h = st->height;
694       return result;
695     }
696 #endif /* !HAVE_COCOA */
697
698   *w = 0;
699   *h = 0;
700   return 0;
701
702 }
703
704 static void *
705 xflame_init (Display *dpy, Window win)
706 {
707   struct state *st = (struct state *) calloc (1, sizeof(*st));
708   st->dpy = dpy;
709   st->window = win;
710   st->baseline = get_integer_resource (dpy, "bitmapBaseline", "Integer");
711   st->delay = get_integer_resource (dpy, "delay", "Integer");
712   st->xim      = NULL;
713   st->top      = 1;
714   st->flame    = NULL;
715
716   GetXInfo(st);
717   InitColors(st);
718   st->theim = loadBitmap(st, &st->theimx, &st->theimy);
719
720   /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
721      makes it hard for us to react to window resizing.  So, punt for now.  The
722      size of the window at startup is the size it will stay.
723   */
724   GetXInfo(st);
725
726   MakeImage(st);
727   InitFlame(st);
728   FlameFill(st,0);
729
730   return st;
731 }
732
733 static unsigned long
734 xflame_draw (Display *dpy, Window win, void *closure)
735 {
736   struct state *st = (struct state *) closure;
737   FlameActive(st);
738
739   if (st->theim)
740     FlamePasteData(st, st->theim, (st->fwidth - st->theimx) / 2,
741                    st->fheight - st->theimy - st->baseline, st->theimx, st->theimy);
742
743   FlameAdvance(st);
744   Flame2Image(st);
745   DisplayImage(st);
746
747   return st->delay;
748 }
749
750 static void
751 xflame_reshape (Display *dpy, Window window, void *closure, 
752                  unsigned int w, unsigned int h)
753 {
754 }
755
756 static Bool
757 xflame_event (Display *dpy, Window window, void *closure, XEvent *event)
758 {
759   return False;
760 }
761
762 static void
763 xflame_free (Display *dpy, Window window, void *closure)
764 {
765 }
766
767
768 \f
769
770 static const char *xflame_defaults [] = {
771   ".background:     black",
772   ".foreground:     #FFAF5F",
773   "*bitmap:         (default)",
774   "*bitmapBaseline: 20",
775   "*delay:          10000",
776   "*hspread:        30",
777   "*vspread:        97",
778   "*residual:       99",
779   "*variance:       50",
780   "*vartrend:       20",
781   "*bloom:          True",   
782
783 #ifdef HAVE_XSHM_EXTENSION
784   "*useSHM: False",   /* xshm turns out not to help. */
785 #endif /* HAVE_XSHM_EXTENSION */
786    0
787 };
788
789 static XrmOptionDescRec xflame_options [] = {
790   { "-foreground",".foreground",     XrmoptionSepArg, 0 },
791   { "-fg",        ".foreground",     XrmoptionSepArg, 0 },
792   { "-delay",     ".delay",          XrmoptionSepArg, 0 },
793   { "-bitmap",    ".bitmap",         XrmoptionSepArg, 0 },
794   { "-baseline",  ".bitmapBaseline", XrmoptionSepArg, 0 },
795   { "-hspread",   ".hspread",        XrmoptionSepArg, 0 },
796   { "-vspread",   ".vspread",        XrmoptionSepArg, 0 },
797   { "-residual",  ".residual",       XrmoptionSepArg, 0 },
798   { "-variance",  ".variance",       XrmoptionSepArg, 0 },
799   { "-vartrend",  ".vartrend",       XrmoptionSepArg, 0 },
800   { "-bloom",     ".bloom",          XrmoptionNoArg, "True" },
801   { "-no-bloom",  ".bloom",          XrmoptionNoArg, "False" },
802 #ifdef HAVE_XSHM_EXTENSION
803   { "-shm",       ".useSHM",         XrmoptionNoArg, "True" },
804   { "-no-shm",    ".useSHM",         XrmoptionNoArg, "False" },
805 #endif /* HAVE_XSHM_EXTENSION */
806   { 0, 0, 0, 0 }
807 };
808
809
810 XSCREENSAVER_MODULE ("XFlame", xflame)