1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998, 2003
2 * Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* This file contains code for grabbing an image of the screen to hack its
14 bits. This is a little tricky, since doing this involves the need to tell
15 the difference between drawing on the actual root window, and on the fake
16 root window used by the screensaver, since at this level the illusion
23 #include <X11/Xatom.h>
24 #include <X11/Xutil.h>
28 # include <X11/Xmu/WinUtil.h>
30 # include <Xmu/WinUtil.h>
36 #include "grabscreen.h"
38 #include "resources.h"
41 #undef RootWindowOfScreen
43 #undef DefaultRootWindow
46 #ifdef HAVE_READ_DISPLAY_EXTENSION
47 # include <X11/extensions/readdisplay.h>
48 static Bool read_display (Screen *, Window, Pixmap, Bool);
49 #endif /* HAVE_READ_DISPLAY_EXTENSION */
52 static void copy_default_colormap_contents (Screen *, Colormap, Visual *);
54 #ifdef HAVE_READ_DISPLAY_EXTENSION
55 static void allocate_cubic_colormap (Screen *, Window, Visual *);
56 void remap_image (Screen *, Window, Colormap, XImage *);
61 MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
63 return (event->xany.type == MapNotify &&
64 event->xvisibility.window == (Window) window);
67 extern char *progname;
68 Bool grab_verbose_p = False;
71 grabscreen_verbose(void)
73 grab_verbose_p = True;
78 raise_window(Display *dpy, Window window, Bool dont_wait)
81 fprintf(stderr, "%s: raising window 0x%08lX (%s)\n",
82 progname, (unsigned long) window,
83 (dont_wait ? "not waiting" : "waiting"));
87 XWindowAttributes xgwa;
90 memset(&hints, 0, sizeof(hints));
91 XGetWMNormalHints(dpy, window, &hints, &supplied);
92 XGetWindowAttributes (dpy, window, &xgwa);
95 hints.width = xgwa.width;
96 hints.height = xgwa.height;
97 hints.flags |= (PPosition|USPosition|PSize|USSize);
98 XSetWMNormalHints(dpy, window, &hints);
100 XSelectInput (dpy, window, (xgwa.your_event_mask | StructureNotifyMask));
103 XMapRaised(dpy, window);
108 XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
115 xscreensaver_window_p (Display *dpy, Window window)
119 unsigned long nitems, bytesafter;
121 if (XGetWindowProperty (dpy, window,
122 XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
123 0, 1, False, XA_STRING,
124 &type, &format, &nitems, &bytesafter,
125 (unsigned char **) &version)
134 /* Whether the given window is:
135 - the real root window;
136 - the virtual root window;
137 - a direct child of the root window;
138 - a direct child of the window manager's decorations.
141 top_level_window_p (Screen *screen, Window window)
143 Display *dpy = DisplayOfScreen (screen);
144 Window root, parent, *kids;
145 Window vroot = VirtualRootWindowOfScreen(screen);
151 if (!XQueryTree (dpy, window, &root, &parent, &kids, &nkids))
157 /* If our direct parent is the root (or *a* root), then yes. */
158 if (parent == root || parent == vroot)
164 unsigned long nitems, bytesafter;
167 /* If our direct parent has the WM_STATE property, then it is a
168 window manager decoration -- yes.
170 if (XGetWindowProperty (dpy, window,
171 XInternAtom (dpy, "WM_STATE", True),
172 0, 0, False, AnyPropertyType,
173 &type, &format, &nitems, &bytesafter,
174 (unsigned char **) &data)
180 /* Else, no. We're deep in a tree somewhere.
187 static Bool error_handler_hit_p = False;
188 static XErrorHandler old_ehandler = 0;
190 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
192 error_handler_hit_p = True;
193 if (error->error_code == BadWindow || error->error_code == BadDrawable)
195 else if (!old_ehandler)
201 return (*old_ehandler) (dpy, error);
205 /* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
206 on a window whose depth is not the maximal depth of the screen? Or
207 something. Anyway, things don't work unless we: use SubwindowMode for
208 the real root window (or a legitimate virtual root window); but do not
209 use SubwindowMode for the xscreensaver window. I make no attempt to
213 use_subwindow_mode_p(Screen *screen, Window window)
215 if (window != VirtualRootWindowOfScreen(screen))
217 else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
224 /* Install the colormaps of all visible windows, deepest first.
225 This should leave the colormaps of the topmost windows installed
226 (if only N colormaps can be installed at a time, then only the
227 topmost N windows will be shown in the right colors.)
230 install_screen_colormaps (Screen *screen)
233 Display *dpy = DisplayOfScreen (screen);
234 Window vroot, real_root;
235 Window parent, *kids = 0;
236 unsigned int nkids = 0;
239 old_ehandler = XSetErrorHandler (BadWindow_ehandler);
240 error_handler_hit_p = False;
242 vroot = VirtualRootWindowOfScreen (screen);
243 if (XQueryTree (dpy, vroot, &real_root, &parent, &kids, &nkids))
244 for (i = 0; i < nkids; i++)
246 XWindowAttributes xgwa;
249 /* #### need to put XmuClientWindow() in xmu.c, sigh... */
250 if (! (client = XmuClientWindow (dpy, kids[i])))
254 XGetWindowAttributes (dpy, client, &xgwa);
255 if (xgwa.colormap && xgwa.map_state == IsViewable)
256 XInstallColormap (dpy, xgwa.colormap);
258 XInstallColormap (dpy, DefaultColormapOfScreen (screen));
260 XSetErrorHandler (old_ehandler);
264 XFree ((char *) kids);
269 grab_screen_image (Screen *screen, Window window)
271 Display *dpy = DisplayOfScreen (screen);
272 XWindowAttributes xgwa;
276 Bool grab_mouse_p = False;
279 real_root = XRootWindowOfScreen (screen); /* not vroot */
280 root_p = (window == real_root);
281 saver_p = xscreensaver_window_p (dpy, window);
283 XGetWindowAttributes (dpy, window, &xgwa);
284 screen = xgwa.screen;
287 /* I think this is redundant, but just to be safe... */
291 /* The only time grabbing the mouse is important is if this program
292 is being run while the saver is locking the screen. */
300 unmap = get_float_resource("grabRootDelay", "Seconds");
301 if (unmap <= 0.00001 || unmap > 20) unmap = 2.5;
305 unmap = get_float_resource("grabWindowDelay", "Seconds");
306 if (unmap <= 0.00001 || unmap > 20) unmap = 0.66;
308 unmap_time = unmap * 100000;
314 "\n%s: window 0x%08lX root: %d saver: %d grab: %d wait: %.1f\n",
315 progname, (unsigned long) window,
316 root_p, saver_p, grab_mouse_p, ((double)unmap_time)/1000000.0);
318 fprintf(stderr, "%s: ", progname);
319 describe_visual(stderr, screen, xgwa.visual, False);
320 fprintf (stderr, "\n");
324 if (!root_p && !top_level_window_p (screen, window))
327 fprintf (stderr, "%s: not a top-level window: 0x%08lX: not grabbing\n",
328 progname, (unsigned long) window);
334 XSetWindowBackgroundPixmap (dpy, window, None);
338 /* prevent random viewer of the screen saver (locker) from messing
339 with windows. We don't check whether it succeeded, because what
340 are our options, really... */
341 XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
342 GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
343 XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
349 XUnmapWindow (dpy, window);
350 install_screen_colormaps (screen);
352 usleep(unmap_time); /* wait for everyone to swap in and handle exposes */
357 #ifdef HAVE_READ_DISPLAY_EXTENSION
358 if (! read_display(screen, window, 0, saver_p))
359 #endif /* HAVE_READ_DISPLAY_EXTENSION */
361 #ifdef HAVE_READ_DISPLAY_EXTENSION
363 fprintf(stderr, "%s: read_display() failed\n", progname);
364 #endif /* HAVE_READ_DISPLAY_EXTENSION */
366 copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
367 raise_window(dpy, window, saver_p);
369 /* Generally it's bad news to call XInstallColormap() explicitly,
370 but this file does a lot of sleazy stuff already... This is to
371 make sure that the window's colormap is installed, even in the
372 case where the window is OverrideRedirect. */
373 if (xgwa.colormap) XInstallColormap (dpy, xgwa.colormap);
380 pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
382 #ifdef HAVE_READ_DISPLAY_EXTENSION
383 if (! read_display(screen, window, pixmap, True))
386 Window real_root = XRootWindowOfScreen (screen); /* not vroot */
390 #ifdef HAVE_READ_DISPLAY_EXTENSION
392 fprintf(stderr, "%s: read_display() failed\n", progname);
393 #endif /* HAVE_READ_DISPLAY_EXTENSION */
395 copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
397 gcv.function = GXcopy;
398 gcv.subwindow_mode = IncludeInferiors;
399 gc = XCreateGC (dpy, window, GCFunction | GCSubwindowMode, &gcv);
400 XCopyArea (dpy, real_root, pixmap, gc,
401 xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
404 XSetWindowBackgroundPixmap (dpy, window, pixmap);
405 XFreePixmap (dpy, pixmap);
409 fprintf (stderr, "%s: grabbed %d bit screen image to %swindow.\n",
410 progname, xgwa.depth,
411 (root_p ? "real root " : ""));
415 XUngrabPointer (dpy, CurrentTime);
416 XUngrabKeyboard (dpy, CurrentTime);
423 /* When we are grabbing and manipulating a screen image, it's important that
424 we use the same colormap it originally had. So, if the screensaver was
425 started with -install, we need to copy the contents of the default colormap
426 into the screensaver's colormap.
429 copy_default_colormap_contents (Screen *screen,
433 Display *dpy = DisplayOfScreen (screen);
434 Visual *from_visual = DefaultVisualOfScreen (screen);
435 Colormap from_cmap = XDefaultColormapOfScreen (screen);
437 XColor *old_colors, *new_colors;
438 unsigned long *pixels;
439 XVisualInfo vi_in, *vi_out;
441 int from_cells, to_cells, max_cells, got_cells;
444 if (from_cmap == to_cmap)
447 vi_in.screen = XScreenNumberOfScreen (screen);
448 vi_in.visualid = XVisualIDFromVisual (from_visual);
449 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
451 if (! vi_out) abort ();
452 from_cells = vi_out [0].colormap_size;
453 XFree ((char *) vi_out);
455 vi_in.screen = XScreenNumberOfScreen (screen);
456 vi_in.visualid = XVisualIDFromVisual (to_visual);
457 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
459 if (! vi_out) abort ();
460 to_cells = vi_out [0].colormap_size;
461 XFree ((char *) vi_out);
463 max_cells = (from_cells > to_cells ? to_cells : from_cells);
465 old_colors = (XColor *) calloc (sizeof (XColor), max_cells);
466 new_colors = (XColor *) calloc (sizeof (XColor), max_cells);
467 pixels = (unsigned long *) calloc (sizeof (unsigned long), max_cells);
468 for (i = 0; i < max_cells; i++)
469 old_colors[i].pixel = i;
470 XQueryColors (dpy, from_cmap, old_colors, max_cells);
472 got_cells = max_cells;
473 allocate_writable_colors (dpy, to_cmap, pixels, &got_cells);
475 if (grab_verbose_p && got_cells != max_cells)
476 fprintf(stderr, "%s: got only %d of %d cells\n", progname,
477 got_cells, max_cells);
479 if (got_cells <= 0) /* we're screwed */
481 else if (got_cells == max_cells && /* we're golden */
482 from_cells == to_cells)
483 XStoreColors (dpy, to_cmap, old_colors, got_cells);
484 else /* try to cope... */
486 for (i = 0; i < got_cells; i++)
488 XColor *c = old_colors + i;
490 for (j = 0; j < got_cells; j++)
491 if (pixels[j] == c->pixel)
493 /* only store this color value if this is one of the pixels
494 we were able to allocate. */
495 XStoreColors (dpy, to_cmap, c, 1);
503 fprintf(stderr, "%s: installing copy of default colormap\n", progname);
512 /* The SGI ReadDisplay extension.
513 This extension lets you get back a 24-bit image of the screen, taking into
514 account the colors with which all windows are *currently* displayed, even
515 if those windows have different visuals. Without this extension, presence
516 of windows with different visuals or colormaps will result in technicolor
517 when one tries to grab the screen image.
520 #ifdef HAVE_READ_DISPLAY_EXTENSION
523 read_display (Screen *screen, Window window, Pixmap into_pixmap,
526 Display *dpy = DisplayOfScreen (screen);
527 XWindowAttributes xgwa;
528 int rd_event_base = 0;
529 int rd_error_base = 0;
530 unsigned long hints = 0;
535 Bool remap_p = False;
537 /* Check to see if the server supports the extension, and bug out if not.
539 if (! XReadDisplayQueryExtension (dpy, &rd_event_base, &rd_error_base))
542 fprintf(stderr, "%s: no XReadDisplay extension\n", progname);
546 /* If this isn't a visual we know how to handle, bug out. We handle:
547 = TrueColor in depths 8, 12, 15, 16, and 32;
548 = PseudoColor and DirectColor in depths 8 and 12.
550 XGetWindowAttributes(dpy, window, &xgwa);
551 class = visual_class (screen, xgwa.visual);
552 if (class == TrueColor)
554 if (xgwa.depth != 8 && xgwa.depth != 12 && xgwa.depth != 15 &&
555 xgwa.depth != 16 && xgwa.depth != 24 && xgwa.depth != 32)
558 fprintf(stderr, "%s: TrueColor depth %d unsupported\n",
559 progname, xgwa.depth);
563 else if (class == PseudoColor || class == DirectColor)
565 if (xgwa.depth != 8 && xgwa.depth != 12)
568 fprintf(stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
569 progname, xgwa.depth);
573 /* Allocate a TrueColor-like spread of colors for the image. */
578 /* Try and read the screen.
580 hints = (XRD_TRANSPARENT | XRD_READ_POINTER);
581 image = XReadDisplay (dpy, window, xgwa.x, xgwa.y, xgwa.width, xgwa.height,
586 fprintf(stderr, "%s: XReadDisplay() failed\n", progname);
592 fprintf(stderr, "%s: XReadDisplay() returned no data\n", progname);
593 XDestroyImage(image);
597 /* XReadDisplay tends to LIE about the depth of the image it read.
598 It is returning an XImage which has `depth' and `bits_per_pixel'
601 That is, on a 24-bit display, where all visuals claim depth 24, and
602 where XGetImage would return an XImage with depth 24, and where
603 XPutImage will get a BadMatch with images that are not depth 24,
604 XReadDisplay is returning images with depth 32! Fuckwits!
606 So if the visual is of depth 24, but the image came back as depth 32,
607 hack it to be 24 lest we get a BadMatch from XPutImage.
609 I wonder what happens on an 8-bit SGI... Probably it still returns
610 an image claiming depth 32? Certainly it can't be 8. So, let's just
613 if (image->depth == 32 /* && xgwa.depth == 24 */ )
616 /* If the visual of the window/pixmap into which we're going to draw is
617 less deep than the screen itself, then we need to convert the grabbed bits
618 to match the depth by clipping off the less significant bit-planes of each
621 if (image->depth > xgwa.depth)
624 /* We use the same image->data in both images -- that's ok, because
625 since we're reading from B and writing to A, and B uses more bytes
626 per pixel than A, the write pointer won't overrun the read pointer.
628 XImage *image2 = XCreateImage (dpy, xgwa.visual, xgwa.depth,
629 ZPixmap, 0, image->data,
630 xgwa.width, xgwa.height,
635 fprintf(stderr, "%s: out of memory?\n", progname);
640 fprintf(stderr, "%s: converting from depth %d to depth %d\n",
641 progname, image->depth, xgwa.depth);
643 for (y = 0; y < image->height; y++)
644 for (x = 0; x < image->width; x++)
646 /* #### really these shift values should be determined from the
647 mask values -- but that's a pain in the ass, and anyway,
648 this is an SGI-specific extension so hardcoding assumptions
649 about the SGI server's behavior isn't *too* heinous... */
650 unsigned long pixel = XGetPixel(image, x, y);
651 unsigned int r = (pixel & image->red_mask);
652 unsigned int g = (pixel & image->green_mask) >> 8;
653 unsigned int b = (pixel & image->blue_mask) >> 16;
656 pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
657 else if (xgwa.depth == 12)
658 pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
659 else if (xgwa.depth == 16 || xgwa.depth == 15)
660 /* Gah! I don't understand why these are in the other order. */
661 pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
665 XPutPixel(image2, x, y, pixel);
668 XDestroyImage(image);
674 allocate_cubic_colormap (screen, window, xgwa.visual);
675 remap_image (screen, window, xgwa.colormap, image);
678 /* Now actually put the bits into the window or pixmap -- note the design
679 bogosity of this extension, where we've been forced to take 24 bit data
680 from the server to the client, and then push it back from the client to
681 the server, *without alteration*. We should have just been able to tell
682 the server, "put a screen image in this drawable", instead of having to
683 go through the intermediate step of converting it to an Image. Geez.
684 (Assuming that the window is of screen depth; we happen to handle less
685 deep windows, but that's beside the point.)
687 gcv.function = GXcopy;
688 gc = XCreateGC (dpy, window, GCFunction, &gcv);
692 gcv.function = GXcopy;
693 gc = XCreateGC (dpy, into_pixmap, GCFunction, &gcv);
694 XPutImage (dpy, into_pixmap, gc, image, 0, 0, 0, 0,
695 xgwa.width, xgwa.height);
699 gcv.function = GXcopy;
700 gc = XCreateGC (dpy, window, GCFunction, &gcv);
702 /* Ok, now we'll be needing that window on the screen... */
703 raise_window(dpy, window, dont_wait);
705 /* Plop down the bits... */
706 XPutImage (dpy, window, gc, image, 0, 0, 0, 0, xgwa.width, xgwa.height);
715 XDestroyImage(image);
719 #endif /* HAVE_READ_DISPLAY_EXTENSION */
722 #ifdef HAVE_READ_DISPLAY_EXTENSION
724 /* Makes and installs a colormap that makes a PseudoColor or DirectColor
725 visual behave like a TrueColor visual of the same depth.
728 allocate_cubic_colormap (Screen *screen, Window window, Visual *visual)
730 Display *dpy = DisplayOfScreen (screen);
731 XWindowAttributes xgwa;
733 int nr, ng, nb, cells;
739 XGetWindowAttributes (dpy, window, &xgwa);
740 cmap = xgwa.colormap;
741 depth = visual_depth(screen, visual);
745 case 8: nr = 3; ng = 3; nb = 2; cells = 256; break;
746 case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
747 default: abort(); break;
750 memset(colors, 0, sizeof(colors));
751 for (r = 0; r < (1 << nr); r++)
752 for (g = 0; g < (1 << ng); g++)
753 for (b = 0; b < (1 << nb); b++)
755 i = (r | (g << nr) | (b << (nr + ng)));
757 colors[i].flags = DoRed|DoGreen|DoBlue;
760 colors[i].red = ((r << 13) | (r << 10) | (r << 7) |
761 (r << 4) | (r << 1));
762 colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
763 (g << 4) | (g << 1));
764 colors[i].blue = ((b << 14) | (b << 12) | (b << 10) |
765 (b << 8) | (b << 6) | (b << 4) |
770 colors[i].red = (r << 12) | (r << 8) | (r << 4) | r;
771 colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
772 colors[i].blue = (b << 12) | (b << 8) | (b << 4) | b;
779 int interleave = cells / 8; /* skip around, rather than allocating in
780 order, so that we get better coverage if
781 we can't allocated all of them. */
782 for (j = 0; j < interleave; j++)
783 for (i = 0; i < cells; i += interleave)
784 if (XAllocColor (dpy, cmap, &colors[i + j]))
788 fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
789 progname, allocated, cells);
794 find_closest_pixel (XColor *colors, int ncolors,
795 unsigned long r, unsigned long g, unsigned long b)
797 unsigned long distance = ~0;
802 for (i = 0; i < ncolors; i++)
807 rd = r - colors[i].red;
808 gd = g - colors[i].green;
809 bd = b - colors[i].blue;
810 if (rd < 0) rd = -rd;
811 if (gd < 0) gd = -gd;
812 if (bd < 0) bd = -bd;
813 d = (rd << 1) + (gd << 2) + bd;
829 remap_image (Screen *screen, Window window, Colormap cmap, XImage *image)
831 Display *dpy = DisplayOfScreen (screen);
832 unsigned long map[4097];
837 if (image->depth == 8)
839 else if (image->depth == 12)
844 memset(map, -1, sizeof(*map));
845 memset(colors, -1, sizeof(*colors));
847 for (i = 0; i < cells; i++)
849 XQueryColors (dpy, cmap, colors, cells);
852 fprintf(stderr, "%s: building table for %d bit image\n",
853 progname, image->depth);
855 for (i = 0; i < cells; i++)
857 unsigned short r, g, b;
861 /* "RRR GGG BB" In an 8 bit map. Convert that to
862 "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
868 r = ((r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1));
869 g = ((g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1));
870 b = ((b << 14) | (b << 12) | (b << 10) | (b << 8) |
871 (b << 6) | (b << 4) | (b << 2) | b);
875 /* "RRRR GGGG BBBB" In a 12 bit map. Convert that to
876 "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
879 g = (i & 0x0F0) >> 4;
880 b = (i & 0xF00) >> 8;
882 r = (r << 12) | (r << 8) | (r << 4) | r;
883 g = (g << 12) | (g << 8) | (g << 4) | g;
884 b = (b << 12) | (b << 8) | (b << 4) | b;
887 map[i] = find_closest_pixel (colors, cells, r, g, b);
891 fprintf(stderr, "%s: remapping colors in %d bit image\n",
892 progname, image->depth);
894 for (y = 0; y < image->height; y++)
895 for (x = 0; x < image->width; x++)
897 unsigned long pixel = XGetPixel(image, x, y);
898 if (pixel >= cells) abort();
899 XPutPixel(image, x, y, map[pixel]);
904 #endif /* HAVE_READ_DISPLAY_EXTENSION */