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.)
43 * 16-Jan-2002, jwz: added gdk_pixbuf support.
48 /* portions by Daniel Zahn <stumpy@religions.com> */
51 #include "screenhack.h"
52 #include "xpm-pixmap.h"
53 #include <X11/Xutil.h>
56 #ifdef HAVE_XSHM_EXTENSION
58 #endif /* HAVE_XSHM_EXTENSION */
60 #include "images/bob.xbm"
64 static Display *display;
69 static Colormap colormap;
70 static Visual *visual;
74 #ifdef HAVE_XSHM_EXTENSION
75 static XShmSegmentInfo shminfo;
76 #endif /* HAVE_XSHM_EXTENSION */
80 static unsigned char *flame;
81 static unsigned char *theim;
96 GetXInfo(Display *disp, Window win)
98 XWindowAttributes xwa;
100 XGetWindowAttributes(disp,win,&xwa);
104 colormap = xwa.colormap;
121 #ifdef HAVE_XSHM_EXTENSION
123 xim = create_xshm_image (display, visual, depth, ZPixmap, NULL,
124 &shminfo, width, height);
125 #else /* !HAVE_XSHM_EXTENSION */
127 #endif /* !HAVE_XSHM_EXTENSION */
132 xim = XCreateImage (display, visual, depth, ZPixmap, 0, NULL,
133 width, height, 32, 0);
135 xim->data = (char *) calloc(xim->height, xim->bytes_per_line);
136 if (!xim || !xim->data)
138 fprintf(stderr,"%s: out of memory.\n", progname);
143 gc = XCreateGC(display,window,0,&gcv);
151 int i = 0, j = 0, red = 0, green = 0, blue = 0;
154 /* Make it possible to set the color of the flames,
155 by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
157 fg.pixel = get_pixel_resource ("foreground", "Foreground",
159 XQueryColor (display, colormap, &fg);
161 red = 255 - (fg.red >> 8);
162 green = 255 - (fg.green >> 8);
163 blue = 255 - (fg.blue >> 8);
166 for (i = 0; i < 256 * 2; i += 2)
169 int r = (i - red) * 3;
170 int g = (i - green) * 3;
171 int b = (i - blue) * 3;
174 if (r > 255) r = 255;
176 if (g > 255) g = 255;
178 if (b > 255) b = 255;
180 xcl.red = (unsigned short)((r << 8) | r);
181 xcl.green = (unsigned short)((g << 8) | g);
182 xcl.blue = (unsigned short)((b << 8) | b);
183 xcl.flags = DoRed | DoGreen | DoBlue;
185 XAllocColor(display,colormap,&xcl);
187 ctab[j++] = (int)xcl.pixel;
195 #ifdef HAVE_XSHM_EXTENSION
197 XShmPutImage(display, window, gc, xim, 0,(top - 1) << 1, 0,
198 (top - 1) << 1, width, height - ((top - 1) << 1), False);
200 #endif /* HAVE_XSHM_EXTENSION */
201 XPutImage(display, window, gc, xim, 0, (top - 1) << 1, 0,
202 (top - 1) << 1, width, height - ((top - 1) << 1));
210 fheight = height / 2;
211 flame = (unsigned char *) malloc((fwidth + 2) * (fheight + 2)
212 * sizeof(unsigned char));
216 fprintf(stderr,"%s: out of memory\n", progname);
221 ihspread = get_integer_resource("hspread", "Integer");
222 ivspread = get_integer_resource("vspread", "Integer");
223 iresidual = get_integer_resource("residual", "Integer");
224 variance = get_integer_resource("variance", "Integer");
225 vartrend = get_integer_resource("vartrend", "Integer");
226 bloom = get_boolean_resource("bloom", "Boolean");
228 # define THROTTLE(VAR,NAME) \
229 if (VAR < 0 || VAR > 255) { \
230 fprintf(stderr, "%s: %s must be in the range 0-255 (not %d).\n", \
231 progname, NAME, VAR); \
233 THROTTLE (ihspread, "hspread");
234 THROTTLE (ivspread, "vspread");
235 THROTTLE (iresidual,"residual");
236 THROTTLE (variance, "variance");
237 THROTTLE (vartrend, "vartrend");
244 residual = iresidual;
256 ptr = (unsigned short *)xim->data;
257 ptr += (top << 1) * width;
258 ptr1 = flame + 1 + (top * (fwidth + 2));
260 for(y = top; y < fheight; y++)
262 for( x = 0; x < fwidth; x++)
265 v2 = (int)*(ptr1 + 1);
266 v3 = (int)*(ptr1 + fwidth + 2);
267 v4 = (int)*(ptr1 + fwidth + 2 + 1);
269 *ptr++ = (unsigned short)ctab[v1];
270 *ptr = (unsigned short)ctab[(v1 + v2) >> 1];
272 *ptr++ = (unsigned short)ctab[(v1 + v3) >> 1];
273 *ptr = (unsigned short)ctab[(v1 + v4) >> 1];
289 ptr = (unsigned int *)xim->data;
290 ptr += (top << 1) * width;
291 ptr1 = flame + 1 + (top * (fwidth + 2));
293 for( y = top; y < fheight; y++)
295 for( x = 0; x < fwidth; x++)
298 v2 = (int)*(ptr1 + 1);
299 v3 = (int)*(ptr1 + fwidth + 2);
300 v4 = (int)*(ptr1 + fwidth + 2 + 1);
302 *ptr++ = (unsigned int)ctab[v1];
303 *ptr = (unsigned int)ctab[(v1 + v2) >> 1];
305 *ptr++ = (unsigned int)ctab[(v1 + v3) >> 1];
306 *ptr = (unsigned int)ctab[(v1 + v4) >> 1];
322 ptr = (unsigned char *)xim->data;
323 ptr += (top << 1) * xim->bytes_per_line;
324 ptr1 = flame + 1 + (top * (fwidth + 2));
326 for( y = top; y < fheight; y++)
328 unsigned char *last_ptr = ptr;
329 for( x = 0; x < fwidth; x++)
332 v2 = (int)*(ptr1 + 1);
333 v3 = (int)*(ptr1 + fwidth + 2);
334 v4 = (int)*(ptr1 + fwidth + 2 + 1);
337 ptr[2] = ((unsigned int)ctab[v1] & 0x00FF0000) >> 16;
338 ptr[1] = ((unsigned int)ctab[v1] & 0x0000FF00) >> 8;
339 ptr[0] = ((unsigned int)ctab[v1] & 0x000000FF);
342 ptr[2] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x00FF0000) >> 16;
343 ptr[1] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x0000FF00) >> 8;
344 ptr[0] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x000000FF);
345 ptr += ((width - 1) * 3);
347 ptr[2] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x00FF0000) >> 16;
348 ptr[1] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x0000FF00) >> 8;
349 ptr[0] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x000000FF);
352 ptr[2] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x00FF0000) >> 16;
353 ptr[1] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x0000FF00) >> 8;
354 ptr[0] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x000000FF);
355 ptr -= ((width - 1) * 3);
358 ptr = last_ptr + (xim->bytes_per_line << 1);
371 ptr = (unsigned char *)xim->data;
372 ptr += (top << 1) * width;
373 ptr1 = flame + 1 + (top * (fwidth + 2));
375 for(y=top;y<fheight;y++)
377 for(x=0;x<fwidth;x++)
380 v2 = (int)*(ptr1 + 1);
381 v3 = (int)*(ptr1 + fwidth + 2);
382 v4 = (int)*(ptr1 + fwidth + 2 + 1);
384 *ptr++ = (unsigned char)ctab[v1];
385 *ptr = (unsigned char)ctab[(v1 + v2) >> 1];
387 *ptr++ = (unsigned char)ctab[(v1 + v3) >> 1];
388 *ptr = (unsigned char)ctab[(v1 + v4) >> 1];
397 Flame2Image1234567(void)
403 ptr1 = flame + 1 + (top * (fwidth + 2));
405 for( y = top; y < fheight; y++)
407 for( x = 0; x < fwidth; x++)
410 v2 = (int)*(ptr1 + 1);
411 v3 = (int)*(ptr1 + fwidth + 2);
412 v4 = (int)*(ptr1 + fwidth + 2 + 1);
414 XPutPixel(xim,(x << 1), (y << 1), ctab[v1]);
415 XPutPixel(xim,(x << 1) + 1,(y << 1), ctab[(v1 + v2) >> 1]);
416 XPutPixel(xim,(x << 1), (y << 1) + 1,ctab[(v1 + v3) >> 1]);
417 XPutPixel(xim,(x << 1) + 1,(y << 1) + 1,ctab[(v1 + v4) >> 1]);
425 switch (xim->bits_per_pixel)
427 case 32: Flame2Image32(); break;
428 case 24: Flame2Image24(); break;
429 case 16: Flame2Image16(); break;
430 case 8: Flame2Image8(); break;
432 if (xim->bits_per_pixel <= 7)
433 Flame2Image1234567();
447 ptr1 = flame + ((fheight + 1) * (fwidth + 2));
449 for (x = 0; x < fwidth + 2; x++)
452 v1 += ((random() % variance) - vartrend);
458 v1= (random() % 100);
460 residual += (random()%10);
462 hspread += (random()%15);
464 vspread += (random()%20);
467 residual = ((iresidual* 10) + (residual *90)) / 100;
468 hspread = ((ihspread * 10) + (hspread *90)) / 100;
469 vspread = ((ivspread * 10) + (vspread *90)) / 100;
480 for (y = fheight + 1; y >= top; y--)
483 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
484 for (x = 0; x < fwidth; x++)
491 ptr2 = ptr1 - fwidth - 2;
492 v3 = (v1 * vspread) >> 8;
498 *(ptr2) = (unsigned char)v2;
499 v3 = (v1 * hspread) >> 8;
500 v2 = (int)*(ptr2 + 1);
505 *(ptr2 + 1) = (unsigned char)v2;
506 v2 = (int)*(ptr2 - 1);
511 *(ptr2 - 1) = (unsigned char)v2;
515 v1 = (v1 * residual) >> 8;
516 *ptr1 = (unsigned char)v1;
524 /* clean up the right gutter */
527 v1 = (v1 * residual) >> 8;
528 *ptr1 = (unsigned char)v1;
543 for (y = 0; y < fheight + 1; y++)
545 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
546 for (x = 0; x < fwidth; x++)
556 FlamePasteData(unsigned char *d, int xx, int yy, int w, int h)
558 unsigned char *ptr1,*ptr2;
566 (xx + w <= fwidth) &&
570 for (y = 0; y < h; y++)
572 ptr1 = flame + 1 + xx + ((yy + y) * (fwidth + 2));
573 for (x = 0; x < w; x++)
576 *ptr1 += random() % (*ptr2 / 24);
585 static Bool warned = False;
588 fprintf (stderr, "%s: window is %dx%d; image must be "
589 "smaller than %dx%d (not %dx%d).\n",
590 progname, width, height, fwidth, fheight, w, h);
597 static unsigned char *
598 loadBitmap(int *w, int *h)
600 char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
604 !strcmp(bitmap_name, "none"))
606 else if (!strcmp(bitmap_name, "(default)")) /* use the builtin */
609 unsigned char *result, *o;
610 char *bits = (char *) malloc (sizeof(bob_bits));
612 int scale = ((width > bob_width * 11) ? 2 : 1);
614 memcpy (bits, bob_bits, sizeof(bob_bits));
615 ximage = XCreateImage (display, visual, 1, XYBitmap, 0, bits,
616 bob_width, bob_height, 8, 0);
617 ximage->byte_order = LSBFirst;
618 ximage->bitmap_bit_order = LSBFirst;
619 *w = ximage->width * scale;
620 *h = ximage->height * scale;
621 o = result = (unsigned char *) malloc ((*w * scale) * (*h * scale));
622 for (y = 0; y < *h; y++)
623 for (x = 0; x < *w; x++)
624 *o++ = (XGetPixel(ximage, x/scale, y/scale) ? 255 : 0);
628 else /* load a bitmap file */
631 xpm_file_to_pixmap (display, window, bitmap_name, &width, &height, 0);
634 unsigned char *result, *o;
636 image = XGetImage (display, pixmap, 0, 0, width, height, ~0L, ZPixmap);
637 XFreePixmap(display, pixmap);
639 result = (unsigned char *) malloc (width * height);
641 for (y = 0; y < height; y++)
642 for (x = 0; x < width; x++)
644 int rgba = XGetPixel (image, x, y);
645 /* This is *so* not handling all the cases... */
646 int gray = (image->depth > 16
647 ? ((((rgba >> 24) & 0xFF) +
648 ((rgba >> 16) & 0xFF) +
649 ((rgba >> 8) & 0xFF) +
650 ((rgba ) & 0xFF)) >> 2)
651 : ((((rgba >> 12) & 0x0F) +
652 ((rgba >> 8) & 0x0F) +
653 ((rgba >> 4) & 0x0F) +
654 ((rgba ) & 0x0F)) >> 1));
660 XDestroyImage (image);
675 char *progclass = "XFlame";
677 char *defaults [] = {
678 ".background: black",
679 ".foreground: #FFAF5F",
680 "*bitmap: (default)",
681 "*bitmapBaseline: 20",
690 #ifdef HAVE_XSHM_EXTENSION
691 "*useSHM: False", /* xshm turns out not to help. */
692 #endif /* HAVE_XSHM_EXTENSION */
696 XrmOptionDescRec options [] = {
697 { "-delay", ".delay", XrmoptionSepArg, 0 },
698 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
699 { "-baseline", ".bitmapBaseline", XrmoptionSepArg, 0 },
700 { "-hspread", ".hspread", XrmoptionSepArg, 0 },
701 { "-vspread", ".vspread", XrmoptionSepArg, 0 },
702 { "-residual", ".residual", XrmoptionSepArg, 0 },
703 { "-variance", ".variance", XrmoptionSepArg, 0 },
704 { "-vartrend", ".vartrend", XrmoptionSepArg, 0 },
705 { "-bloom", ".bloom", XrmoptionNoArg, "True" },
706 { "-no-bloom", ".bloom", XrmoptionNoArg, "False" },
707 #ifdef HAVE_XSHM_EXTENSION
708 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
709 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
710 #endif /* HAVE_XSHM_EXTENSION */
715 screenhack (Display *disp, Window win)
717 int theimx = 0, theimy = 0;
718 int baseline = get_integer_resource ("bitmapBaseline", "Integer");
719 int delay = get_integer_resource ("delay", "Integer");
726 theim = loadBitmap(&theimx, &theimy);
728 /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
729 makes it hard for us to react to window resizing. So, punt for now. The
730 size of the window at startup is the size it will stay.
743 FlamePasteData(theim, (fwidth - theimx) / 2,
744 fheight - theimy - baseline, theimx, theimy);
750 XSync(display,False);
751 screenhack_handle_events(display);