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>
75 static Display *display;
80 static Colormap colormap;
81 static Visual *visual;
85 #ifdef HAVE_XSHM_EXTENSION
86 static XShmSegmentInfo shminfo;
87 #endif /* HAVE_XSHM_EXTENSION */
91 static unsigned char *flame;
92 static unsigned char *theim;
102 static int iresidual;
107 GetXInfo(Display *disp, Window win)
109 XWindowAttributes xwa;
111 XGetWindowAttributes(disp,win,&xwa);
115 colormap = xwa.colormap;
132 #ifdef HAVE_XSHM_EXTENSION
134 xim = create_xshm_image (display, visual, depth, ZPixmap, NULL,
135 &shminfo, width, height);
136 #else /* !HAVE_XSHM_EXTENSION */
138 #endif /* !HAVE_XSHM_EXTENSION */
143 xim = XCreateImage (display, visual, depth, ZPixmap, 0, NULL,
144 width, height, 32, 0);
146 xim->data = (char *) calloc(xim->height, xim->bytes_per_line);
147 if (!xim || !xim->data)
149 fprintf(stderr,"%s: out of memory.\n", progname);
154 gc = XCreateGC(display,window,0,&gcv);
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 ("foreground", "Foreground",
170 XQueryColor (display, 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(display,colormap,&xcl);
198 ctab[j++] = (int)xcl.pixel;
206 #ifdef HAVE_XSHM_EXTENSION
208 XShmPutImage(display, window, gc, xim, 0,(top - 1) << 1, 0,
209 (top - 1) << 1, width, height - ((top - 1) << 1), False);
211 #endif /* HAVE_XSHM_EXTENSION */
212 XPutImage(display, window, gc, xim, 0, (top - 1) << 1, 0,
213 (top - 1) << 1, width, height - ((top - 1) << 1));
221 fheight = height / 2;
222 flame = (unsigned char *) malloc((fwidth + 2) * (fheight + 2)
223 * sizeof(unsigned char));
227 fprintf(stderr,"%s: out of memory\n", progname);
232 ihspread = get_integer_resource("hspread", "Integer");
233 ivspread = get_integer_resource("vspread", "Integer");
234 iresidual = get_integer_resource("residual", "Integer");
235 variance = get_integer_resource("variance", "Integer");
236 vartrend = get_integer_resource("vartrend", "Integer");
237 bloom = get_boolean_resource("bloom", "Boolean");
239 # define THROTTLE(VAR,NAME) \
240 if (VAR < 0 || VAR > 255) { \
241 fprintf(stderr, "%s: %s must be in the range 0-255 (not %d).\n", \
242 progname, NAME, VAR); \
244 THROTTLE (ihspread, "hspread");
245 THROTTLE (ivspread, "vspread");
246 THROTTLE (iresidual,"residual");
247 THROTTLE (variance, "variance");
248 THROTTLE (vartrend, "vartrend");
255 residual = iresidual;
267 ptr = (unsigned short *)xim->data;
268 ptr += (top << 1) * width;
269 ptr1 = flame + 1 + (top * (fwidth + 2));
271 for(y = top; y < fheight; y++)
273 for( x = 0; x < fwidth; x++)
276 v2 = (int)*(ptr1 + 1);
277 v3 = (int)*(ptr1 + fwidth + 2);
278 v4 = (int)*(ptr1 + fwidth + 2 + 1);
280 *ptr++ = (unsigned short)ctab[v1];
281 *ptr = (unsigned short)ctab[(v1 + v2) >> 1];
283 *ptr++ = (unsigned short)ctab[(v1 + v3) >> 1];
284 *ptr = (unsigned short)ctab[(v1 + v4) >> 1];
300 ptr = (unsigned int *)xim->data;
301 ptr += (top << 1) * width;
302 ptr1 = flame + 1 + (top * (fwidth + 2));
304 for( y = top; y < fheight; y++)
306 for( x = 0; x < fwidth; x++)
309 v2 = (int)*(ptr1 + 1);
310 v3 = (int)*(ptr1 + fwidth + 2);
311 v4 = (int)*(ptr1 + fwidth + 2 + 1);
313 *ptr++ = (unsigned int)ctab[v1];
314 *ptr = (unsigned int)ctab[(v1 + v2) >> 1];
316 *ptr++ = (unsigned int)ctab[(v1 + v3) >> 1];
317 *ptr = (unsigned int)ctab[(v1 + v4) >> 1];
333 ptr = (unsigned char *)xim->data;
334 ptr += (top << 1) * xim->bytes_per_line;
335 ptr1 = flame + 1 + (top * (fwidth + 2));
337 for( y = top; y < fheight; y++)
339 unsigned char *last_ptr = ptr;
340 for( x = 0; x < fwidth; x++)
343 v2 = (int)*(ptr1 + 1);
344 v3 = (int)*(ptr1 + fwidth + 2);
345 v4 = (int)*(ptr1 + fwidth + 2 + 1);
348 ptr[2] = ((unsigned int)ctab[v1] & 0x00FF0000) >> 16;
349 ptr[1] = ((unsigned int)ctab[v1] & 0x0000FF00) >> 8;
350 ptr[0] = ((unsigned int)ctab[v1] & 0x000000FF);
353 ptr[2] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x00FF0000) >> 16;
354 ptr[1] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x0000FF00) >> 8;
355 ptr[0] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x000000FF);
356 ptr += ((width - 1) * 3);
358 ptr[2] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x00FF0000) >> 16;
359 ptr[1] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x0000FF00) >> 8;
360 ptr[0] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x000000FF);
363 ptr[2] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x00FF0000) >> 16;
364 ptr[1] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x0000FF00) >> 8;
365 ptr[0] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x000000FF);
366 ptr -= ((width - 1) * 3);
369 ptr = last_ptr + (xim->bytes_per_line << 1);
382 ptr = (unsigned char *)xim->data;
383 ptr += (top << 1) * width;
384 ptr1 = flame + 1 + (top * (fwidth + 2));
386 for(y=top;y<fheight;y++)
388 for(x=0;x<fwidth;x++)
391 v2 = (int)*(ptr1 + 1);
392 v3 = (int)*(ptr1 + fwidth + 2);
393 v4 = (int)*(ptr1 + fwidth + 2 + 1);
395 *ptr++ = (unsigned char)ctab[v1];
396 *ptr = (unsigned char)ctab[(v1 + v2) >> 1];
398 *ptr++ = (unsigned char)ctab[(v1 + v3) >> 1];
399 *ptr = (unsigned char)ctab[(v1 + v4) >> 1];
408 Flame2Image1234567(void)
414 ptr1 = flame + 1 + (top * (fwidth + 2));
416 for( y = top; y < fheight; y++)
418 for( x = 0; x < fwidth; x++)
421 v2 = (int)*(ptr1 + 1);
422 v3 = (int)*(ptr1 + fwidth + 2);
423 v4 = (int)*(ptr1 + fwidth + 2 + 1);
425 XPutPixel(xim,(x << 1), (y << 1), ctab[v1]);
426 XPutPixel(xim,(x << 1) + 1,(y << 1), ctab[(v1 + v2) >> 1]);
427 XPutPixel(xim,(x << 1), (y << 1) + 1,ctab[(v1 + v3) >> 1]);
428 XPutPixel(xim,(x << 1) + 1,(y << 1) + 1,ctab[(v1 + v4) >> 1]);
436 switch (xim->bits_per_pixel)
438 case 32: Flame2Image32(); break;
439 case 24: Flame2Image24(); break;
440 case 16: Flame2Image16(); break;
441 case 8: Flame2Image8(); break;
443 if (xim->bits_per_pixel <= 7)
444 Flame2Image1234567();
458 ptr1 = flame + ((fheight + 1) * (fwidth + 2));
460 for (x = 0; x < fwidth + 2; x++)
463 v1 += ((random() % variance) - vartrend);
469 v1= (random() % 100);
471 residual += (random()%10);
473 hspread += (random()%15);
475 vspread += (random()%20);
478 residual = ((iresidual* 10) + (residual *90)) / 100;
479 hspread = ((ihspread * 10) + (hspread *90)) / 100;
480 vspread = ((ivspread * 10) + (vspread *90)) / 100;
491 for (y = fheight + 1; y >= top; y--)
494 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
495 for (x = 0; x < fwidth; x++)
502 ptr2 = ptr1 - fwidth - 2;
503 v3 = (v1 * vspread) >> 8;
509 *(ptr2) = (unsigned char)v2;
510 v3 = (v1 * hspread) >> 8;
511 v2 = (int)*(ptr2 + 1);
516 *(ptr2 + 1) = (unsigned char)v2;
517 v2 = (int)*(ptr2 - 1);
522 *(ptr2 - 1) = (unsigned char)v2;
526 v1 = (v1 * residual) >> 8;
527 *ptr1 = (unsigned char)v1;
547 for (y = 0; y < fheight + 1; y++)
549 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
550 for (x = 0; x < fwidth; x++)
560 FlamePasteData(unsigned char *d, int xx, int yy, int w, int h)
562 unsigned char *ptr1,*ptr2;
570 (xx + w <= fwidth) &&
574 for (y = 0; y < h; y++)
576 ptr1 = flame + 1 + xx + ((yy + y) * (fwidth + 2));
577 for (x = 0; x < w; x++)
580 *ptr1 += random() % (*ptr2 / 24);
589 static Bool warned = False;
592 fprintf (stderr, "%s: window is %dx%d; image must be "
593 "smaller than %dx%d (not %dx%d).\n",
594 progname, width, height, fwidth, fheight, w, h);
601 static unsigned char *
602 loadBitmap(int *w, int *h)
604 char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
608 !!strcmp(bitmap_name, "none"))
611 XpmInfo xpm_info = { 0, };
612 XpmImage xpm_image = { 0, };
614 int result = XpmReadFileToXpmImage (bitmap_name, &xpm_image, &xpm_info);
615 if (result == XpmSuccess)
618 unsigned char *result, *o;
619 unsigned char *grays;
620 XWindowAttributes xgwa;
622 *w = xpm_image.width;
623 *h = xpm_image.height;
624 result = (unsigned char *) malloc ((*w) * (*h));
627 fprintf(stderr, "%s: out of memory loading %s\n",
628 progname, bitmap_name);
632 XGetWindowAttributes (display, window, &xgwa);
634 grays = (unsigned char *) calloc (xpm_image.ncolors+1, 1);
635 for (x = 0; x < xpm_image.ncolors; x++)
638 XpmColor *xpmc = &xpm_image.colorTable[x];
640 if (xpmc->g_color && *xpmc->g_color)
641 cstring = xpmc->g_color;
642 else if (xpmc->g4_color && *xpmc->g4_color)
643 cstring = xpmc->g4_color;
644 else if (xpmc->c_color && *xpmc->c_color)
645 cstring = xpmc->c_color;
647 cstring = xpmc->m_color;
649 memset (&xc, 0, sizeof(xc));
652 !XParseColor (display, xgwa.colormap, cstring, &xc))
655 grays[x] = (int) (((xc.red * 0.299) +
662 for (y = 0; y < *h; y++)
663 for (x = 0; x < *w; x++)
665 int color = xpm_image.data[(y * (*w)) + x];
666 if (color < 0 || color > xpm_image.ncolors) abort();
671 else /* failed to read XPM -- fall through and try XBM */
672 #endif /* HAVE_XPM */
676 int width, height, xh, yh;
678 unsigned char *result, *o;
680 XmuLocateBitmapFile (DefaultScreenOfDisplay (display),
681 bitmap_name, 0, 0, &width, &height, &xh, &yh);
684 fprintf(stderr, "%s: unable to load bitmap file %s\n",
685 progname, bitmap_name);
688 ximage = XGetImage (display, bitmap, 0, 0, width, height,
690 XFreePixmap (display, bitmap);
692 if (ximage->depth != 1) abort();
696 result = (unsigned char *) malloc ((*w) * (*h));
699 fprintf(stderr, "%s: out of memory loading %s\n",
700 progname, bitmap_name);
705 for (y = 0; y < *h; y++)
706 for (x = 0; x < *w; x++)
707 *o++ = (XGetPixel(ximage, x, y) ? 255 : 0);
713 "%s: your vendor doesn't ship the standard Xmu library.\n",
715 fprintf (stderr, "\tWe can't load XBM files without it.\n");
729 char *progclass = "XFlame";
731 char *defaults [] = {
732 ".background: black",
733 ".foreground: #FFAF5F",
735 "*bitmapBaseline: 20",
744 #ifdef HAVE_XSHM_EXTENSION
745 "*useSHM: False", /* xshm turns out not to help. */
746 #endif /* HAVE_XSHM_EXTENSION */
750 XrmOptionDescRec options [] = {
751 { "-delay", ".delay", XrmoptionSepArg, 0 },
752 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
753 { "-baseline", ".bitmapBaseline", XrmoptionSepArg, 0 },
754 { "-hspread", ".hspread", XrmoptionSepArg, 0 },
755 { "-vspread", ".vspread", XrmoptionSepArg, 0 },
756 { "-residual", ".residual", XrmoptionSepArg, 0 },
757 { "-variance", ".variance", XrmoptionSepArg, 0 },
758 { "-vartrend", ".vartrend", XrmoptionSepArg, 0 },
759 { "-bloom", ".bloom", XrmoptionNoArg, "True" },
760 { "-no-bloom", ".bloom", XrmoptionNoArg, "False" },
761 #ifdef HAVE_XSHM_EXTENSION
762 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
763 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
764 #endif /* HAVE_XSHM_EXTENSION */
769 screenhack (Display *disp, Window win)
771 int theimx = 0, theimy = 0;
772 int baseline = get_integer_resource ("bitmapBaseline", "Integer");
773 int delay = get_integer_resource ("delay", "Integer");
780 theim = loadBitmap(&theimx, &theimy);
782 /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
783 makes it hard for us to react to window resizing. So, punt for now. The
784 size of the window at startup is the size it will stay.
797 FlamePasteData(theim, (fwidth - theimx) / 2,
798 fheight - theimy - baseline, theimx, theimy);
804 XSync(display,False);
805 screenhack_handle_events(display);