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