25283401fea17b10e5a89b5301f6bcf5b2841dba
[xscreensaver] / hacks / xflame.c
1 /* xflame, Copyright (c) 1996-2018 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 "ximage-loader.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/gen/bob_png.h"
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 Pixmap
588 double_pixmap (Display *dpy, Visual *visual, int depth, Pixmap pixmap,
589                int pix_w, int pix_h)
590 {
591   int x, y;
592   Pixmap p2 = XCreatePixmap(dpy, pixmap, pix_w*2, pix_h*2, depth);
593   XImage *i1 = XGetImage (dpy, pixmap, 0, 0, pix_w, pix_h, ~0L, 
594                           (depth == 1 ? XYPixmap : ZPixmap));
595   XImage *i2 = XCreateImage (dpy, visual, depth, 
596                              (depth == 1 ? XYPixmap : ZPixmap), 0, 0,
597                              pix_w*2, pix_h*2, 8, 0);
598   XGCValues gcv;
599   GC gc = XCreateGC (dpy, p2, 0, &gcv);
600   i2->data = (char *) calloc(i2->height, i2->bytes_per_line);
601   for (y = 0; y < pix_h; y++)
602     for (x = 0; x < pix_w; x++)
603       {
604         unsigned long p = XGetPixel(i1, x, y);
605         XPutPixel(i2, x*2,   y*2,   p);
606         XPutPixel(i2, x*2+1, y*2,   p);
607         XPutPixel(i2, x*2,   y*2+1, p);
608         XPutPixel(i2, x*2+1, y*2+1, p);
609       }
610   free(i1->data); i1->data = 0;
611   XDestroyImage(i1);
612   XPutImage(dpy, p2, gc, i2, 0, 0, 0, 0, i2->width, i2->height);
613   XFreeGC (dpy, gc);
614   free(i2->data); i2->data = 0;
615   XDestroyImage(i2);
616   XFreePixmap(dpy, pixmap);
617   return p2;
618 }
619
620
621 static unsigned char *
622 reformat_pixmap (struct state *st, Pixmap pixmap, Pixmap mask, int *w, int *h)
623 {
624   XImage *image = 0, *mimage = 0;
625   int x, y;
626   unsigned char *result, *o;
627   XColor colors[256];
628   Bool cmap_p = has_writable_cells (st->screen, st->visual);
629
630   while (*w < st->width  / 10 &&
631          *h < st->height / 10)
632     {
633       pixmap = double_pixmap (st->dpy, st->visual, st->depth, pixmap, *w, *h);
634       if (mask)
635         mask = double_pixmap (st->dpy, st->visual, st->depth, mask, *w, *h);
636       *w *= 2;
637       *h *= 2;
638     }
639
640   if (cmap_p)
641     {
642       int i;
643       for (i = 0; i < countof (colors); i++)
644         colors[i].pixel = i;
645       XQueryColors (st->dpy, st->colormap, colors, countof (colors));
646     }
647
648   image  = XGetImage (st->dpy, pixmap, 0, 0, *w, *h, ~0L, ZPixmap);
649   XFreePixmap(st->dpy, pixmap);
650
651   if (mask)
652     {
653       mimage = XGetImage (st->dpy, mask,   0, 0, *w, *h, ~0L, ZPixmap);
654       XFreePixmap(st->dpy, mask);
655     }
656
657   result = (unsigned char *) malloc (image->width * image->height);
658   o = result;
659   for (y = 0; y < image->height; y++)
660     for (x = 0; x < image->width; x++)
661       {
662         unsigned long rgb = XGetPixel (image, x, y);
663         unsigned long a   = mimage ? XGetPixel (mimage, x, y) : 1;
664         unsigned long gray;
665         if (!a)
666           rgb = 0xFFFFFFFFL;
667         if (cmap_p)
668           gray = ((200 - ((((colors[rgb].red   >> 8) & 0xFF) +
669                            ((colors[rgb].green >> 8) & 0xFF) +
670                            ((colors[rgb].blue  >> 8) & 0xFF))
671                           >> 1))
672                   & 0xFF);
673         else
674           /* This is *so* not handling all the cases... */
675           gray = (image->depth > 16
676                   ? ((((rgb >> 24) & 0xFF) +
677                       ((rgb >> 16) & 0xFF) +
678                       ((rgb >>  8) & 0xFF) +
679                       ((rgb      ) & 0xFF)) >> 2)
680                   : ((((rgb >> 12) & 0x0F) +
681                       ((rgb >>  8) & 0x0F) +
682                       ((rgb >>  4) & 0x0F) +
683                       ((rgb      ) & 0x0F)) >> 1));
684
685         *o++ = 255 - gray;
686       }
687
688   *w = image->width;
689   *h = image->height;
690   XDestroyImage (image);
691   if (mimage)
692     XDestroyImage (mimage);
693
694   return result;
695
696 }
697
698
699 static unsigned char *
700 loadBitmap(struct state *st, int *w, int *h)
701 {
702 # ifdef HAVE_JWXYZ
703   const char *bitmap_name = "(default)"; /* #### always use builtin */
704 # else
705   char *bitmap_name = get_string_resource (st->dpy, "bitmap", "Bitmap");
706 # endif
707   Pixmap p = 0, mask = 0;
708   if (!bitmap_name ||
709       !*bitmap_name ||
710       !strcmp(bitmap_name, "none"))
711     ;
712   else if (!strcmp(bitmap_name, "(default)"))   /* use the builtin */
713     p = image_data_to_pixmap (st->dpy, st->window,
714                               bob_png, sizeof(bob_png),
715                               w, h, &mask);
716   else  /* load a bitmap file */
717     p = file_to_pixmap (st->dpy, st->window, bitmap_name,
718                         &st->width, &st->height, 0);
719
720   if (!p) return 0;
721   return reformat_pixmap (st, p, mask, w, h);
722 }
723
724 static void *
725 xflame_init (Display *dpy, Window win)
726 {
727   struct state *st = (struct state *) calloc (1, sizeof(*st));
728   st->dpy = dpy;
729   st->window = win;
730   st->baseline = get_integer_resource (dpy, "bitmapBaseline", "Integer");
731   st->delay = get_integer_resource (dpy, "delay", "Integer");
732   st->xim      = NULL;
733   st->top      = 1;
734   st->flame    = NULL;
735
736   GetXInfo(st);
737   InitColors(st);
738   st->theim = loadBitmap(st, &st->theimx, &st->theimy);
739
740   MakeImage(st);
741   InitFlame(st);
742   FlameFill(st,0);
743
744   return st;
745 }
746
747 static unsigned long
748 xflame_draw (Display *dpy, Window win, void *closure)
749 {
750   struct state *st = (struct state *) closure;
751   FlameActive(st);
752
753   if (st->theim)
754     FlamePasteData(st, st->theim, (st->fwidth - st->theimx) / 2,
755                    st->fheight - st->theimy - st->baseline, st->theimx, st->theimy);
756
757   FlameAdvance(st);
758   Flame2Image(st);
759   DisplayImage(st);
760
761   return st->delay;
762 }
763
764 static void
765 xflame_reshape (Display *dpy, Window window, void *closure, 
766                  unsigned int w, unsigned int h)
767 {
768   struct state *st = (struct state *) closure;
769   GetXInfo(st);
770   MakeImage(st);
771   InitFlame(st);
772   FlameFill(st,0);
773   XClearWindow (dpy, window);
774 }
775
776 static Bool
777 xflame_event (Display *dpy, Window window, void *closure, XEvent *event)
778 {
779   return False;
780 }
781
782 static void
783 xflame_free (Display *dpy, Window window, void *closure)
784 {
785 }
786
787
788 \f
789
790 static const char *xflame_defaults [] = {
791   ".background:     black",
792   ".foreground:     #FFAF5F",
793   "*fpsTop:         true",
794   "*fpsSolid:       true",
795   "*bitmap:         (default)",
796   "*bitmapBaseline: 20",
797   "*delay:          10000",
798   "*hspread:        30",
799   "*vspread:        97",
800   "*residual:       99",
801   "*variance:       50",
802   "*vartrend:       20",
803   "*bloom:          True",   
804
805 #ifdef HAVE_XSHM_EXTENSION
806   "*useSHM: False",   /* xshm turns out not to help. */
807 #endif /* HAVE_XSHM_EXTENSION */
808    0
809 };
810
811 static XrmOptionDescRec xflame_options [] = {
812   { "-foreground",".foreground",     XrmoptionSepArg, 0 },
813   { "-fg",        ".foreground",     XrmoptionSepArg, 0 },
814   { "-delay",     ".delay",          XrmoptionSepArg, 0 },
815   { "-bitmap",    ".bitmap",         XrmoptionSepArg, 0 },
816   { "-baseline",  ".bitmapBaseline", XrmoptionSepArg, 0 },
817   { "-hspread",   ".hspread",        XrmoptionSepArg, 0 },
818   { "-vspread",   ".vspread",        XrmoptionSepArg, 0 },
819   { "-residual",  ".residual",       XrmoptionSepArg, 0 },
820   { "-variance",  ".variance",       XrmoptionSepArg, 0 },
821   { "-vartrend",  ".vartrend",       XrmoptionSepArg, 0 },
822   { "-bloom",     ".bloom",          XrmoptionNoArg, "True" },
823   { "-no-bloom",  ".bloom",          XrmoptionNoArg, "False" },
824 #ifdef HAVE_XSHM_EXTENSION
825   { "-shm",       ".useSHM",         XrmoptionNoArg, "True" },
826   { "-no-shm",    ".useSHM",         XrmoptionNoArg, "False" },
827 #endif /* HAVE_XSHM_EXTENSION */
828   { 0, 0, 0, 0 }
829 };
830
831
832 XSCREENSAVER_MODULE ("XFlame", xflame)