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;
549 for (y = 0; y < fheight + 1; y++)
551 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
552 for (x = 0; x < fwidth; x++)
562 FlamePasteData(unsigned char *d, int xx, int yy, int w, int h)
564 unsigned char *ptr1,*ptr2;
572 (xx + w <= fwidth) &&
576 for (y = 0; y < h; y++)
578 ptr1 = flame + 1 + xx + ((yy + y) * (fwidth + 2));
579 for (x = 0; x < w; x++)
582 *ptr1 += random() % (*ptr2 / 24);
591 static Bool warned = False;
594 fprintf (stderr, "%s: window is %dx%d; image must be "
595 "smaller than %dx%d (not %dx%d).\n",
596 progname, width, height, fwidth, fheight, w, h);
603 static unsigned char *
604 loadBitmap(int *w, int *h)
606 char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
610 !strcmp(bitmap_name, "none"))
612 else if (!strcmp(bitmap_name, "(default)")) /* use the builtin */
615 unsigned char *result, *o;
616 char *bits = (char *) malloc (sizeof(bob_bits));
618 int scale = ((width > bob_width * 11) ? 2 : 1);
620 memcpy (bits, bob_bits, sizeof(bob_bits));
621 ximage = XCreateImage (display, visual, 1, XYBitmap, 0, bits,
622 bob_width, bob_height, 8, 0);
623 ximage->byte_order = LSBFirst;
624 ximage->bitmap_bit_order = LSBFirst;
625 *w = ximage->width * scale;
626 *h = ximage->height * scale;
627 o = result = (unsigned char *) malloc ((*w * scale) * (*h * scale));
628 for (y = 0; y < *h; y++)
629 for (x = 0; x < *w; x++)
630 *o++ = (XGetPixel(ximage, x/scale, y/scale) ? 255 : 0);
634 else /* load a bitmap file */
637 XpmInfo xpm_info = { 0, };
638 XpmImage xpm_image = { 0, };
640 int result = XpmReadFileToXpmImage (bitmap_name, &xpm_image, &xpm_info);
641 if (result == XpmSuccess)
644 unsigned char *result, *o;
645 unsigned char *grays;
646 XWindowAttributes xgwa;
648 *w = xpm_image.width;
649 *h = xpm_image.height;
650 result = (unsigned char *) malloc ((*w) * (*h));
653 fprintf(stderr, "%s: out of memory loading %s\n",
654 progname, bitmap_name);
658 XGetWindowAttributes (display, window, &xgwa);
660 grays = (unsigned char *) calloc (xpm_image.ncolors+1, 1);
661 for (x = 0; x < xpm_image.ncolors; x++)
664 XpmColor *xpmc = &xpm_image.colorTable[x];
666 if (xpmc->g_color && *xpmc->g_color)
667 cstring = xpmc->g_color;
668 else if (xpmc->g4_color && *xpmc->g4_color)
669 cstring = xpmc->g4_color;
670 else if (xpmc->c_color && *xpmc->c_color)
671 cstring = xpmc->c_color;
673 cstring = xpmc->m_color;
675 memset (&xc, 0, sizeof(xc));
678 !XParseColor (display, xgwa.colormap, cstring, &xc))
681 grays[x] = (int) (((xc.red * 0.299) +
688 for (y = 0; y < *h; y++)
689 for (x = 0; x < *w; x++)
691 int color = xpm_image.data[(y * (*w)) + x];
692 if (color < 0 || color > xpm_image.ncolors) abort();
697 else /* failed to read XPM -- fall through and try XBM */
698 #endif /* HAVE_XPM */
702 int width, height, xh, yh;
704 unsigned char *result, *o;
706 XmuLocateBitmapFile (DefaultScreenOfDisplay (display),
707 bitmap_name, 0, 0, &width, &height, &xh, &yh);
710 fprintf(stderr, "%s: unable to load bitmap file %s\n",
711 progname, bitmap_name);
714 ximage = XGetImage (display, bitmap, 0, 0, width, height,
716 XFreePixmap (display, bitmap);
718 if (ximage->depth != 1) abort();
722 result = (unsigned char *) malloc ((*w) * (*h));
725 fprintf(stderr, "%s: out of memory loading %s\n",
726 progname, bitmap_name);
731 for (y = 0; y < *h; y++)
732 for (x = 0; x < *w; x++)
733 *o++ = (XGetPixel(ximage, x, y) ? 255 : 0);
739 "%s: your vendor doesn't ship the standard Xmu library.\n",
741 fprintf (stderr, "\tWe can't load XBM files without it.\n");
755 char *progclass = "XFlame";
757 char *defaults [] = {
758 ".background: black",
759 ".foreground: #FFAF5F",
760 "*bitmap: (default)",
761 "*bitmapBaseline: 20",
770 #ifdef HAVE_XSHM_EXTENSION
771 "*useSHM: False", /* xshm turns out not to help. */
772 #endif /* HAVE_XSHM_EXTENSION */
776 XrmOptionDescRec options [] = {
777 { "-delay", ".delay", XrmoptionSepArg, 0 },
778 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
779 { "-baseline", ".bitmapBaseline", XrmoptionSepArg, 0 },
780 { "-hspread", ".hspread", XrmoptionSepArg, 0 },
781 { "-vspread", ".vspread", XrmoptionSepArg, 0 },
782 { "-residual", ".residual", XrmoptionSepArg, 0 },
783 { "-variance", ".variance", XrmoptionSepArg, 0 },
784 { "-vartrend", ".vartrend", XrmoptionSepArg, 0 },
785 { "-bloom", ".bloom", XrmoptionNoArg, "True" },
786 { "-no-bloom", ".bloom", XrmoptionNoArg, "False" },
787 #ifdef HAVE_XSHM_EXTENSION
788 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
789 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
790 #endif /* HAVE_XSHM_EXTENSION */
795 screenhack (Display *disp, Window win)
797 int theimx = 0, theimy = 0;
798 int baseline = get_integer_resource ("bitmapBaseline", "Integer");
799 int delay = get_integer_resource ("delay", "Integer");
806 theim = loadBitmap(&theimx, &theimy);
808 /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
809 makes it hard for us to react to window resizing. So, punt for now. The
810 size of the window at startup is the size it will stay.
823 FlamePasteData(theim, (fwidth - theimx) / 2,
824 fheight - theimy - baseline, theimx, theimy);
830 XSync(display,False);
831 screenhack_handle_events(display);