1 /* xflame, Copyright (c) 1996-1999 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.)
47 /* portions by Daniel Zahn <stumpy@religions.com> */
50 #include "screenhack.h"
51 #include <X11/Xutil.h>
54 #ifdef HAVE_XSHM_EXTENSION
56 #endif /* HAVE_XSHM_EXTENSION */
60 # ifndef PIXEL_ALREADY_TYPEDEFED
61 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
67 # include <X11/Xmu/Drawing.h>
69 # include <Xmu/Drawing.h>
73 #include "images/bob.xbm"
77 static Display *display;
82 static Colormap colormap;
83 static Visual *visual;
87 #ifdef HAVE_XSHM_EXTENSION
88 static XShmSegmentInfo shminfo;
89 #endif /* HAVE_XSHM_EXTENSION */
93 static unsigned char *flame;
94 static unsigned char *theim;
104 static int iresidual;
109 GetXInfo(Display *disp, Window win)
111 XWindowAttributes xwa;
113 XGetWindowAttributes(disp,win,&xwa);
117 colormap = xwa.colormap;
134 #ifdef HAVE_XSHM_EXTENSION
136 xim = create_xshm_image (display, visual, depth, ZPixmap, NULL,
137 &shminfo, width, height);
138 #else /* !HAVE_XSHM_EXTENSION */
140 #endif /* !HAVE_XSHM_EXTENSION */
145 xim = XCreateImage (display, visual, depth, ZPixmap, 0, NULL,
146 width, height, 32, 0);
148 xim->data = (char *) calloc(xim->height, xim->bytes_per_line);
149 if (!xim || !xim->data)
151 fprintf(stderr,"%s: out of memory.\n", progname);
156 gc = XCreateGC(display,window,0,&gcv);
164 int i = 0, j = 0, red = 0, green = 0, blue = 0;
167 /* Make it possible to set the color of the flames,
168 by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
170 fg.pixel = get_pixel_resource ("foreground", "Foreground",
172 XQueryColor (display, colormap, &fg);
174 red = 255 - (fg.red >> 8);
175 green = 255 - (fg.green >> 8);
176 blue = 255 - (fg.blue >> 8);
179 for (i = 0; i < 256 * 2; i += 2)
182 int r = (i - red) * 3;
183 int g = (i - green) * 3;
184 int b = (i - blue) * 3;
187 if (r > 255) r = 255;
189 if (g > 255) g = 255;
191 if (b > 255) b = 255;
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;
198 XAllocColor(display,colormap,&xcl);
200 ctab[j++] = (int)xcl.pixel;
208 #ifdef HAVE_XSHM_EXTENSION
210 XShmPutImage(display, window, gc, xim, 0,(top - 1) << 1, 0,
211 (top - 1) << 1, width, height - ((top - 1) << 1), False);
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));
223 fheight = height / 2;
224 flame = (unsigned char *) malloc((fwidth + 2) * (fheight + 2)
225 * sizeof(unsigned char));
229 fprintf(stderr,"%s: out of memory\n", progname);
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");
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 (ihspread, "hspread");
247 THROTTLE (ivspread, "vspread");
248 THROTTLE (iresidual,"residual");
249 THROTTLE (variance, "variance");
250 THROTTLE (vartrend, "vartrend");
257 residual = iresidual;
269 ptr = (unsigned short *)xim->data;
270 ptr += (top << 1) * width;
271 ptr1 = flame + 1 + (top * (fwidth + 2));
273 for(y = top; y < fheight; y++)
275 for( x = 0; x < fwidth; x++)
278 v2 = (int)*(ptr1 + 1);
279 v3 = (int)*(ptr1 + fwidth + 2);
280 v4 = (int)*(ptr1 + fwidth + 2 + 1);
282 *ptr++ = (unsigned short)ctab[v1];
283 *ptr = (unsigned short)ctab[(v1 + v2) >> 1];
285 *ptr++ = (unsigned short)ctab[(v1 + v3) >> 1];
286 *ptr = (unsigned short)ctab[(v1 + v4) >> 1];
302 ptr = (unsigned int *)xim->data;
303 ptr += (top << 1) * width;
304 ptr1 = flame + 1 + (top * (fwidth + 2));
306 for( y = top; y < fheight; y++)
308 for( x = 0; x < fwidth; x++)
311 v2 = (int)*(ptr1 + 1);
312 v3 = (int)*(ptr1 + fwidth + 2);
313 v4 = (int)*(ptr1 + fwidth + 2 + 1);
315 *ptr++ = (unsigned int)ctab[v1];
316 *ptr = (unsigned int)ctab[(v1 + v2) >> 1];
318 *ptr++ = (unsigned int)ctab[(v1 + v3) >> 1];
319 *ptr = (unsigned int)ctab[(v1 + v4) >> 1];
335 ptr = (unsigned char *)xim->data;
336 ptr += (top << 1) * xim->bytes_per_line;
337 ptr1 = flame + 1 + (top * (fwidth + 2));
339 for( y = top; y < fheight; y++)
341 unsigned char *last_ptr = ptr;
342 for( x = 0; x < fwidth; x++)
345 v2 = (int)*(ptr1 + 1);
346 v3 = (int)*(ptr1 + fwidth + 2);
347 v4 = (int)*(ptr1 + fwidth + 2 + 1);
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);
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);
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);
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);
371 ptr = last_ptr + (xim->bytes_per_line << 1);
384 ptr = (unsigned char *)xim->data;
385 ptr += (top << 1) * width;
386 ptr1 = flame + 1 + (top * (fwidth + 2));
388 for(y=top;y<fheight;y++)
390 for(x=0;x<fwidth;x++)
393 v2 = (int)*(ptr1 + 1);
394 v3 = (int)*(ptr1 + fwidth + 2);
395 v4 = (int)*(ptr1 + fwidth + 2 + 1);
397 *ptr++ = (unsigned char)ctab[v1];
398 *ptr = (unsigned char)ctab[(v1 + v2) >> 1];
400 *ptr++ = (unsigned char)ctab[(v1 + v3) >> 1];
401 *ptr = (unsigned char)ctab[(v1 + v4) >> 1];
410 Flame2Image1234567(void)
416 ptr1 = flame + 1 + (top * (fwidth + 2));
418 for( y = top; y < fheight; y++)
420 for( x = 0; x < fwidth; x++)
423 v2 = (int)*(ptr1 + 1);
424 v3 = (int)*(ptr1 + fwidth + 2);
425 v4 = (int)*(ptr1 + fwidth + 2 + 1);
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]);
438 switch (xim->bits_per_pixel)
440 case 32: Flame2Image32(); break;
441 case 24: Flame2Image24(); break;
442 case 16: Flame2Image16(); break;
443 case 8: Flame2Image8(); break;
445 if (xim->bits_per_pixel <= 7)
446 Flame2Image1234567();
460 ptr1 = flame + ((fheight + 1) * (fwidth + 2));
462 for (x = 0; x < fwidth + 2; x++)
465 v1 += ((random() % variance) - vartrend);
471 v1= (random() % 100);
473 residual += (random()%10);
475 hspread += (random()%15);
477 vspread += (random()%20);
480 residual = ((iresidual* 10) + (residual *90)) / 100;
481 hspread = ((ihspread * 10) + (hspread *90)) / 100;
482 vspread = ((ivspread * 10) + (vspread *90)) / 100;
493 for (y = fheight + 1; y >= top; y--)
496 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
497 for (x = 0; x < fwidth; x++)
504 ptr2 = ptr1 - fwidth - 2;
505 v3 = (v1 * vspread) >> 8;
511 *(ptr2) = (unsigned char)v2;
512 v3 = (v1 * hspread) >> 8;
513 v2 = (int)*(ptr2 + 1);
518 *(ptr2 + 1) = (unsigned char)v2;
519 v2 = (int)*(ptr2 - 1);
524 *(ptr2 - 1) = (unsigned char)v2;
528 v1 = (v1 * residual) >> 8;
529 *ptr1 = (unsigned char)v1;
537 /* clean up the right gutter */
540 v1 = (v1 * residual) >> 8;
541 *ptr1 = (unsigned char)v1;
556 for (y = 0; y < fheight + 1; y++)
558 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
559 for (x = 0; x < fwidth; x++)
569 FlamePasteData(unsigned char *d, int xx, int yy, int w, int h)
571 unsigned char *ptr1,*ptr2;
579 (xx + w <= fwidth) &&
583 for (y = 0; y < h; y++)
585 ptr1 = flame + 1 + xx + ((yy + y) * (fwidth + 2));
586 for (x = 0; x < w; x++)
589 *ptr1 += random() % (*ptr2 / 24);
598 static Bool warned = False;
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);
610 static unsigned char *
611 loadBitmap(int *w, int *h)
613 char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
617 !strcmp(bitmap_name, "none"))
619 else if (!strcmp(bitmap_name, "(default)")) /* use the builtin */
622 unsigned char *result, *o;
623 char *bits = (char *) malloc (sizeof(bob_bits));
625 int scale = ((width > bob_width * 11) ? 2 : 1);
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);
641 else /* load a bitmap file */
644 XpmInfo xpm_info = { 0, };
645 XpmImage xpm_image = { 0, };
647 int result = XpmReadFileToXpmImage (bitmap_name, &xpm_image, &xpm_info);
648 if (result == XpmSuccess)
651 unsigned char *result, *o;
652 unsigned char *grays;
653 XWindowAttributes xgwa;
655 *w = xpm_image.width;
656 *h = xpm_image.height;
657 result = (unsigned char *) malloc ((*w) * (*h));
660 fprintf(stderr, "%s: out of memory loading %s\n",
661 progname, bitmap_name);
665 XGetWindowAttributes (display, window, &xgwa);
667 grays = (unsigned char *) calloc (xpm_image.ncolors+1, 1);
668 for (x = 0; x < xpm_image.ncolors; x++)
671 XpmColor *xpmc = &xpm_image.colorTable[x];
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;
680 cstring = xpmc->m_color;
682 memset (&xc, 0, sizeof(xc));
685 !XParseColor (display, xgwa.colormap, cstring, &xc))
688 grays[x] = (int) (((xc.red * 0.299) +
695 for (y = 0; y < *h; y++)
696 for (x = 0; x < *w; x++)
698 int color = xpm_image.data[(y * (*w)) + x];
699 if (color < 0 || color > xpm_image.ncolors) abort();
704 else /* failed to read XPM -- fall through and try XBM */
705 #endif /* HAVE_XPM */
709 int width, height, xh, yh;
711 unsigned char *result, *o;
713 XmuLocateBitmapFile (DefaultScreenOfDisplay (display),
714 bitmap_name, 0, 0, &width, &height, &xh, &yh);
717 fprintf(stderr, "%s: unable to load bitmap file %s\n",
718 progname, bitmap_name);
721 ximage = XGetImage (display, bitmap, 0, 0, width, height,
723 XFreePixmap (display, bitmap);
725 if (ximage->depth != 1) abort();
729 result = (unsigned char *) malloc ((*w) * (*h));
732 fprintf(stderr, "%s: out of memory loading %s\n",
733 progname, bitmap_name);
738 for (y = 0; y < *h; y++)
739 for (x = 0; x < *w; x++)
740 *o++ = (XGetPixel(ximage, x, y) ? 255 : 0);
746 "%s: your vendor doesn't ship the standard Xmu library.\n",
748 fprintf (stderr, "\tWe can't load XBM files without it.\n");
762 char *progclass = "XFlame";
764 char *defaults [] = {
765 ".background: black",
766 ".foreground: #FFAF5F",
767 "*bitmap: (default)",
768 "*bitmapBaseline: 20",
777 #ifdef HAVE_XSHM_EXTENSION
778 "*useSHM: False", /* xshm turns out not to help. */
779 #endif /* HAVE_XSHM_EXTENSION */
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 */
802 screenhack (Display *disp, Window win)
804 int theimx = 0, theimy = 0;
805 int baseline = get_integer_resource ("bitmapBaseline", "Integer");
806 int delay = get_integer_resource ("delay", "Integer");
813 theim = loadBitmap(&theimx, &theimy);
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.
830 FlamePasteData(theim, (fwidth - theimx) / 2,
831 fheight - theimy - baseline, theimx, theimy);
837 XSync(display,False);
838 screenhack_handle_events(display);