bd2be990f36923e8e5da306fb6affb39ad702ba9
[xscreensaver] / hacks / xflame.c
1 /* xflame, Copyright (c) 1996-1999 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
44  */
45
46
47 /* portions by Daniel Zahn <stumpy@religions.com> */
48
49
50 #include "screenhack.h"
51 #include <X11/Xutil.h>
52 #include <limits.h>
53
54 #ifdef HAVE_XSHM_EXTENSION
55 # include "xshm.h"
56 #endif /* HAVE_XSHM_EXTENSION */
57
58 #ifdef HAVE_XPM
59 # include <X11/xpm.h>
60 # ifndef PIXEL_ALREADY_TYPEDEFED
61 #  define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
62 # endif
63 #endif
64
65 #ifdef HAVE_XMU
66 # ifndef VMS
67 #  include <X11/Xmu/Drawing.h>
68 # else  /* VMS */
69 #  include <Xmu/Drawing.h>
70 # endif /* VMS */
71 #endif /* HAVE_XMU */
72
73 #include "images/bob.xbm"
74
75 #define MAX_VAL             255
76
77 static Display         *display;
78 static Window          window;
79 static int             depth;
80 static int             width;
81 static int             height;
82 static Colormap        colormap;
83 static Visual          *visual;
84 static Bool            shared;
85 static Bool            bloom;
86 static XImage          *xim;
87 #ifdef HAVE_XSHM_EXTENSION
88 static XShmSegmentInfo shminfo;
89 #endif /* HAVE_XSHM_EXTENSION */
90 static GC              gc;
91 static int             ctab[256];
92
93 static unsigned char  *flame;
94 static unsigned char  *theim;
95 static int             fwidth;
96 static int             fheight;
97 static int             top;
98 static int             hspread;
99 static int             vspread;
100 static int             residual;
101
102 static int ihspread;
103 static int ivspread;
104 static int iresidual;
105 static int variance;
106 static int vartrend;
107
108 static void
109 GetXInfo(Display *disp, Window win)
110 {
111   XWindowAttributes xwa;
112    
113   XGetWindowAttributes(disp,win,&xwa);
114
115   window   = win;
116   display  = disp;
117   colormap = xwa.colormap;
118   depth    = xwa.depth;
119   visual   = xwa.visual;
120   width    = xwa.width;
121   height   = xwa.height;
122
123   if (width%2)
124     width++;
125   if (height%2)
126     height++;
127 }
128
129 static void
130 MakeImage(void)
131 {
132   XGCValues gcv;
133
134 #ifdef HAVE_XSHM_EXTENSION
135   shared = True;
136   xim = create_xshm_image (display, visual, depth, ZPixmap, NULL,
137                            &shminfo, width, height);
138 #else  /* !HAVE_XSHM_EXTENSION */
139   xim = 0;
140 #endif /* !HAVE_XSHM_EXTENSION */
141
142   if (!xim)
143     {
144       shared = False;
145       xim = XCreateImage (display, visual, depth, ZPixmap, 0, NULL,
146                           width, height, 32, 0);
147       if (xim)
148         xim->data = (char *) calloc(xim->height, xim->bytes_per_line);
149       if (!xim || !xim->data)
150         {
151           fprintf(stderr,"%s: out of memory.\n", progname);
152           exit(1);
153         }
154     }
155
156   gc = XCreateGC(display,window,0,&gcv);
157   if (!gc) exit (1);
158 }
159
160
161 static void
162 InitColors(void)
163 {
164   int i = 0, j = 0, red = 0, green = 0, blue = 0;
165   XColor fg;
166
167   /* Make it possible to set the color of the flames, 
168      by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
169   */
170   fg.pixel = get_pixel_resource ("foreground", "Foreground",
171                                  display, colormap);
172   XQueryColor (display, colormap, &fg);
173
174   red   = 255 - (fg.red   >> 8);
175   green = 255 - (fg.green >> 8);
176   blue  = 255 - (fg.blue  >> 8);
177
178
179   for (i = 0; i < 256 * 2; i += 2)
180     {
181       XColor xcl;
182       int r = (i - red)   * 3;
183       int g = (i - green) * 3;
184       int b = (i - blue)  * 3;
185     
186       if (r < 0)   r = 0;
187       if (r > 255) r = 255;
188       if (g < 0)   g = 0;
189       if (g > 255) g = 255;
190       if (b < 0)   b = 0;
191       if (b > 255) b = 255;
192
193       xcl.red   = (unsigned short)((r << 8) | r);
194       xcl.green = (unsigned short)((g << 8) | g);
195       xcl.blue  = (unsigned short)((b << 8) | b);
196       xcl.flags = DoRed | DoGreen | DoBlue;
197
198       XAllocColor(display,colormap,&xcl);
199
200       ctab[j++] = (int)xcl.pixel;
201     }
202 }
203
204
205 static void
206 DisplayImage(void)
207 {
208 #ifdef HAVE_XSHM_EXTENSION
209   if (shared)
210     XShmPutImage(display, window, gc, xim, 0,(top - 1) << 1, 0,
211                  (top - 1) << 1, width, height - ((top - 1) << 1), False);
212   else
213 #endif /* HAVE_XSHM_EXTENSION */
214     XPutImage(display, window, gc, xim, 0, (top - 1) << 1, 0,
215               (top - 1) << 1, width, height - ((top - 1) << 1));
216 }
217
218
219 static void
220 InitFlame(void)
221 {
222   fwidth  = width / 2;
223   fheight = height / 2;
224   flame   = (unsigned char *) malloc((fwidth + 2) * (fheight + 2)
225                                      * sizeof(unsigned char));
226
227   if (!flame)
228     {
229       fprintf(stderr,"%s: out of memory\n", progname);
230       exit(1);
231     }
232
233   top      = 1;
234   ihspread  = get_integer_resource("hspread", "Integer");
235   ivspread  = get_integer_resource("vspread", "Integer");
236   iresidual = get_integer_resource("residual", "Integer");
237   variance  = get_integer_resource("variance", "Integer");
238   vartrend  = get_integer_resource("vartrend", "Integer");
239   bloom     = get_boolean_resource("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 (ihspread, "hspread");
247   THROTTLE (ivspread, "vspread");
248   THROTTLE (iresidual,"residual");
249   THROTTLE (variance, "variance");
250   THROTTLE (vartrend, "vartrend");
251 # undef THROTTLE
252
253
254
255   hspread = ihspread;
256   vspread = ivspread;
257   residual = iresidual;
258 }
259
260
261 static void
262 Flame2Image16(void)
263 {
264   int x,y;
265   unsigned short *ptr;
266   unsigned char *ptr1;
267   int v1,v2,v3,v4;
268
269   ptr  = (unsigned short *)xim->data;
270   ptr += (top << 1) * width;
271   ptr1 = flame + 1 + (top * (fwidth + 2));
272
273   for(y = top; y < fheight; y++)
274     {
275       for( x = 0; x < fwidth; x++)
276         {
277           v1 = (int)*ptr1;
278           v2 = (int)*(ptr1 + 1);
279           v3 = (int)*(ptr1 + fwidth + 2);
280           v4 = (int)*(ptr1 + fwidth + 2 + 1);
281           ptr1++;
282           *ptr++ = (unsigned short)ctab[v1];
283           *ptr   = (unsigned short)ctab[(v1 + v2) >> 1];
284           ptr   += width - 1;
285           *ptr++ = (unsigned short)ctab[(v1 + v3) >> 1];
286           *ptr   = (unsigned short)ctab[(v1 + v4) >> 1];
287           ptr   -= width - 1;
288         }
289       ptr  += width;
290       ptr1 += 2;
291     }
292 }
293
294 static void
295 Flame2Image32(void)
296 {
297   int x,y;
298   unsigned int *ptr;
299   unsigned char *ptr1;
300   int v1,v2,v3,v4;
301
302   ptr  = (unsigned int *)xim->data;
303   ptr += (top << 1) * width;
304   ptr1 = flame + 1 + (top * (fwidth + 2));
305
306   for( y = top; y < fheight; y++)
307     {
308       for( x = 0; x < fwidth; x++)
309         {
310           v1 = (int)*ptr1;
311           v2 = (int)*(ptr1 + 1);
312           v3 = (int)*(ptr1 + fwidth + 2);
313           v4 = (int)*(ptr1 + fwidth + 2 + 1);
314           ptr1++;
315           *ptr++ = (unsigned int)ctab[v1];
316           *ptr   = (unsigned int)ctab[(v1 + v2) >> 1];
317           ptr   += width - 1;
318           *ptr++ = (unsigned int)ctab[(v1 + v3) >> 1];
319           *ptr   = (unsigned int)ctab[(v1 + v4) >> 1];
320           ptr   -= width - 1;
321         }
322       ptr  += width;
323       ptr1 += 2;
324     }
325 }
326
327 static void
328 Flame2Image24(void)
329 {
330   int x,y;
331   unsigned char *ptr;
332   unsigned char *ptr1;
333   int v1,v2,v3,v4;
334
335   ptr  = (unsigned char *)xim->data;
336   ptr += (top << 1) * xim->bytes_per_line;
337   ptr1 = flame + 1 + (top * (fwidth + 2));
338
339   for( y = top; y < fheight; y++)
340     {
341       unsigned char *last_ptr = ptr;
342       for( x = 0; x < fwidth; x++)
343         {
344           v1 = (int)*ptr1;
345           v2 = (int)*(ptr1 + 1);
346           v3 = (int)*(ptr1 + fwidth + 2);
347           v4 = (int)*(ptr1 + fwidth + 2 + 1);
348           ptr1++;
349
350           ptr[2] = ((unsigned int)ctab[v1] & 0x00FF0000) >> 16;
351           ptr[1] = ((unsigned int)ctab[v1] & 0x0000FF00) >> 8;
352           ptr[0] = ((unsigned int)ctab[v1] & 0x000000FF);
353           ptr += 3;
354
355           ptr[2] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x00FF0000) >> 16;
356           ptr[1] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x0000FF00) >> 8;
357           ptr[0] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x000000FF);
358           ptr += ((width - 1) * 3);
359
360           ptr[2] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x00FF0000) >> 16;
361           ptr[1] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x0000FF00) >> 8;
362           ptr[0] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x000000FF);
363           ptr += 3;
364
365           ptr[2] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x00FF0000) >> 16;
366           ptr[1] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x0000FF00) >> 8;
367           ptr[0] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x000000FF);
368           ptr -= ((width - 1) * 3);
369         }
370
371       ptr = last_ptr + (xim->bytes_per_line << 1);
372       ptr1 += 2;
373     }
374 }
375
376 static void
377 Flame2Image8(void)
378 {
379   int x,y;
380   unsigned char *ptr;
381   unsigned char *ptr1;
382   int v1,v2,v3,v4;
383
384   ptr  = (unsigned char *)xim->data;
385   ptr += (top << 1) * width;
386   ptr1 = flame + 1 + (top * (fwidth + 2));
387
388   for(y=top;y<fheight;y++)
389     {
390       for(x=0;x<fwidth;x++)
391         {
392           v1 = (int)*ptr1;
393           v2 = (int)*(ptr1 + 1);
394           v3 = (int)*(ptr1 + fwidth + 2);
395           v4 = (int)*(ptr1 + fwidth + 2 + 1);
396           ptr1++;
397           *ptr++ = (unsigned char)ctab[v1];
398           *ptr   = (unsigned char)ctab[(v1 + v2) >> 1];
399           ptr   += width - 1;
400           *ptr++ = (unsigned char)ctab[(v1 + v3) >> 1];
401           *ptr   = (unsigned char)ctab[(v1 + v4) >> 1];
402           ptr   -= width - 1;
403         }
404       ptr  += width;
405       ptr1 += 2;
406     }
407 }
408
409 static void
410 Flame2Image1234567(void)
411 {
412   int x,y;
413   unsigned char *ptr1;
414   int v1,v2,v3,v4;
415
416   ptr1 = flame + 1 + (top * (fwidth + 2));
417
418   for( y = top; y < fheight; y++)
419     {
420       for( x = 0; x < fwidth; x++)
421         {
422           v1 = (int)*ptr1;
423           v2 = (int)*(ptr1 + 1);
424           v3 = (int)*(ptr1 + fwidth + 2);
425           v4 = (int)*(ptr1 + fwidth + 2 + 1);
426           ptr1++;
427           XPutPixel(xim,(x << 1),    (y << 1),    ctab[v1]);
428           XPutPixel(xim,(x << 1) + 1,(y << 1),    ctab[(v1 + v2) >> 1]);
429           XPutPixel(xim,(x << 1),    (y << 1) + 1,ctab[(v1 + v3) >> 1]);
430           XPutPixel(xim,(x << 1) + 1,(y << 1) + 1,ctab[(v1 + v4) >> 1]);
431         }
432     }
433 }
434
435 static void
436 Flame2Image(void)
437 {
438   switch (xim->bits_per_pixel)
439     {
440     case 32: Flame2Image32(); break;
441     case 24: Flame2Image24(); break;
442     case 16: Flame2Image16(); break;
443     case 8:  Flame2Image8();  break;
444     default:
445       if (xim->bits_per_pixel <= 7)
446         Flame2Image1234567();
447       else
448         abort();
449       break;
450     }
451 }
452
453
454 static void
455 FlameActive(void)
456 {
457   int x,v1;
458   unsigned char *ptr1;
459    
460   ptr1 = flame + ((fheight + 1) * (fwidth + 2));
461
462   for (x = 0; x < fwidth + 2; x++)
463     {
464       v1      = *ptr1;
465       v1     += ((random() % variance) - vartrend);
466       *ptr1++ = v1 % 255;
467     }
468
469   if (bloom)
470     {
471       v1= (random() % 100);
472       if (v1 == 10)
473         residual += (random()%10);
474       else if (v1 == 20)
475         hspread += (random()%15);
476       else if (v1 == 30)
477         vspread += (random()%20);
478     }
479
480   residual = ((iresidual* 10) + (residual *90)) / 100;
481   hspread  = ((ihspread * 10) + (hspread  *90)) / 100;
482   vspread  = ((ivspread * 10) + (vspread  *90)) / 100;
483 }
484
485
486 static void
487 FlameAdvance(void)
488 {
489   int x,y;
490   unsigned char *ptr2;
491   int newtop = top;
492
493   for (y = fheight + 1; y >= top; y--)
494     {
495       int used = 0;
496       unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
497       for (x = 0; x < fwidth; x++)
498         {
499           int v1 = (int)*ptr1;
500           int v2, v3;
501           if (v1 > 0)
502             {
503               used = 1;
504               ptr2 = ptr1 - fwidth - 2;
505               v3   = (v1 * 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 * 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 < fheight + 1)
527                 {
528                   v1    = (v1 * 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 * residual) >> 8;
541         *ptr1 = (unsigned char)v1;
542       }
543     }
544
545   top = newtop - 1;
546
547   if (top < 1)
548     top = 1;
549 }
550
551
552 static void
553 FlameFill(int val)
554 {
555   int x, y;
556   for (y = 0; y < fheight + 1; y++)
557     {
558       unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
559       for (x = 0; x < fwidth; x++)
560         {
561           *ptr1 = val;
562           ptr1++;
563         }
564     }
565 }
566
567
568 static void
569 FlamePasteData(unsigned char *d, int xx, int yy, int w, int h)
570 {
571   unsigned char *ptr1,*ptr2;
572   ptr2 = d;
573
574   if (xx < 0) xx = 0;
575   if (yy < 0) yy = 0;
576
577   if ((xx >= 0) &&
578       (yy >= 0) &&
579       (xx + w <= fwidth) &&
580       (yy + h <= fheight))
581     {
582       int x, y;
583       for (y = 0; y < h; y++)
584         {
585           ptr1 = flame + 1 + xx + ((yy + y) * (fwidth + 2));
586           for (x = 0; x < w; x++)
587             {
588               if (*ptr2 / 24)
589                 *ptr1 += random() % (*ptr2 / 24);
590
591               ptr1++;
592               ptr2++;
593             }
594         }
595     }
596   else
597     {
598       static Bool warned = False;
599       if (!warned)
600         {
601           fprintf (stderr, "%s: window is %dx%d; image must be "
602                    "smaller than %dx%d (not %dx%d).\n",
603                    progname, width, height, fwidth, fheight, w, h);
604           warned = True;
605         }
606     }
607 }
608
609
610 static unsigned char *
611 loadBitmap(int *w, int *h)
612 {
613   char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
614
615   if (!bitmap_name ||
616       !*bitmap_name ||
617       !strcmp(bitmap_name, "none"))
618     ;
619   else if (!strcmp(bitmap_name, "(default)"))   /* use the builtin */
620     {
621       XImage *ximage;
622       unsigned char *result, *o;
623       char *bits = (char *) malloc (sizeof(bob_bits));
624       int x, y;
625       int scale = ((width > bob_width * 11) ? 2 : 1);
626  
627       memcpy (bits, bob_bits, sizeof(bob_bits));
628       ximage = XCreateImage (display, visual, 1, XYBitmap, 0, bits,
629                              bob_width, bob_height, 8, 0);
630       ximage->byte_order = LSBFirst;
631       ximage->bitmap_bit_order = LSBFirst;
632       *w = ximage->width * scale;
633       *h = ximage->height * scale;
634       o = result = (unsigned char *) malloc ((*w * scale) * (*h * scale));
635       for (y = 0; y < *h; y++)
636         for (x = 0; x < *w; x++)
637           *o++ = (XGetPixel(ximage, x/scale, y/scale) ? 255 : 0);
638        
639       return result;
640     }
641   else  /* load a bitmap file */
642     {
643 #ifdef HAVE_XPM
644       XpmInfo xpm_info = { 0, };
645       XpmImage xpm_image = { 0, };
646
647       int result = XpmReadFileToXpmImage (bitmap_name, &xpm_image, &xpm_info);
648       if (result == XpmSuccess)
649         {
650           int x, y;
651           unsigned char *result, *o;
652           unsigned char *grays;
653           XWindowAttributes xgwa;
654
655           *w = xpm_image.width;
656           *h = xpm_image.height;
657           result = (unsigned char *) malloc ((*w) * (*h));
658           if (!result)
659             {
660               fprintf(stderr, "%s: out of memory loading %s\n",
661                       progname, bitmap_name);
662               exit (1);
663             }
664
665           XGetWindowAttributes (display, window, &xgwa);
666
667           grays = (unsigned char *) calloc (xpm_image.ncolors+1, 1);
668           for (x = 0; x < xpm_image.ncolors; x++)
669             {
670               XColor xc;
671               XpmColor *xpmc = &xpm_image.colorTable[x];
672               char *cstring = 0;
673               if (xpmc->g_color && *xpmc->g_color)
674                 cstring = xpmc->g_color;
675               else if (xpmc->g4_color && *xpmc->g4_color)
676                 cstring = xpmc->g4_color;
677               else if (xpmc->c_color && *xpmc->c_color)
678                 cstring = xpmc->c_color;
679               else
680                 cstring = xpmc->m_color;
681
682               memset (&xc, 0, sizeof(xc));
683               if (!cstring ||
684                   !*cstring ||
685                   !XParseColor (display, xgwa.colormap, cstring, &xc))
686                 grays[x] = 0;
687               else
688                 grays[x] = (int) (((xc.red   * 0.299) +
689                                    (xc.green * 0.587) +
690                                    (xc.blue  * 0.114))
691                                   / 255);
692             }
693
694           o = result;
695           for (y = 0; y < *h; y++)
696             for (x = 0; x < *w; x++)
697               {
698                 int color = xpm_image.data[(y * (*w)) + x];
699                 if (color < 0 || color > xpm_image.ncolors) abort();
700                 *o++ = grays[color];
701               }
702           return result;
703         }
704       else      /* failed to read XPM -- fall through and try XBM */
705 #endif /* HAVE_XPM */
706         {
707 #ifdef HAVE_XMU
708           XImage *ximage = 0;
709           int width, height, xh, yh;
710           int x, y;
711           unsigned char *result, *o;
712           Pixmap bitmap =
713             XmuLocateBitmapFile (DefaultScreenOfDisplay (display),
714                                  bitmap_name, 0, 0, &width, &height, &xh, &yh);
715           if (!bitmap)
716             {
717               fprintf(stderr, "%s: unable to load bitmap file %s\n",
718                       progname, bitmap_name);
719               exit (1);
720             }
721           ximage = XGetImage (display, bitmap, 0, 0, width, height,
722                               1L, XYPixmap);
723           XFreePixmap (display, bitmap);
724
725           if (ximage->depth != 1) abort();
726
727           *w = ximage->width;
728           *h = ximage->height;
729           result = (unsigned char *) malloc ((*w) * (*h));
730           if (!result)
731             {
732               fprintf(stderr, "%s: out of memory loading %s\n",
733                       progname, bitmap_name);
734               exit (1);
735             }
736
737           o = result;
738           for (y = 0; y < *h; y++)
739             for (x = 0; x < *w; x++)
740               *o++ = (XGetPixel(ximage, x, y) ? 255 : 0);
741
742           return result;
743
744 #else  /* !XMU */
745           fprintf (stderr,
746                    "%s: your vendor doesn't ship the standard Xmu library.\n",
747                    progname);
748           fprintf (stderr, "\tWe can't load XBM files without it.\n");
749           exit (1);
750 #endif /* !XMU */
751         }
752     }
753
754   *w = 0;
755   *h = 0;
756   return 0;
757
758 }
759
760
761 \f
762 char *progclass = "XFlame";
763
764 char *defaults [] = {
765   ".background:     black",
766   ".foreground:     #FFAF5F",
767   "*bitmap:         (default)",
768   "*bitmapBaseline: 20",
769   "*delay:          10000",
770   "*hspread:        30",
771   "*vspread:        97",
772   "*residual:       99",
773   "*variance:       50",
774   "*vartrend:       20",
775   "*bloom:          True",   
776
777 #ifdef HAVE_XSHM_EXTENSION
778   "*useSHM: False",   /* xshm turns out not to help. */
779 #endif /* HAVE_XSHM_EXTENSION */
780    0
781 };
782
783 XrmOptionDescRec options [] = {
784   { "-delay",     ".delay",          XrmoptionSepArg, 0 },
785   { "-bitmap",    ".bitmap",         XrmoptionSepArg, 0 },
786   { "-baseline",  ".bitmapBaseline", XrmoptionSepArg, 0 },
787   { "-hspread",   ".hspread",        XrmoptionSepArg, 0 },
788   { "-vspread",   ".vspread",        XrmoptionSepArg, 0 },
789   { "-residual",  ".residual",       XrmoptionSepArg, 0 },
790   { "-variance",  ".variance",       XrmoptionSepArg, 0 },
791   { "-vartrend",  ".vartrend",       XrmoptionSepArg, 0 },
792   { "-bloom",     ".bloom",          XrmoptionNoArg, "True" },
793   { "-no-bloom",  ".bloom",          XrmoptionNoArg, "False" },
794 #ifdef HAVE_XSHM_EXTENSION
795   { "-shm",       ".useSHM",         XrmoptionNoArg, "True" },
796   { "-no-shm",    ".useSHM",         XrmoptionNoArg, "False" },
797 #endif /* HAVE_XSHM_EXTENSION */
798   { 0, 0, 0, 0 }
799 };
800
801 void
802 screenhack (Display *disp, Window win)
803 {
804   int theimx = 0, theimy = 0;
805   int baseline = get_integer_resource ("bitmapBaseline", "Integer");
806   int delay = get_integer_resource ("delay", "Integer");
807   xim      = NULL;
808   top      = 1;
809   flame    = NULL;
810
811   GetXInfo(disp,win);
812   InitColors();
813   theim = loadBitmap(&theimx, &theimy);
814
815   /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
816      makes it hard for us to react to window resizing.  So, punt for now.  The
817      size of the window at startup is the size it will stay.
818   */
819   GetXInfo(disp,win);
820
821   MakeImage();
822   InitFlame();
823   FlameFill(0);
824
825   while (1)
826     {
827       FlameActive();
828
829       if (theim)
830         FlamePasteData(theim, (fwidth - theimx) / 2,
831                        fheight - theimy - baseline, theimx, theimy);
832
833       FlameAdvance();
834       Flame2Image();
835       DisplayImage();
836
837       XSync(display,False);
838       screenhack_handle_events(display);
839       if (delay)
840         usleep (delay);
841     }
842 }