1 /* xflame, Copyright (c) 1996-2002 Carsten Haitzler <raster@redhat.com>
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
12 /* Version history as near as I (jwz) can piece together:
14 * Carsten Haitzler <raster@redhat.com> wrote the first version in 1996.
16 * Rahul Jain <rahul@rice.edu> added support for TrueColor displays.
18 * Someone did a rough port of it to use the xscreensaver utility routines
19 instead of creating its own window by hand.
21 * Someone (probably Raster) came up with a subsequent version that had
22 a Red Hat logo hardcoded into it.
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.
28 * Jamie Zawinski <jwz@jwz.org> found several versions of xflame in
29 March 1999, and pieced them together. Changes:
31 - Correct and fault-tolerant use of the Shared Memory extension;
32 previous versions of xflame did not work when $DISPLAY was remote.
34 - Replaced PGM-reading code with code that can read arbitrary XBM
35 and XPM files (color ones will be converted to grayscale.)
37 - Command-line options all around -- no hardcoded pathnames or
40 - General cleanup and portability tweaks.
42 * 4-Oct-99, jwz: added support for packed-24bpp (versus 32bpp.)
43 * 16-Jan-2002, jwz: added gdk_pixbuf support.
47 /* portions by Daniel Zahn <stumpy@religions.com> */
50 #include "screenhack.h"
51 #include "xpm-pixmap.h"
55 #define countof(x) (sizeof((x))/sizeof((*x)))
57 #ifdef HAVE_XSHM_EXTENSION
59 #endif /* HAVE_XSHM_EXTENSION */
61 #include "images/bob.xbm"
77 #ifdef HAVE_XSHM_EXTENSION
78 XShmSegmentInfo shminfo;
79 #endif /* HAVE_XSHM_EXTENSION */
104 GetXInfo(struct state *st)
106 XWindowAttributes xwa;
108 XGetWindowAttributes(st->dpy,st->window,&xwa);
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;
124 MakeImage(struct state *st)
128 /* #### This probably leaks SHM every time the window is resized. */
130 XDestroyImage (st->xim);
132 #ifdef HAVE_XSHM_EXTENSION
134 st->xim = create_xshm_image (st->dpy, st->visual, st->depth, ZPixmap, NULL,
135 &st->shminfo, st->width, st->height);
136 #else /* !HAVE_XSHM_EXTENSION */
138 #endif /* !HAVE_XSHM_EXTENSION */
143 st->xim = XCreateImage (st->dpy, st->visual, st->depth, ZPixmap, 0, NULL,
144 st->width, st->height, 32, 0);
146 st->xim->data = (char *) calloc(st->xim->height, st->xim->bytes_per_line);
147 if (!st->xim || !st->xim->data)
149 fprintf(stderr,"%s: out of memory.\n", progname);
155 st->gc = XCreateGC(st->dpy,st->window,0,&gcv);
160 InitColors(struct state *st)
162 int i = 0, j = 0, red = 0, green = 0, blue = 0;
165 /* Make it possible to set the color of the flames,
166 by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
168 fg.pixel = get_pixel_resource (st->dpy, st->colormap,
169 "foreground", "Foreground");
170 XQueryColor (st->dpy, st->colormap, &fg);
172 red = 255 - (fg.red >> 8);
173 green = 255 - (fg.green >> 8);
174 blue = 255 - (fg.blue >> 8);
177 for (i = 0; i < 256 * 2; i += 2)
180 int r = (i - red) * 3;
181 int g = (i - green) * 3;
182 int b = (i - blue) * 3;
185 if (r > 255) r = 255;
187 if (g > 255) g = 255;
189 if (b > 255) b = 255;
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;
196 XAllocColor(st->dpy,st->colormap,&xcl);
198 st->ctab[j++] = (int)xcl.pixel;
204 DisplayImage(struct state *st)
206 #ifdef HAVE_XSHM_EXTENSION
208 XShmPutImage(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), False);
211 #endif /* HAVE_XSHM_EXTENSION */
212 XPutImage(st->dpy, st->window, st->gc, st->xim, 0, (st->top - 1) << 1, 0,
213 (st->top - 1) << 1, st->width, st->height - ((st->top - 1) << 1));
218 InitFlame(struct state *st)
220 st->fwidth = st->width / 2;
221 st->fheight = st->height / 2;
223 if (st->flame) free (st->flame);
224 st->flame = (unsigned char *) malloc((st->fwidth + 2) * (st->fheight + 2)
225 * sizeof(unsigned char));
229 fprintf(stderr,"%s: out of memory\n", progname);
234 st->ihspread = get_integer_resource(st->dpy, "hspread", "Integer");
235 st->ivspread = get_integer_resource(st->dpy, "vspread", "Integer");
236 st->iresidual = get_integer_resource(st->dpy, "residual", "Integer");
237 st->variance = get_integer_resource(st->dpy, "variance", "Integer");
238 st->vartrend = get_integer_resource(st->dpy, "vartrend", "Integer");
239 st->bloom = get_boolean_resource(st->dpy, "bloom", "Boolean");
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); \
246 THROTTLE (st->ihspread, "hspread");
247 THROTTLE (st->ivspread, "vspread");
248 THROTTLE (st->iresidual,"residual");
249 THROTTLE (st->variance, "variance");
250 THROTTLE (st->vartrend, "vartrend");
255 st->hspread = st->ihspread;
256 st->vspread = st->ivspread;
257 st->residual = st->iresidual;
262 Flame2Image16(struct state *st)
269 ptr = (unsigned short *)st->xim->data;
270 ptr += (st->top << 1) * st->width;
271 ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
273 for(y = st->top; y < st->fheight; y++)
275 for( x = 0; x < st->fwidth; x++)
278 v2 = (int)*(ptr1 + 1);
279 v3 = (int)*(ptr1 + st->fwidth + 2);
280 v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
282 *ptr++ = (unsigned short)st->ctab[v1];
283 *ptr = (unsigned short)st->ctab[(v1 + v2) >> 1];
284 ptr += st->width - 1;
285 *ptr++ = (unsigned short)st->ctab[(v1 + v3) >> 1];
286 *ptr = (unsigned short)st->ctab[(v1 + v4) >> 1];
287 ptr -= st->width - 1;
295 Flame2Image32(struct state *st)
302 ptr = (unsigned int *)st->xim->data;
303 ptr += (st->top << 1) * st->width;
304 ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
306 for( y = st->top; y < st->fheight; y++)
308 for( x = 0; x < st->fwidth; x++)
311 v2 = (int)*(ptr1 + 1);
312 v3 = (int)*(ptr1 + st->fwidth + 2);
313 v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
315 *ptr++ = (unsigned int)st->ctab[v1];
316 *ptr = (unsigned int)st->ctab[(v1 + v2) >> 1];
317 ptr += st->width - 1;
318 *ptr++ = (unsigned int)st->ctab[(v1 + v3) >> 1];
319 *ptr = (unsigned int)st->ctab[(v1 + v4) >> 1];
320 ptr -= st->width - 1;
328 Flame2Image24(struct state *st)
335 ptr = (unsigned char *)st->xim->data;
336 ptr += (st->top << 1) * st->xim->bytes_per_line;
337 ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
339 for( y = st->top; y < st->fheight; y++)
341 unsigned char *last_ptr = ptr;
342 for( x = 0; x < st->fwidth; x++)
345 v2 = (int)*(ptr1 + 1);
346 v3 = (int)*(ptr1 + st->fwidth + 2);
347 v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
350 ptr[2] = ((unsigned int)st->ctab[v1] & 0x00FF0000) >> 16;
351 ptr[1] = ((unsigned int)st->ctab[v1] & 0x0000FF00) >> 8;
352 ptr[0] = ((unsigned int)st->ctab[v1] & 0x000000FF);
355 ptr[2] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x00FF0000) >> 16;
356 ptr[1] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x0000FF00) >> 8;
357 ptr[0] = ((unsigned int)st->ctab[(v1 + v2) >> 1] & 0x000000FF);
358 ptr += ((st->width - 1) * 3);
360 ptr[2] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x00FF0000) >> 16;
361 ptr[1] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x0000FF00) >> 8;
362 ptr[0] = ((unsigned int)st->ctab[(v1 + v3) >> 1] & 0x000000FF);
365 ptr[2] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x00FF0000) >> 16;
366 ptr[1] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x0000FF00) >> 8;
367 ptr[0] = ((unsigned int)st->ctab[(v1 + v4) >> 1] & 0x000000FF);
368 ptr -= ((st->width - 1) * 3);
371 ptr = last_ptr + (st->xim->bytes_per_line << 1);
377 Flame2Image8(struct state *st)
384 ptr = (unsigned char *)st->xim->data;
385 ptr += (st->top << 1) * st->width;
386 ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
388 for(y=st->top;y<st->fheight;y++)
390 for(x=0;x<st->fwidth;x++)
393 v2 = (int)*(ptr1 + 1);
394 v3 = (int)*(ptr1 + st->fwidth + 2);
395 v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
397 *ptr++ = (unsigned char)st->ctab[v1];
398 *ptr = (unsigned char)st->ctab[(v1 + v2) >> 1];
399 ptr += st->width - 1;
400 *ptr++ = (unsigned char)st->ctab[(v1 + v3) >> 1];
401 *ptr = (unsigned char)st->ctab[(v1 + v4) >> 1];
402 ptr -= st->width - 1;
410 Flame2Image1234567(struct state *st)
416 ptr1 = st->flame + 1 + (st->top * (st->fwidth + 2));
418 for( y = st->top; y < st->fheight; y++)
420 for( x = 0; x < st->fwidth; x++)
423 v2 = (int)*(ptr1 + 1);
424 v3 = (int)*(ptr1 + st->fwidth + 2);
425 v4 = (int)*(ptr1 + st->fwidth + 2 + 1);
427 XPutPixel(st->xim,(x << 1), (y << 1), st->ctab[v1]);
428 XPutPixel(st->xim,(x << 1) + 1,(y << 1), st->ctab[(v1 + v2) >> 1]);
429 XPutPixel(st->xim,(x << 1), (y << 1) + 1,st->ctab[(v1 + v3) >> 1]);
430 XPutPixel(st->xim,(x << 1) + 1,(y << 1) + 1,st->ctab[(v1 + v4) >> 1]);
436 Flame2Image(struct state *st)
438 switch (st->xim->bits_per_pixel)
440 case 32: Flame2Image32(st); break;
441 case 24: Flame2Image24(st); break;
442 case 16: Flame2Image16(st); break;
443 case 8: Flame2Image8(st); break;
445 if (st->xim->bits_per_pixel <= 7)
446 Flame2Image1234567(st);
455 FlameActive(struct state *st)
460 ptr1 = st->flame + ((st->fheight + 1) * (st->fwidth + 2));
462 for (x = 0; x < st->fwidth + 2; x++)
465 v1 += ((random() % st->variance) - st->vartrend);
471 v1= (random() % 100);
473 st->residual += (random()%10);
475 st->hspread += (random()%15);
477 st->vspread += (random()%20);
480 st->residual = ((st->iresidual* 10) + (st->residual *90)) / 100;
481 st->hspread = ((st->ihspread * 10) + (st->hspread *90)) / 100;
482 st->vspread = ((st->ivspread * 10) + (st->vspread *90)) / 100;
487 FlameAdvance(struct state *st)
491 int newtop = st->top;
493 for (y = st->fheight + 1; y >= st->top; y--)
496 unsigned char *ptr1 = st->flame + 1 + (y * (st->fwidth + 2));
497 for (x = 0; x < st->fwidth; x++)
504 ptr2 = ptr1 - st->fwidth - 2;
505 v3 = (v1 * st->vspread) >> 8;
511 *(ptr2) = (unsigned char)v2;
512 v3 = (v1 * st->hspread) >> 8;
513 v2 = (int)*(ptr2 + 1);
518 *(ptr2 + 1) = (unsigned char)v2;
519 v2 = (int)*(ptr2 - 1);
524 *(ptr2 - 1) = (unsigned char)v2;
526 if (y < st->fheight + 1)
528 v1 = (v1 * st->residual) >> 8;
529 *ptr1 = (unsigned char)v1;
537 /* clean up the right gutter */
540 v1 = (v1 * st->residual) >> 8;
541 *ptr1 = (unsigned char)v1;
545 st->top = newtop - 1;
553 FlameFill(struct state *st, int val)
556 for (y = 0; y < st->fheight + 1; y++)
558 unsigned char *ptr1 = st->flame + 1 + (y * (st->fwidth + 2));
559 for (x = 0; x < st->fwidth; x++)
569 FlamePasteData(struct state *st,
570 unsigned char *d, int xx, int yy, int w, int h)
572 unsigned char *ptr1,*ptr2;
580 (xx + w <= st->fwidth) &&
581 (yy + h <= st->fheight))
584 for (y = 0; y < h; y++)
586 ptr1 = st->flame + 1 + xx + ((yy + y) * (st->fwidth + 2));
587 for (x = 0; x < w; x++)
590 *ptr1 += random() % (*ptr2 / 24);
599 static Bool warned = False;
602 fprintf (stderr, "%s: st->window is %dx%d; image must be "
603 "smaller than %dx%d (not %dx%d).\n",
604 progname, st->width, st->height, st->fwidth, st->fheight, w, h);
611 static unsigned char *
612 loadBitmap(struct state *st, int *w, int *h)
615 const char *bitmap_name = "(default)"; /* #### always use builtin */
617 char *bitmap_name = get_string_resource (st->dpy, "bitmap", "Bitmap");
622 !strcmp(bitmap_name, "none"))
624 else if (!strcmp(bitmap_name, "(default)")) /* use the builtin */
627 unsigned char *result, *o;
628 unsigned char *bits = (unsigned char *) malloc (sizeof(bob_bits));
630 int scale = ((st->width > bob_width * 10) ? 2 : 1);
632 memcpy (bits, bob_bits, sizeof(bob_bits));
633 ximage = XCreateImage (st->dpy, st->visual, 1, XYBitmap, 0,
634 (char *) bits, bob_width, bob_height, 8, 0);
635 ximage->byte_order = LSBFirst;
636 ximage->bitmap_bit_order = LSBFirst;
637 *w = ximage->width * scale;
638 *h = ximage->height * scale;
639 o = result = (unsigned char *) malloc ((*w * scale) * (*h * scale));
640 for (y = 0; y < *h; y++)
641 for (x = 0; x < *w; x++)
642 *o++ = (XGetPixel(ximage, x/scale, y/scale) ? 255 : 0);
646 else /* load a bitmap file */
648 abort(); /* #### fix me */
652 xpm_file_to_pixmap (st->dpy, st->window, bitmap_name, &st->width, &st->height, 0);
655 unsigned char *result, *o;
657 Bool cmap_p = has_writable_cells (st->screen, st->visual);
662 for (i = 0; i < countof (colors); i++)
664 XQueryColors (st->dpy, st->colormap, colors, countof (colors));
667 image = XGetImage (st->dpy, pixmap, 0, 0, st->width, st->height, ~0L, ZPixmap);
668 XFreePixmap(st->dpy, pixmap);
670 result = (unsigned char *) malloc (st->width * st->height);
672 for (y = 0; y < st->height; y++)
673 for (x = 0; x < st->width; x++)
675 int rgba = XGetPixel (image, x, y);
678 gray = ((200 - ((((colors[rgba].red >> 8) & 0xFF) +
679 ((colors[rgba].green >> 8) & 0xFF) +
680 ((colors[rgba].blue >> 8) & 0xFF))
684 /* This is *so* not handling all the cases... */
685 gray = (image->depth > 16
686 ? ((((rgba >> 24) & 0xFF) +
687 ((rgba >> 16) & 0xFF) +
688 ((rgba >> 8) & 0xFF) +
689 ((rgba ) & 0xFF)) >> 2)
690 : ((((rgba >> 12) & 0x0F) +
691 ((rgba >> 8) & 0x0F) +
692 ((rgba >> 4) & 0x0F) +
693 ((rgba ) & 0x0F)) >> 1));
700 XDestroyImage (image);
706 #endif /* !HAVE_JWXYZ */
715 xflame_init (Display *dpy, Window win)
717 struct state *st = (struct state *) calloc (1, sizeof(*st));
720 st->baseline = get_integer_resource (dpy, "bitmapBaseline", "Integer");
721 st->delay = get_integer_resource (dpy, "delay", "Integer");
728 st->theim = loadBitmap(st, &st->theimx, &st->theimy);
738 xflame_draw (Display *dpy, Window win, void *closure)
740 struct state *st = (struct state *) closure;
744 FlamePasteData(st, st->theim, (st->fwidth - st->theimx) / 2,
745 st->fheight - st->theimy - st->baseline, st->theimx, st->theimy);
755 xflame_reshape (Display *dpy, Window window, void *closure,
756 unsigned int w, unsigned int h)
758 struct state *st = (struct state *) closure;
763 XClearWindow (dpy, window);
767 xflame_event (Display *dpy, Window window, void *closure, XEvent *event)
773 xflame_free (Display *dpy, Window window, void *closure)
780 static const char *xflame_defaults [] = {
781 ".background: black",
782 ".foreground: #FFAF5F",
785 "*bitmap: (default)",
786 "*bitmapBaseline: 20",
795 #ifdef HAVE_XSHM_EXTENSION
796 "*useSHM: False", /* xshm turns out not to help. */
797 #endif /* HAVE_XSHM_EXTENSION */
801 static XrmOptionDescRec xflame_options [] = {
802 { "-foreground",".foreground", XrmoptionSepArg, 0 },
803 { "-fg", ".foreground", XrmoptionSepArg, 0 },
804 { "-delay", ".delay", XrmoptionSepArg, 0 },
805 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
806 { "-baseline", ".bitmapBaseline", XrmoptionSepArg, 0 },
807 { "-hspread", ".hspread", XrmoptionSepArg, 0 },
808 { "-vspread", ".vspread", XrmoptionSepArg, 0 },
809 { "-residual", ".residual", XrmoptionSepArg, 0 },
810 { "-variance", ".variance", XrmoptionSepArg, 0 },
811 { "-vartrend", ".vartrend", XrmoptionSepArg, 0 },
812 { "-bloom", ".bloom", XrmoptionNoArg, "True" },
813 { "-no-bloom", ".bloom", XrmoptionNoArg, "False" },
814 #ifdef HAVE_XSHM_EXTENSION
815 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
816 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
817 #endif /* HAVE_XSHM_EXTENSION */
822 XSCREENSAVER_MODULE ("XFlame", xflame)