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