http://www.jwz.org/xscreensaver/xscreensaver-5.13.tar.gz
[xscreensaver] / hacks / xflame.c
1 /* xflame, Copyright (c) 1996-2002 Carsten Haitzler <raster@redhat.com>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 /* Version history as near as I (jwz) can piece together:
13
14    * Carsten Haitzler <raster@redhat.com> wrote the first version in 1996.
15
16    * Rahul Jain <rahul@rice.edu> added support for TrueColor displays.
17
18    * Someone did a rough port of it to use the xscreensaver utility routines
19      instead of creating its own window by hand.
20
21    * Someone (probably Raster) came up with a subsequent version that had
22      a Red Hat logo hardcoded into it.
23
24    * Daniel Zahn <stumpy@religions.com> found that version in 1998, and 
25      hacked it to be able to load a different logo from a PGM (P5) file, 
26      with a single hardcoded pathname.
27
28    * Jamie Zawinski <jwz@jwz.org> found several versions of xflame in
29      March 1999, and pieced them together.  Changes:
30
31        - Correct and fault-tolerant use of the Shared Memory extension;
32          previous versions of xflame did not work when $DISPLAY was remote.
33
34        - Replaced PGM-reading code with code that can read arbitrary XBM
35          and XPM files (color ones will be converted to grayscale.)
36
37        - Command-line options all around -- no hardcoded pathnames or
38          behavioral constants.
39
40        - General cleanup and portability tweaks.
41
42    * 4-Oct-99, jwz: added support for packed-24bpp (versus 32bpp.)
43    * 16-Jan-2002, jwz: added gdk_pixbuf support.
44
45  */
46
47 /* portions by Daniel Zahn <stumpy@religions.com> */
48
49
50 #include "screenhack.h"
51 #include "xpm-pixmap.h"
52 #include <limits.h>
53
54 #undef countof
55 #define countof(x) (sizeof((x))/sizeof((*x)))
56
57 #ifdef HAVE_XSHM_EXTENSION
58 # include "xshm.h"
59 #endif /* HAVE_XSHM_EXTENSION */
60
61 #include "images/bob.xbm"
62
63 #define MAX_VAL             255
64
65 struct state {
66   Display *dpy;
67   Window window;
68   int             depth;
69   int             width;
70   int             height;
71   Colormap        colormap;
72   Visual          *visual;
73   Screen          *screen;
74   Bool            shared;
75   Bool            bloom;
76   XImage          *xim;
77 #ifdef HAVE_XSHM_EXTENSION
78   XShmSegmentInfo shminfo;
79 #endif /* HAVE_XSHM_EXTENSION */
80   GC              gc;
81   int             ctab[256];
82
83   unsigned char  *flame;
84   unsigned char  *theim;
85   int             fwidth;
86   int             fheight;
87   int             top;
88   int             hspread;
89   int             vspread;
90   int             residual;
91
92   int ihspread;
93   int ivspread;
94   int iresidual;
95   int variance;
96   int vartrend;
97
98   int delay;
99   int baseline;
100   int theimx, theimy;
101 };
102
103 static void
104 GetXInfo(struct state *st)
105 {
106   XWindowAttributes xwa;
107    
108   XGetWindowAttributes(st->dpy,st->window,&xwa);
109
110   st->colormap = xwa.colormap;
111   st->depth    = xwa.depth;
112   st->visual   = xwa.visual;
113   st->screen   = xwa.screen;
114   st->width    = xwa.width;
115   st->height   = xwa.height;
116
117   if (st->width%2)
118     st->width++;
119   if (st->height%2)
120     st->height++;
121 }
122
123 static void
124 MakeImage(struct state *st)
125 {
126   XGCValues gcv;
127
128 #ifdef HAVE_XSHM_EXTENSION
129   st->shared = True;
130   st->xim = create_xshm_image (st->dpy, st->visual, st->depth, ZPixmap, NULL,
131                            &st->shminfo, st->width, st->height);
132 #else  /* !HAVE_XSHM_EXTENSION */
133   st->xim = 0;
134 #endif /* !HAVE_XSHM_EXTENSION */
135
136   if (!st->xim)
137     {
138       st->shared = False;
139       st->xim = XCreateImage (st->dpy, st->visual, st->depth, ZPixmap, 0, NULL,
140                           st->width, st->height, 32, 0);
141       if (st->xim)
142         st->xim->data = (char *) calloc(st->xim->height, st->xim->bytes_per_line);
143       if (!st->xim || !st->xim->data)
144         {
145           fprintf(stderr,"%s: out of memory.\n", progname);
146           exit(1);
147         }
148     }
149
150   st->gc = XCreateGC(st->dpy,st->window,0,&gcv);
151   if (!st->gc) exit (1);
152 }
153
154
155 static void
156 InitColors(struct state *st)
157 {
158   int i = 0, j = 0, red = 0, green = 0, blue = 0;
159   XColor fg;
160
161   /* Make it possible to set the color of the flames, 
162      by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
163   */
164   fg.pixel = get_pixel_resource (st->dpy, st->colormap,
165                                  "foreground", "Foreground");
166   XQueryColor (st->dpy, st->colormap, &fg);
167
168   red   = 255 - (fg.red   >> 8);
169   green = 255 - (fg.green >> 8);
170   blue  = 255 - (fg.blue  >> 8);
171
172
173   for (i = 0; i < 256 * 2; i += 2)
174     {
175       XColor xcl;
176       int r = (i - red)   * 3;
177       int g = (i - green) * 3;
178       int b = (i - blue)  * 3;
179     
180       if (r < 0)   r = 0;
181       if (r > 255) r = 255;
182       if (g < 0)   g = 0;
183       if (g > 255) g = 255;
184       if (b < 0)   b = 0;
185       if (b > 255) b = 255;
186
187       xcl.red   = (unsigned short)((r << 8) | r);
188       xcl.green = (unsigned short)((g << 8) | g);
189       xcl.blue  = (unsigned short)((b << 8) | b);
190       xcl.flags = DoRed | DoGreen | DoBlue;
191
192       XAllocColor(st->dpy,st->colormap,&xcl);
193
194       st->ctab[j++] = (int)xcl.pixel;
195     }
196 }
197
198
199 static void
200 DisplayImage(struct state *st)
201 {
202 #ifdef HAVE_XSHM_EXTENSION
203   if (st->shared)
204     XShmPutImage(st->dpy, st->window, st->gc, st->xim, 0,(st->top - 1) << 1, 0,
205                  (st->top - 1) << 1, st->width, st->height - ((st->top - 1) << 1), False);
206   else
207 #endif /* HAVE_XSHM_EXTENSION */
208     XPutImage(st->dpy, st->window, st->gc, st->xim, 0, (st->top - 1) << 1, 0,
209               (st->top - 1) << 1, st->width, st->height - ((st->top - 1) << 1));
210 }
211
212
213 static void
214 InitFlame(struct state *st)
215 {
216   st->fwidth  = st->width / 2;
217   st->fheight = st->height / 2;
218   st->flame   = (unsigned char *) malloc((st->fwidth + 2) * (st->fheight + 2)
219                                      * sizeof(unsigned char));
220
221   if (!st->flame)
222     {
223       fprintf(stderr,"%s: out of memory\n", progname);
224       exit(1);
225     }
226
227   st->top      = 1;
228   st->ihspread  = get_integer_resource(st->dpy, "hspread", "Integer");
229   st->ivspread  = get_integer_resource(st->dpy, "vspread", "Integer");
230   st->iresidual = get_integer_resource(st->dpy, "residual", "Integer");
231   st->variance  = get_integer_resource(st->dpy, "variance", "Integer");
232   st->vartrend  = get_integer_resource(st->dpy, "vartrend", "Integer");
233   st->bloom     = get_boolean_resource(st->dpy, "bloom",    "Boolean");
234
235 # define THROTTLE(VAR,NAME) \
236   if (VAR < 0 || VAR > 255) { \
237     fprintf(stderr, "%s: %s must be in the range 0-255 (not %d).\n", \
238             progname, NAME, VAR); \
239     exit(1); }
240   THROTTLE (st->ihspread, "hspread");
241   THROTTLE (st->ivspread, "vspread");
242   THROTTLE (st->iresidual,"residual");
243   THROTTLE (st->variance, "variance");
244   THROTTLE (st->vartrend, "vartrend");
245 # undef THROTTLE
246
247
248
249   st->hspread = st->ihspread;
250   st->vspread = st->ivspread;
251   st->residual = st->iresidual;
252 }
253
254
255 static void
256 Flame2Image16(struct state *st)
257 {
258   int x,y;
259   unsigned short *ptr;
260   unsigned char *ptr1;
261   int v1,v2,v3,v4;
262
263   ptr  = (unsigned short *)st->xim->data;
264   ptr += (st->top << 1) * st->width;
265   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
266
267   for(y = st->top; y < st->fheight; y++)
268     {
269       for( x = 0; x < st->fwidth; x++)
270         {
271           v1 = (int)*ptr1;
272           v2 = (int)*(ptr1 + 1);
273           v3 = (int)*(ptr1 + st->fwidth + 2);
274           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
275           ptr1++;
276           *ptr++ = (unsigned short)st->ctab[v1];
277           *ptr   = (unsigned short)st->ctab[(v1 + v2) >> 1];
278           ptr   += st->width - 1;
279           *ptr++ = (unsigned short)st->ctab[(v1 + v3) >> 1];
280           *ptr   = (unsigned short)st->ctab[(v1 + v4) >> 1];
281           ptr   -= st->width - 1;
282         }
283       ptr  += st->width;
284       ptr1 += 2;
285     }
286 }
287
288 static void
289 Flame2Image32(struct state *st)
290 {
291   int x,y;
292   unsigned int *ptr;
293   unsigned char *ptr1;
294   int v1,v2,v3,v4;
295
296   ptr  = (unsigned int *)st->xim->data;
297   ptr += (st->top << 1) * st->width;
298   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
299
300   for( y = st->top; y < st->fheight; y++)
301     {
302       for( x = 0; x < st->fwidth; x++)
303         {
304           v1 = (int)*ptr1;
305           v2 = (int)*(ptr1 + 1);
306           v3 = (int)*(ptr1 + st->fwidth + 2);
307           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
308           ptr1++;
309           *ptr++ = (unsigned int)st->ctab[v1];
310           *ptr   = (unsigned int)st->ctab[(v1 + v2) >> 1];
311           ptr   += st->width - 1;
312           *ptr++ = (unsigned int)st->ctab[(v1 + v3) >> 1];
313           *ptr   = (unsigned int)st->ctab[(v1 + v4) >> 1];
314           ptr   -= st->width - 1;
315         }
316       ptr  += st->width;
317       ptr1 += 2;
318     }
319 }
320
321 static void
322 Flame2Image24(struct state *st)
323 {
324   int x,y;
325   unsigned char *ptr;
326   unsigned char *ptr1;
327   int v1,v2,v3,v4;
328
329   ptr  = (unsigned char *)st->xim->data;
330   ptr += (st->top << 1) * st->xim->bytes_per_line;
331   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
332
333   for( y = st->top; y < st->fheight; y++)
334     {
335       unsigned char *last_ptr = ptr;
336       for( x = 0; x < st->fwidth; x++)
337         {
338           v1 = (int)*ptr1;
339           v2 = (int)*(ptr1 + 1);
340           v3 = (int)*(ptr1 + st->fwidth + 2);
341           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
342           ptr1++;
343
344           ptr[2] = ((unsigned int)st->ctab[v1] & 0x00FF0000) >> 16;
345           ptr[1] = ((unsigned int)st->ctab[v1] & 0x0000FF00) >> 8;
346           ptr[0] = ((unsigned int)st->ctab[v1] & 0x000000FF);
347           ptr += 3;
348
349           ptr[2] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x00FF0000) >> 16;
350           ptr[1] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x0000FF00) >> 8;
351           ptr[0] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x000000FF);
352           ptr += ((st->width - 1) * 3);
353
354           ptr[2] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x00FF0000) >> 16;
355           ptr[1] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x0000FF00) >> 8;
356           ptr[0] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x000000FF);
357           ptr += 3;
358
359           ptr[2] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x00FF0000) >> 16;
360           ptr[1] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x0000FF00) >> 8;
361           ptr[0] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x000000FF);
362           ptr -= ((st->width - 1) * 3);
363         }
364
365       ptr = last_ptr + (st->xim->bytes_per_line << 1);
366       ptr1 += 2;
367     }
368 }
369
370 static void
371 Flame2Image8(struct state *st)
372 {
373   int x,y;
374   unsigned char *ptr;
375   unsigned char *ptr1;
376   int v1,v2,v3,v4;
377
378   ptr  = (unsigned char *)st->xim->data;
379   ptr += (st->top << 1) * st->width;
380   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
381
382   for(y=st->top;y<st->fheight;y++)
383     {
384       for(x=0;x<st->fwidth;x++)
385         {
386           v1 = (int)*ptr1;
387           v2 = (int)*(ptr1 + 1);
388           v3 = (int)*(ptr1 + st->fwidth + 2);
389           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
390           ptr1++;
391           *ptr++ = (unsigned char)st->ctab[v1];
392           *ptr   = (unsigned char)st->ctab[(v1 + v2) >> 1];
393           ptr   += st->width - 1;
394           *ptr++ = (unsigned char)st->ctab[(v1 + v3) >> 1];
395           *ptr   = (unsigned char)st->ctab[(v1 + v4) >> 1];
396           ptr   -= st->width - 1;
397         }
398       ptr  += st->width;
399       ptr1 += 2;
400     }
401 }
402
403 static void
404 Flame2Image1234567(struct state *st)
405 {
406   int x,y;
407   unsigned char *ptr1;
408   int v1,v2,v3,v4;
409
410   ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
411
412   for( y = st->top; y < st->fheight; y++)
413     {
414       for( x = 0; x < st->fwidth; x++)
415         {
416           v1 = (int)*ptr1;
417           v2 = (int)*(ptr1 + 1);
418           v3 = (int)*(ptr1 + st->fwidth + 2);
419           v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
420           ptr1++;
421           XPutPixel(st->xim,(x << 1),    (y << 1),    st->ctab[v1]);
422           XPutPixel(st->xim,(x << 1) + 1,(y << 1),    st->ctab[(v1 + v2) >> 1]);
423           XPutPixel(st->xim,(x << 1),    (y << 1) + 1,st->ctab[(v1 + v3) >> 1]);
424           XPutPixel(st->xim,(x << 1) + 1,(y << 1) + 1,st->ctab[(v1 + v4) >> 1]);
425         }
426     }
427 }
428
429 static void
430 Flame2Image(struct state *st)
431 {
432   switch (st->xim->bits_per_pixel)
433     {
434     case 32: Flame2Image32(st); break;
435     case 24: Flame2Image24(st); break;
436     case 16: Flame2Image16(st); break;
437     case 8:  Flame2Image8(st);  break;
438     default:
439       if (st->xim->bits_per_pixel <= 7)
440         Flame2Image1234567(st);
441       else
442         abort();
443       break;
444     }
445 }
446
447
448 static void
449 FlameActive(struct state *st)
450 {
451   int x,v1;
452   unsigned char *ptr1;
453    
454   ptr1 = st->flame + ((st->fheight + 1) * (st->fwidth + 2));
455
456   for (x = 0; x < st->fwidth + 2; x++)
457     {
458       v1      = *ptr1;
459       v1     += ((random() % st->variance) - st->vartrend);
460       *ptr1++ = v1 % 255;
461     }
462
463   if (st->bloom)
464     {
465       v1= (random() % 100);
466       if (v1 == 10)
467         st->residual += (random()%10);
468       else if (v1 == 20)
469         st->hspread += (random()%15);
470       else if (v1 == 30)
471         st->vspread += (random()%20);
472     }
473
474   st->residual = ((st->iresidual* 10) + (st->residual *90)) / 100;
475   st->hspread  = ((st->ihspread * 10) + (st->hspread  *90)) / 100;
476   st->vspread  = ((st->ivspread * 10) + (st->vspread  *90)) / 100;
477 }
478
479
480 static void
481 FlameAdvance(struct state *st)
482 {
483   int x,y;
484   unsigned char *ptr2;
485   int newtop = st->top;
486
487   for (y = st->fheight + 1; y >= st->top; y--)
488     {
489       int used = 0;
490       unsigned char *ptr1 = st->flame + 1 + (y * (st->fwidth + 2));
491       for (x = 0; x < st->fwidth; x++)
492         {
493           int v1 = (int)*ptr1;
494           int v2, v3;
495           if (v1 > 0)
496             {
497               used = 1;
498               ptr2 = ptr1 - st->fwidth - 2;
499               v3   = (v1 * st->vspread) >> 8;
500               v2   = (int)*(ptr2);
501               v2  += v3;
502               if (v2 > MAX_VAL) 
503                 v2 = MAX_VAL;
504
505               *(ptr2) = (unsigned char)v2;
506               v3  = (v1 * st->hspread) >> 8;
507               v2  = (int)*(ptr2 + 1);
508               v2 += v3;
509               if (v2 > MAX_VAL) 
510                 v2 = MAX_VAL;
511           
512               *(ptr2 + 1) = (unsigned char)v2;
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         
520               if (y < st->fheight + 1)
521                 {
522                   v1    = (v1 * st->residual) >> 8;
523                   *ptr1 = (unsigned char)v1;
524                 }
525             }
526           ptr1++;
527           if (used) 
528             newtop = y - 1;
529         }
530  
531       /* clean up the right gutter */
532       {
533         int v1 = (int)*ptr1;
534         v1 = (v1 * st->residual) >> 8;
535         *ptr1 = (unsigned char)v1;
536       }
537     }
538
539   st->top = newtop - 1;
540
541   if (st->top < 1)
542     st->top = 1;
543 }
544
545
546 static void
547 FlameFill(struct state *st, int val)
548 {
549   int x, y;
550   for (y = 0; y < st->fheight + 1; y++)
551     {
552       unsigned char *ptr1 = st->flame + 1 + (y * (st->fwidth + 2));
553       for (x = 0; x < st->fwidth; x++)
554         {
555           *ptr1 = val;
556           ptr1++;
557         }
558     }
559 }
560
561
562 static void
563 FlamePasteData(struct state *st,
564                unsigned char *d, int xx, int yy, int w, int h)
565 {
566   unsigned char *ptr1,*ptr2;
567   ptr2 = d;
568
569   if (xx < 0) xx = 0;
570   if (yy < 0) yy = 0;
571
572   if ((xx >= 0) &&
573       (yy >= 0) &&
574       (xx + w <= st->fwidth) &&
575       (yy + h <= st->fheight))
576     {
577       int x, y;
578       for (y = 0; y < h; y++)
579         {
580           ptr1 = st->flame + 1 + xx + ((yy + y) * (st->fwidth + 2));
581           for (x = 0; x < w; x++)
582             {
583               if (*ptr2 / 24)
584                 *ptr1 += random() % (*ptr2 / 24);
585
586               ptr1++;
587               ptr2++;
588             }
589         }
590     }
591   else
592     {
593       static Bool warned = False;
594       if (!warned)
595         {
596           fprintf (stderr, "%s: st->window is %dx%d; image must be "
597                    "smaller than %dx%d (not %dx%d).\n",
598                    progname, st->width, st->height, st->fwidth, st->fheight, w, h);
599           warned = True;
600         }
601     }
602 }
603
604
605 static unsigned char *
606 loadBitmap(struct state *st, int *w, int *h)
607 {
608   char *bitmap_name = get_string_resource (st->dpy, "bitmap", "Bitmap");
609
610 #ifdef HAVE_COCOA
611   bitmap_name = "(default)"; /* #### always use builtin */
612 #endif /* HAVE_COCOA */
613   
614   if (!bitmap_name ||
615       !*bitmap_name ||
616       !strcmp(bitmap_name, "none"))
617     ;
618   else if (!strcmp(bitmap_name, "(default)"))   /* use the builtin */
619     {
620       XImage *ximage;
621       unsigned char *result, *o;
622       char *bits = (char *) malloc (sizeof(bob_bits));
623       int x, y;
624       int scale = ((st->width > bob_width * 11) ? 2 : 1);
625  
626       memcpy (bits, bob_bits, sizeof(bob_bits));
627       ximage = XCreateImage (st->dpy, st->visual, 1, XYBitmap, 0, bits,
628                              bob_width, bob_height, 8, 0);
629       ximage->byte_order = LSBFirst;
630       ximage->bitmap_bit_order = LSBFirst;
631       *w = ximage->width * scale;
632       *h = ximage->height * scale;
633       o = result = (unsigned char *) malloc ((*w * scale) * (*h * scale));
634       for (y = 0; y < *h; y++)
635         for (x = 0; x < *w; x++)
636           *o++ = (XGetPixel(ximage, x/scale, y/scale) ? 255 : 0);
637        
638       return result;
639     }
640   else  /* load a bitmap file */
641 #ifdef HAVE_COCOA
642     abort(); /* #### fix me */
643 #else
644    {
645       Pixmap pixmap =
646         xpm_file_to_pixmap (st->dpy, st->window, bitmap_name, &st->width, &st->height, 0);
647       XImage *image;
648       int x, y;
649       unsigned char *result, *o;
650       XColor colors[256];
651       Bool cmap_p = has_writable_cells (st->screen, st->visual);
652
653       if (cmap_p)
654         {
655           int i;
656           for (i = 0; i < countof (colors); i++)
657             colors[i].pixel = i;
658           XQueryColors (st->dpy, st->colormap, colors, countof (colors));
659         }
660
661       image = XGetImage (st->dpy, pixmap, 0, 0, st->width, st->height, ~0L, ZPixmap);
662       XFreePixmap(st->dpy, pixmap);
663
664       result = (unsigned char *) malloc (st->width * st->height);
665       o = result;
666       for (y = 0; y < st->height; y++)
667         for (x = 0; x < st->width; x++)
668           {
669             int rgba = XGetPixel (image, x, y);
670             int gray;
671             if (cmap_p)
672               gray = ((200 - ((((colors[rgba].red   >> 8) & 0xFF) +
673                               ((colors[rgba].green >> 8) & 0xFF) +
674                               ((colors[rgba].blue  >> 8) & 0xFF))
675                              >> 1))
676                       & 0xFF);
677             else
678               /* This is *so* not handling all the cases... */
679               gray = (image->depth > 16
680                       ? ((((rgba >> 24) & 0xFF) +
681                           ((rgba >> 16) & 0xFF) +
682                           ((rgba >>  8) & 0xFF) +
683                           ((rgba      ) & 0xFF)) >> 2)
684                       : ((((rgba >> 12) & 0x0F) +
685                           ((rgba >>  8) & 0x0F) +
686                           ((rgba >>  4) & 0x0F) +
687                           ((rgba      ) & 0x0F)) >> 1));
688
689             *o++ = 255 - gray;
690           }
691
692       XFree (image->data);
693       image->data = 0;
694       XDestroyImage (image);
695
696       *w = st->width;
697       *h = st->height;
698       return result;
699     }
700 #endif /* !HAVE_COCOA */
701
702   *w = 0;
703   *h = 0;
704   return 0;
705
706 }
707
708 static void *
709 xflame_init (Display *dpy, Window win)
710 {
711   struct state *st = (struct state *) calloc (1, sizeof(*st));
712   st->dpy = dpy;
713   st->window = win;
714   st->baseline = get_integer_resource (dpy, "bitmapBaseline", "Integer");
715   st->delay = get_integer_resource (dpy, "delay", "Integer");
716   st->xim      = NULL;
717   st->top      = 1;
718   st->flame    = NULL;
719
720   GetXInfo(st);
721   InitColors(st);
722   st->theim = loadBitmap(st, &st->theimx, &st->theimy);
723
724   /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
725      makes it hard for us to react to window resizing.  So, punt for now.  The
726      size of the window at startup is the size it will stay.
727   */
728   GetXInfo(st);
729
730   MakeImage(st);
731   InitFlame(st);
732   FlameFill(st,0);
733
734   return st;
735 }
736
737 static unsigned long
738 xflame_draw (Display *dpy, Window win, void *closure)
739 {
740   struct state *st = (struct state *) closure;
741   FlameActive(st);
742
743   if (st->theim)
744     FlamePasteData(st, st->theim, (st->fwidth - st->theimx) / 2,
745                    st->fheight - st->theimy - st->baseline, st->theimx, st->theimy);
746
747   FlameAdvance(st);
748   Flame2Image(st);
749   DisplayImage(st);
750
751   return st->delay;
752 }
753
754 static void
755 xflame_reshape (Display *dpy, Window window, void *closure, 
756                  unsigned int w, unsigned int h)
757 {
758 }
759
760 static Bool
761 xflame_event (Display *dpy, Window window, void *closure, XEvent *event)
762 {
763   return False;
764 }
765
766 static void
767 xflame_free (Display *dpy, Window window, void *closure)
768 {
769 }
770
771
772 \f
773
774 static const char *xflame_defaults [] = {
775   ".background:     black",
776   ".foreground:     #FFAF5F",
777   "*fpsTop:         true",
778   "*fpsSolid:       true",
779   "*bitmap:         (default)",
780   "*bitmapBaseline: 20",
781   "*delay:          10000",
782   "*hspread:        30",
783   "*vspread:        97",
784   "*residual:       99",
785   "*variance:       50",
786   "*vartrend:       20",
787   "*bloom:          True",   
788
789 #ifdef HAVE_XSHM_EXTENSION
790   "*useSHM: False",   /* xshm turns out not to help. */
791 #endif /* HAVE_XSHM_EXTENSION */
792    0
793 };
794
795 static XrmOptionDescRec xflame_options [] = {
796   { "-foreground",".foreground",     XrmoptionSepArg, 0 },
797   { "-fg",        ".foreground",     XrmoptionSepArg, 0 },
798   { "-delay",     ".delay",          XrmoptionSepArg, 0 },
799   { "-bitmap",    ".bitmap",         XrmoptionSepArg, 0 },
800   { "-baseline",  ".bitmapBaseline", XrmoptionSepArg, 0 },
801   { "-hspread",   ".hspread",        XrmoptionSepArg, 0 },
802   { "-vspread",   ".vspread",        XrmoptionSepArg, 0 },
803   { "-residual",  ".residual",       XrmoptionSepArg, 0 },
804   { "-variance",  ".variance",       XrmoptionSepArg, 0 },
805   { "-vartrend",  ".vartrend",       XrmoptionSepArg, 0 },
806   { "-bloom",     ".bloom",          XrmoptionNoArg, "True" },
807   { "-no-bloom",  ".bloom",          XrmoptionNoArg, "False" },
808 #ifdef HAVE_XSHM_EXTENSION
809   { "-shm",       ".useSHM",         XrmoptionNoArg, "True" },
810   { "-no-shm",    ".useSHM",         XrmoptionNoArg, "False" },
811 #endif /* HAVE_XSHM_EXTENSION */
812   { 0, 0, 0, 0 }
813 };
814
815
816 XSCREENSAVER_MODULE ("XFlame", xflame)