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