1 /* xflame, Copyright (c) 1996-2002 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>
57 #define countof(x) (sizeof((x))/sizeof((*x)))
59 #ifdef HAVE_XSHM_EXTENSION
61 #endif /* HAVE_XSHM_EXTENSION */
63 #include "images/bob.xbm"
67 static Display *display;
72 static Colormap colormap;
73 static Visual *visual;
74 static Screen *screen;
78 #ifdef HAVE_XSHM_EXTENSION
79 static XShmSegmentInfo shminfo;
80 #endif /* HAVE_XSHM_EXTENSION */
84 static unsigned char *flame;
85 static unsigned char *theim;
100 GetXInfo(Display *disp, Window win)
102 XWindowAttributes xwa;
104 XGetWindowAttributes(disp,win,&xwa);
108 colormap = xwa.colormap;
126 #ifdef HAVE_XSHM_EXTENSION
128 xim = create_xshm_image (display, visual, depth, ZPixmap, NULL,
129 &shminfo, width, height);
130 #else /* !HAVE_XSHM_EXTENSION */
132 #endif /* !HAVE_XSHM_EXTENSION */
137 xim = XCreateImage (display, visual, depth, ZPixmap, 0, NULL,
138 width, height, 32, 0);
140 xim->data = (char *) calloc(xim->height, xim->bytes_per_line);
141 if (!xim || !xim->data)
143 fprintf(stderr,"%s: out of memory.\n", progname);
148 gc = XCreateGC(display,window,0,&gcv);
156 int i = 0, j = 0, red = 0, green = 0, blue = 0;
159 /* Make it possible to set the color of the flames,
160 by Raymond Medeiros <ray@stommel.marine.usf.edu> and jwz.
162 fg.pixel = get_pixel_resource ("foreground", "Foreground",
164 XQueryColor (display, colormap, &fg);
166 red = 255 - (fg.red >> 8);
167 green = 255 - (fg.green >> 8);
168 blue = 255 - (fg.blue >> 8);
171 for (i = 0; i < 256 * 2; i += 2)
174 int r = (i - red) * 3;
175 int g = (i - green) * 3;
176 int b = (i - blue) * 3;
179 if (r > 255) r = 255;
181 if (g > 255) g = 255;
183 if (b > 255) b = 255;
185 xcl.red = (unsigned short)((r << 8) | r);
186 xcl.green = (unsigned short)((g << 8) | g);
187 xcl.blue = (unsigned short)((b << 8) | b);
188 xcl.flags = DoRed | DoGreen | DoBlue;
190 XAllocColor(display,colormap,&xcl);
192 ctab[j++] = (int)xcl.pixel;
200 #ifdef HAVE_XSHM_EXTENSION
202 XShmPutImage(display, window, gc, xim, 0,(top - 1) << 1, 0,
203 (top - 1) << 1, width, height - ((top - 1) << 1), False);
205 #endif /* HAVE_XSHM_EXTENSION */
206 XPutImage(display, window, gc, xim, 0, (top - 1) << 1, 0,
207 (top - 1) << 1, width, height - ((top - 1) << 1));
215 fheight = height / 2;
216 flame = (unsigned char *) malloc((fwidth + 2) * (fheight + 2)
217 * sizeof(unsigned char));
221 fprintf(stderr,"%s: out of memory\n", progname);
226 ihspread = get_integer_resource("hspread", "Integer");
227 ivspread = get_integer_resource("vspread", "Integer");
228 iresidual = get_integer_resource("residual", "Integer");
229 variance = get_integer_resource("variance", "Integer");
230 vartrend = get_integer_resource("vartrend", "Integer");
231 bloom = get_boolean_resource("bloom", "Boolean");
233 # define THROTTLE(VAR,NAME) \
234 if (VAR < 0 || VAR > 255) { \
235 fprintf(stderr, "%s: %s must be in the range 0-255 (not %d).\n", \
236 progname, NAME, VAR); \
238 THROTTLE (ihspread, "hspread");
239 THROTTLE (ivspread, "vspread");
240 THROTTLE (iresidual,"residual");
241 THROTTLE (variance, "variance");
242 THROTTLE (vartrend, "vartrend");
249 residual = iresidual;
261 ptr = (unsigned short *)xim->data;
262 ptr += (top << 1) * width;
263 ptr1 = flame + 1 + (top * (fwidth + 2));
265 for(y = top; y < fheight; y++)
267 for( x = 0; x < fwidth; x++)
270 v2 = (int)*(ptr1 + 1);
271 v3 = (int)*(ptr1 + fwidth + 2);
272 v4 = (int)*(ptr1 + fwidth + 2 + 1);
274 *ptr++ = (unsigned short)ctab[v1];
275 *ptr = (unsigned short)ctab[(v1 + v2) >> 1];
277 *ptr++ = (unsigned short)ctab[(v1 + v3) >> 1];
278 *ptr = (unsigned short)ctab[(v1 + v4) >> 1];
294 ptr = (unsigned int *)xim->data;
295 ptr += (top << 1) * width;
296 ptr1 = flame + 1 + (top * (fwidth + 2));
298 for( y = top; y < fheight; y++)
300 for( x = 0; x < fwidth; x++)
303 v2 = (int)*(ptr1 + 1);
304 v3 = (int)*(ptr1 + fwidth + 2);
305 v4 = (int)*(ptr1 + fwidth + 2 + 1);
307 *ptr++ = (unsigned int)ctab[v1];
308 *ptr = (unsigned int)ctab[(v1 + v2) >> 1];
310 *ptr++ = (unsigned int)ctab[(v1 + v3) >> 1];
311 *ptr = (unsigned int)ctab[(v1 + v4) >> 1];
327 ptr = (unsigned char *)xim->data;
328 ptr += (top << 1) * xim->bytes_per_line;
329 ptr1 = flame + 1 + (top * (fwidth + 2));
331 for( y = top; y < fheight; y++)
333 unsigned char *last_ptr = ptr;
334 for( x = 0; x < fwidth; x++)
337 v2 = (int)*(ptr1 + 1);
338 v3 = (int)*(ptr1 + fwidth + 2);
339 v4 = (int)*(ptr1 + fwidth + 2 + 1);
342 ptr[2] = ((unsigned int)ctab[v1] & 0x00FF0000) >> 16;
343 ptr[1] = ((unsigned int)ctab[v1] & 0x0000FF00) >> 8;
344 ptr[0] = ((unsigned int)ctab[v1] & 0x000000FF);
347 ptr[2] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x00FF0000) >> 16;
348 ptr[1] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x0000FF00) >> 8;
349 ptr[0] = ((unsigned int)ctab[(v1 + v2) >> 1] & 0x000000FF);
350 ptr += ((width - 1) * 3);
352 ptr[2] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x00FF0000) >> 16;
353 ptr[1] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x0000FF00) >> 8;
354 ptr[0] = ((unsigned int)ctab[(v1 + v3) >> 1] & 0x000000FF);
357 ptr[2] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x00FF0000) >> 16;
358 ptr[1] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x0000FF00) >> 8;
359 ptr[0] = ((unsigned int)ctab[(v1 + v4) >> 1] & 0x000000FF);
360 ptr -= ((width - 1) * 3);
363 ptr = last_ptr + (xim->bytes_per_line << 1);
376 ptr = (unsigned char *)xim->data;
377 ptr += (top << 1) * width;
378 ptr1 = flame + 1 + (top * (fwidth + 2));
380 for(y=top;y<fheight;y++)
382 for(x=0;x<fwidth;x++)
385 v2 = (int)*(ptr1 + 1);
386 v3 = (int)*(ptr1 + fwidth + 2);
387 v4 = (int)*(ptr1 + fwidth + 2 + 1);
389 *ptr++ = (unsigned char)ctab[v1];
390 *ptr = (unsigned char)ctab[(v1 + v2) >> 1];
392 *ptr++ = (unsigned char)ctab[(v1 + v3) >> 1];
393 *ptr = (unsigned char)ctab[(v1 + v4) >> 1];
402 Flame2Image1234567(void)
408 ptr1 = flame + 1 + (top * (fwidth + 2));
410 for( y = top; y < fheight; y++)
412 for( x = 0; x < fwidth; x++)
415 v2 = (int)*(ptr1 + 1);
416 v3 = (int)*(ptr1 + fwidth + 2);
417 v4 = (int)*(ptr1 + fwidth + 2 + 1);
419 XPutPixel(xim,(x << 1), (y << 1), ctab[v1]);
420 XPutPixel(xim,(x << 1) + 1,(y << 1), ctab[(v1 + v2) >> 1]);
421 XPutPixel(xim,(x << 1), (y << 1) + 1,ctab[(v1 + v3) >> 1]);
422 XPutPixel(xim,(x << 1) + 1,(y << 1) + 1,ctab[(v1 + v4) >> 1]);
430 switch (xim->bits_per_pixel)
432 case 32: Flame2Image32(); break;
433 case 24: Flame2Image24(); break;
434 case 16: Flame2Image16(); break;
435 case 8: Flame2Image8(); break;
437 if (xim->bits_per_pixel <= 7)
438 Flame2Image1234567();
452 ptr1 = flame + ((fheight + 1) * (fwidth + 2));
454 for (x = 0; x < fwidth + 2; x++)
457 v1 += ((random() % variance) - vartrend);
463 v1= (random() % 100);
465 residual += (random()%10);
467 hspread += (random()%15);
469 vspread += (random()%20);
472 residual = ((iresidual* 10) + (residual *90)) / 100;
473 hspread = ((ihspread * 10) + (hspread *90)) / 100;
474 vspread = ((ivspread * 10) + (vspread *90)) / 100;
485 for (y = fheight + 1; y >= top; y--)
488 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
489 for (x = 0; x < fwidth; x++)
496 ptr2 = ptr1 - fwidth - 2;
497 v3 = (v1 * vspread) >> 8;
503 *(ptr2) = (unsigned char)v2;
504 v3 = (v1 * hspread) >> 8;
505 v2 = (int)*(ptr2 + 1);
510 *(ptr2 + 1) = (unsigned char)v2;
511 v2 = (int)*(ptr2 - 1);
516 *(ptr2 - 1) = (unsigned char)v2;
520 v1 = (v1 * residual) >> 8;
521 *ptr1 = (unsigned char)v1;
529 /* clean up the right gutter */
532 v1 = (v1 * residual) >> 8;
533 *ptr1 = (unsigned char)v1;
548 for (y = 0; y < fheight + 1; y++)
550 unsigned char *ptr1 = flame + 1 + (y * (fwidth + 2));
551 for (x = 0; x < fwidth; x++)
561 FlamePasteData(unsigned char *d, int xx, int yy, int w, int h)
563 unsigned char *ptr1,*ptr2;
571 (xx + w <= fwidth) &&
575 for (y = 0; y < h; y++)
577 ptr1 = flame + 1 + xx + ((yy + y) * (fwidth + 2));
578 for (x = 0; x < w; x++)
581 *ptr1 += random() % (*ptr2 / 24);
590 static Bool warned = False;
593 fprintf (stderr, "%s: window is %dx%d; image must be "
594 "smaller than %dx%d (not %dx%d).\n",
595 progname, width, height, fwidth, fheight, w, h);
602 static unsigned char *
603 loadBitmap(int *w, int *h)
605 char *bitmap_name = get_string_resource ("bitmap", "Bitmap");
609 !strcmp(bitmap_name, "none"))
611 else if (!strcmp(bitmap_name, "(default)")) /* use the builtin */
614 unsigned char *result, *o;
615 char *bits = (char *) malloc (sizeof(bob_bits));
617 int scale = ((width > bob_width * 11) ? 2 : 1);
619 memcpy (bits, bob_bits, sizeof(bob_bits));
620 ximage = XCreateImage (display, visual, 1, XYBitmap, 0, bits,
621 bob_width, bob_height, 8, 0);
622 ximage->byte_order = LSBFirst;
623 ximage->bitmap_bit_order = LSBFirst;
624 *w = ximage->width * scale;
625 *h = ximage->height * scale;
626 o = result = (unsigned char *) malloc ((*w * scale) * (*h * scale));
627 for (y = 0; y < *h; y++)
628 for (x = 0; x < *w; x++)
629 *o++ = (XGetPixel(ximage, x/scale, y/scale) ? 255 : 0);
633 else /* load a bitmap file */
636 xpm_file_to_pixmap (display, window, bitmap_name, &width, &height, 0);
639 unsigned char *result, *o;
641 Bool cmap_p = has_writable_cells (screen, visual);
646 for (i = 0; i < countof (colors); i++)
648 XQueryColors (display, colormap, colors, countof (colors));
651 image = XGetImage (display, pixmap, 0, 0, width, height, ~0L, ZPixmap);
652 XFreePixmap(display, pixmap);
654 result = (unsigned char *) malloc (width * height);
656 for (y = 0; y < height; y++)
657 for (x = 0; x < width; x++)
659 int rgba = XGetPixel (image, x, y);
662 gray = ((200 - ((((colors[rgba].red >> 8) & 0xFF) +
663 ((colors[rgba].green >> 8) & 0xFF) +
664 ((colors[rgba].blue >> 8) & 0xFF))
668 /* This is *so* not handling all the cases... */
669 gray = (image->depth > 16
670 ? ((((rgba >> 24) & 0xFF) +
671 ((rgba >> 16) & 0xFF) +
672 ((rgba >> 8) & 0xFF) +
673 ((rgba ) & 0xFF)) >> 2)
674 : ((((rgba >> 12) & 0x0F) +
675 ((rgba >> 8) & 0x0F) +
676 ((rgba >> 4) & 0x0F) +
677 ((rgba ) & 0x0F)) >> 1));
684 XDestroyImage (image);
699 char *progclass = "XFlame";
701 char *defaults [] = {
702 ".background: black",
703 ".foreground: #FFAF5F",
704 "*bitmap: (default)",
705 "*bitmapBaseline: 20",
714 #ifdef HAVE_XSHM_EXTENSION
715 "*useSHM: False", /* xshm turns out not to help. */
716 #endif /* HAVE_XSHM_EXTENSION */
720 XrmOptionDescRec options [] = {
721 { "-foreground",".foreground", XrmoptionSepArg, 0 },
722 { "-fg", ".foreground", XrmoptionSepArg, 0 },
723 { "-delay", ".delay", XrmoptionSepArg, 0 },
724 { "-bitmap", ".bitmap", XrmoptionSepArg, 0 },
725 { "-baseline", ".bitmapBaseline", XrmoptionSepArg, 0 },
726 { "-hspread", ".hspread", XrmoptionSepArg, 0 },
727 { "-vspread", ".vspread", XrmoptionSepArg, 0 },
728 { "-residual", ".residual", XrmoptionSepArg, 0 },
729 { "-variance", ".variance", XrmoptionSepArg, 0 },
730 { "-vartrend", ".vartrend", XrmoptionSepArg, 0 },
731 { "-bloom", ".bloom", XrmoptionNoArg, "True" },
732 { "-no-bloom", ".bloom", XrmoptionNoArg, "False" },
733 #ifdef HAVE_XSHM_EXTENSION
734 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
735 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
736 #endif /* HAVE_XSHM_EXTENSION */
741 screenhack (Display *disp, Window win)
743 int theimx = 0, theimy = 0;
744 int baseline = get_integer_resource ("bitmapBaseline", "Integer");
745 int delay = get_integer_resource ("delay", "Integer");
752 theim = loadBitmap(&theimx, &theimy);
754 /* utils/xshm.c doesn't provide a way to free the shared-memory image, which
755 makes it hard for us to react to window resizing. So, punt for now. The
756 size of the window at startup is the size it will stay.
769 FlamePasteData(theim, (fwidth - theimx) / 2,
770 fheight - theimy - baseline, theimx, theimy);
776 XSync(display,False);
777 screenhack_handle_events(display);