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