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