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.
44 /* portions by Daniel Zahn <stumpy@religions.com> */
47 #include "screenhack.h"
48 #include <X11/Xutil.h>
51 #ifdef HAVE_XSHM_EXTENSION
53 #endif /* HAVE_XSHM_EXTENSION */
57 # ifndef PIXEL_ALREADY_TYPEDEFED
58 # define PIXEL_ALREADY_TYPEDEFED /* Sigh, Xmu/Drawing.h needs this... */
64 # include <X11/Xmu/Drawing.h>
66 # include <Xmu/Drawing.h>
72 static Display *display;
77 static Colormap colormap;
78 static Visual *visual;
82 #ifdef HAVE_XSHM_EXTENSION
83 static XShmSegmentInfo shminfo;
84 #endif /* HAVE_XSHM_EXTENSION */
88 static unsigned char *flame;
89 static unsigned char *theim;
104 GetXInfo(Display *disp, Window win)
106 XWindowAttributes xwa;
108 XGetWindowAttributes(disp,win,&xwa);
112 colormap = xwa.colormap;
129 #ifdef HAVE_XSHM_EXTENSION
131 xim = create_xshm_image (display, visual, depth, ZPixmap, NULL,
132 &shminfo, width, height);
133 #else /* !HAVE_XSHM_EXTENSION */
135 #endif /* !HAVE_XSHM_EXTENSION */
140 xim = XCreateImage (display, visual, depth, ZPixmap, 0, NULL,
141 width, height, 32, 0);
143 xim->data = (char *) calloc(xim->height, xim->bytes_per_line);
144 if (!xim || !xim->data)
146 fprintf(stderr,"%s: out of memory.\n", progname);
151 gc = XCreateGC(display,window,0,&gcv);
159 int i = 0, j = 0, red = 0, green = 0, blue = 0;
162 /* Make it possible to set the color of the flames,
163 by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
165 fg.pixel = get_pixel_resource ("foreground", "Foreground",
167 XQueryColor (display, colormap, &fg);
169 red = 255 - (fg.red >> 8);
170 green = 255 - (fg.green >> 8);
171 blue = 255 - (fg.blue >> 8);
174 for (i = 0; i < 256 * 2; i += 2)
177 int r = (i - red) * 3;
178 int g = (i - green) * 3;
179 int b = (i - blue) * 3;
182 if (r > 255) r = 255;
184 if (g > 255) g = 255;
186 if (b > 255) b = 255;
188 xcl.red = (unsigned short)((r << 8) | r);
189 xcl.green = (unsigned short)((g << 8) | g);
190 xcl.blue = (unsigned short)((b << 8) | b);
191 xcl.flags = DoRed | DoGreen | DoBlue;
193 XAllocColor(display,colormap,&xcl);
195 ctab[j++] = (int)xcl.pixel;
203 #ifdef HAVE_XSHM_EXTENSION
205 XShmPutImage(display, window, gc, xim, 0,(top - 1) << 1, 0,
206 (top - 1) << 1, width, height - ((top - 1) << 1), False);
208 #endif /* HAVE_XSHM_EXTENSION */
209 XPutImage(display, window, gc, xim, 0, (top - 1) << 1, 0,
210 (top - 1) << 1, width, height - ((top - 1) << 1));
218 fheight = height / 2;
219 flame = (unsigned char *) malloc((fwidth + 2) * (fheight + 2)
220 * sizeof(unsigned char));
224 fprintf(stderr,"%s: out of memory\n", progname);
229 ihspread = get_integer_resource("hspread", "Integer");
230 ivspread = get_integer_resource("vspread", "Integer");
231 iresidual = get_integer_resource("residual", "Integer");
232 variance = get_integer_resource("variance", "Integer");
233 vartrend = get_integer_resource("vartrend", "Integer");
234 bloom = get_boolean_resource("bloom", "Boolean");
236 # define THROTTLE(VAR,NAME) \
237 if (VAR < 0 || VAR > 255) { \
238 fprintf(stderr, "%s: %s must be in the range 0-255 (not %d).\n", \
239 progname, NAME, VAR); \
241 THROTTLE (ihspread, "hspread");
242 THROTTLE (ivspread, "vspread");
243 THROTTLE (iresidual,"residual");
244 THROTTLE (variance, "variance");
245 THROTTLE (vartrend, "vartrend");
252 residual = iresidual;
264 ptr = (unsigned short *)xim->data;
265 ptr += (top << 1) * width;
266 ptr1 = flame + 1 + (top * (fwidth + 2));
268 for(y = top; y < fheight; y++)
270 for( x = 0; x < fwidth; x++)
273 v2 = (int)*(ptr1 + 1);
274 v3 = (int)*(ptr1 + fwidth + 2);
275 v4 = (int)*(ptr1 + fwidth + 2 + 1);
277 *ptr++ = (unsigned short)ctab[v1];
278 *ptr = (unsigned short)ctab[(v1 + v2) >> 1];
280 *ptr++ = (unsigned short)ctab[(v1 + v3) >> 1];
281 *ptr = (unsigned short)ctab[(v1 + v4) >> 1];
297 ptr = (unsigned int *)xim->data;
298 ptr += (top << 1) * width;
299 ptr1 = flame + 1 + (top * (fwidth + 2));
301 for( y = top; y < fheight; y++)
303 for( x = 0; x < fwidth; x++)
306 v2 = (int)*(ptr1 + 1);
307 v3 = (int)*(ptr1 + fwidth + 2);
308 v4 = (int)*(ptr1 + fwidth + 2 + 1);
310 *ptr++ = (unsigned int)ctab[v1];
311 *ptr = (unsigned int)ctab[(v1 + v2) >> 1];
313 *ptr++ = (unsigned int)ctab[(v1 + v3) >> 1];
314 *ptr = (unsigned int)ctab[(v1 + v4) >> 1];
330 ptr = (unsigned char *)xim->data;
331 ptr += (top << 1) * width;
332 ptr1 = flame + 1 + (top * (fwidth + 2));
334 for(y=top;y<fheight;y++)
336 for(x=0;x<fwidth;x++)
339 v2 = (int)*(ptr1 + 1);
340 v3 = (int)*(ptr1 + fwidth + 2);
341 v4 = (int)*(ptr1 + fwidth + 2 + 1);
343 *ptr++ = (unsigned char)ctab[v1];
344 *ptr = (unsigned char)ctab[(v1 + v2) >> 1];
346 *ptr++ = (unsigned char)ctab[(v1 + v3) >> 1];
347 *ptr = (unsigned char)ctab[(v1 + v4) >> 1];
356 Flame2Image1234567(void)
362 ptr1 = flame + 1 + (top * (fwidth + 2));
364 for( y = top; y < fheight; y++)
366 for( x = 0; x < fwidth; x++)
369 v2 = (int)*(ptr1 + 1);
370 v3 = (int)*(ptr1 + fwidth + 2);
371 v4 = (int)*(ptr1 + fwidth + 2 + 1);
373 XPutPixel(xim,(x << 1), (y << 1), ctab[v1]);
374 XPutPixel(xim,(x << 1) + 1,(y << 1), ctab[(v1 + v2) >> 1]);
375 XPutPixel(xim,(x << 1), (y << 1) + 1,ctab[(v1 + v3) >> 1]);
376 XPutPixel(xim,(x << 1) + 1,(y << 1) + 1,ctab[(v1 + v4) >> 1]);
384 if (depth >= 24) Flame2Image32();
385 else if (depth == 16) Flame2Image16();
386 else if (depth == 8) Flame2Image8();
387 else if (depth == 15) Flame2Image16();
388 else if (depth < 8) Flame2Image1234567();
389 else if (depth == 12) Flame2Image16();
398 ptr1 = flame + ((fheight + 1) * (fwidth + 2));
400 for (x = 0; x < fwidth + 2; x++)
403 v1 += ((random() % variance) - vartrend);
409 v1= (random() % 100);
411 residual += (random()%10);
413 hspread += (random()%15);
415 vspread += (random()%20);
418 residual = ((iresidual* 10) + (residual *90)) / 100;
419 hspread = ((ihspread * 10) + (hspread *90)) / 100;
420 vspread = ((ivspread * 10) + (vspread *90)) / 100;
431 for (y = fheight + 1; y >= top; y--)
434 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
435 for (x = 0; x < fwidth; x++)
442 ptr2 = ptr1 - fwidth - 2;
443 v3 = (v1 * vspread) >> 8;
449 *(ptr2) = (unsigned char)v2;
450 v3 = (v1 * hspread) >> 8;
451 v2 = (int)*(ptr2 + 1);
456 *(ptr2 + 1) = (unsigned char)v2;
457 v2 = (int)*(ptr2 - 1);
462 *(ptr2 - 1) = (unsigned char)v2;
466 v1 = (v1 * residual) >> 8;
467 *ptr1 = (unsigned char)v1;
487 for (y = 0; y < fheight + 1; y++)
489 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
490 for (x = 0; x < fwidth; x++)
500 FlamePasteData(unsigned char *d, int xx, int yy, int w, int h)
502 unsigned char *ptr1,*ptr2;
510 (xx + w <= fwidth) &&
514 for (y = 0; y < h; y++)
516 ptr1 = flame + 1 + xx + ((yy + y) * (fwidth + 2));
517 for (x = 0; x < w; x++)
520 *ptr1 += random() % (*ptr2 / 24);
529 static Bool warned = False;
532 fprintf (stderr, "%s: window is %dx%d; image must be "
533 "smaller than %dx%d (not %dx%d).\n",
534 progname, width, height, fwidth, fheight, w, h);
541 static unsigned char *
542 loadBitmap(int *w, int *h)
544 char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
548 !!strcmp(bitmap_name, "none"))
551 XpmInfo xpm_info = { 0, };
552 XpmImage xpm_image = { 0, };
554 int result = XpmReadFileToXpmImage (bitmap_name, &xpm_image, &xpm_info);
555 if (result == XpmSuccess)
558 unsigned char *result, *o;
559 unsigned char *grays;
560 XWindowAttributes xgwa;
562 *w = xpm_image.width;
563 *h = xpm_image.height;
564 result = (unsigned char *) malloc ((*w) * (*h));
567 fprintf(stderr, "%s: out of memory loading %s\n",
568 progname, bitmap_name);
572 XGetWindowAttributes (display, window, &xgwa);
574 grays = (unsigned char *) calloc (xpm_image.ncolors+1, 1);
575 for (x = 0; x < xpm_image.ncolors; x++)
578 XpmColor *xpmc = &xpm_image.colorTable[x];
580 if (xpmc->g_color && *xpmc->g_color)
581 cstring = xpmc->g_color;
582 else if (xpmc->g4_color && *xpmc->g4_color)
583 cstring = xpmc->g4_color;
584 else if (xpmc->c_color && *xpmc->c_color)
585 cstring = xpmc->c_color;
587 cstring = xpmc->m_color;
589 memset (&xc, 0, sizeof(xc));
592 !XParseColor (display, xgwa.colormap, cstring, &xc))
595 grays[x] = (int) (((xc.red * 0.299) +
602 for (y = 0; y < *h; y++)
603 for (x = 0; x < *w; x++)
605 int color = xpm_image.data[(y * (*w)) + x];
606 if (color < 0 || color > xpm_image.ncolors) abort();
611 else /* failed to read XPM -- fall through and try XBM */
612 #endif /* HAVE_XPM */
616 int width, height, xh, yh;
618 unsigned char *result, *o;
620 XmuLocateBitmapFile (DefaultScreenOfDisplay (display),
621 bitmap_name, 0, 0, &width, &height, &xh, &yh);
624 fprintf(stderr, "%s: unable to load bitmap file %s\n",
625 progname, bitmap_name);
628 ximage = XGetImage (display, bitmap, 0, 0, width, height,
630 XFreePixmap (display, bitmap);
632 if (ximage->depth != 1) abort();
636 result = (unsigned char *) malloc ((*w) * (*h));
639 fprintf(stderr, "%s: out of memory loading %s\n",
640 progname, bitmap_name);
645 for (y = 0; y < *h; y++)
646 for (x = 0; x < *w; x++)
647 *o++ = (XGetPixel(ximage, x, y) ? 255 : 0);
653 "%s: your vendor doesn't ship the standard Xmu library.\n",
655 fprintf (stderr, "\tWe can't load XBM files without it.\n");
669 char *progclass = "XFlame";
671 char *defaults [] = {
672 ".background: black",
673 ".foreground: #FFAF5F",
675 "*bitmapBaseline: 20",
684 #ifdef HAVE_XSHM_EXTENSION
685 "*useSHM: False", /* xshm turns out not to help. */
686 #endif /* HAVE_XSHM_EXTENSION */
690 XrmOptionDescRec options [] = {
691 { "-delay", ".delay", XrmoptionSepArg, 0 },
692 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
693 { "-baseline", ".bitmapBaseline", XrmoptionSepArg, 0 },
694 { "-hspread", ".hspread", XrmoptionSepArg, 0 },
695 { "-vspread", ".vspread", XrmoptionSepArg, 0 },
696 { "-residual", ".residual", XrmoptionSepArg, 0 },
697 { "-variance", ".variance", XrmoptionSepArg, 0 },
698 { "-vartrend", ".vartrend", XrmoptionSepArg, 0 },
699 { "-bloom", ".bloom", XrmoptionNoArg, "True" },
700 { "-no-bloom", ".bloom", XrmoptionNoArg, "False" },
701 #ifdef HAVE_XSHM_EXTENSION
702 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
703 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
704 #endif /* HAVE_XSHM_EXTENSION */
709 screenhack (Display *disp, Window win)
711 int theimx = 0, theimy = 0;
712 int baseline = get_integer_resource ("bitmapBaseline", "Integer");
713 int delay = get_integer_resource ("delay", "Integer");
720 theim = loadBitmap(&theimx, &theimy);
722 /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
723 makes it hard for us to react to window resizing. So, punt for now. The
724 size of the window at startup is the size it will stay.
737 FlamePasteData(theim, (fwidth - theimx) / 2,
738 fheight - theimy - baseline, theimx, theimy);
744 XSync(display,False);
745 screenhack_handle_events(display);