1 /* xscreensaver, Copyright (c) 1992, 1993, 1994 Jamie Zawinski <jwz@mcom.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 /* This file contains code for grabbing an image of the screen to hack its
13 bits. This is a little tricky, since doing this involves the need to tell
14 the difference between drawing on the actual root window, and on the fake
15 root window used by the screensaver, since at this level the illusion
25 #include <X11/Xatom.h>
26 #include <X11/Xutil.h>
29 MapNotify_event_p (dpy, event, window)
34 return (event->xany.type == MapNotify &&
35 event->xvisibility.window == (Window) window);
40 static Bool screensaver_window_p (Display *, Window);
44 screensaver_window_p (dpy, window)
50 unsigned long nitems, bytesafter;
52 if (XGetWindowProperty (dpy, window,
53 XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
54 0, 1, False, XA_STRING,
55 &type, &format, &nitems, &bytesafter,
56 (unsigned char **) &version)
64 grab_screen_image (dpy, window, root_p)
70 XWindowAttributes xgwa;
72 XGetWindowAttributes (dpy, window, &xgwa);
74 if (screensaver_window_p (dpy, window))
76 /* note: this assumes vroot.h didn't encapsulate the XRootWindowOfScreen
77 function, only the RootWindowOfScreen macro... */
78 Window real_root = XRootWindowOfScreen (DefaultScreenOfDisplay (dpy));
80 XSetWindowBackgroundPixmap (dpy, window, None);
82 /* prevent random viewer of the screen saver (locker) from messing
83 with windows. We don't check whether it succeeded, because what
84 are our options, really... */
85 XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
86 GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
87 XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
90 XUnmapWindow (dpy, window);
92 sleep (5); /* wait for everyone to swap in and handle exposes... */
93 XMapRaised (dpy, window);
95 XUngrabPointer (dpy, CurrentTime);
96 XUngrabKeyboard (dpy, CurrentTime);
104 gcv.function = GXcopy;
105 gcv.subwindow_mode = IncludeInferiors;
106 gc = XCreateGC (dpy, window, GCFunction | GCSubwindowMode, &gcv);
107 pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
108 XCopyArea (dpy, RootWindowOfScreen (xgwa.screen), pixmap, gc,
109 xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
111 XSetWindowBackgroundPixmap (dpy, window, pixmap);
116 XSetWindowBackgroundPixmap (dpy, window, None);
117 XMapWindow (dpy, window);
119 XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
126 /* When we are grabbing and manipulating a screen image, it's important that
127 we use the same colormap it originally had. So, if the screensaver was
128 started with -install, we need to copy the contents of the default colormap
129 into the screensaver's colormap.
132 copy_default_colormap_contents (dpy, to_cmap, to_visual)
137 Screen *screen = DefaultScreenOfDisplay (dpy);
138 Visual *from_visual = DefaultVisualOfScreen (screen);
139 Colormap from_cmap = XDefaultColormapOfScreen (screen);
141 XColor *old_colors, *new_colors;
142 unsigned long *pixels;
143 XVisualInfo vi_in, *vi_out;
145 int from_cells, to_cells, max_cells;
149 if (from_cmap == to_cmap)
152 vi_in.screen = XScreenNumberOfScreen (screen);
153 vi_in.visualid = XVisualIDFromVisual (from_visual);
154 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
156 if (! vi_out) abort ();
157 from_cells = vi_out [0].colormap_size;
158 XFree ((char *) vi_out);
160 vi_in.screen = XScreenNumberOfScreen (screen);
161 vi_in.visualid = XVisualIDFromVisual (to_visual);
162 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
164 if (! vi_out) abort ();
165 to_cells = vi_out [0].colormap_size;
166 XFree ((char *) vi_out);
168 max_cells = (from_cells > to_cells ? to_cells : from_cells);
170 old_colors = (XColor *) calloc (sizeof (XColor), max_cells);
171 new_colors = (XColor *) calloc (sizeof (XColor), max_cells);
172 pixels = (unsigned long *) calloc (sizeof (unsigned long), max_cells);
173 for (i = 0; i < max_cells; i++)
174 old_colors[i].pixel = i;
175 XQueryColors (dpy, from_cmap, old_colors, max_cells);
177 requested = max_cells;
178 while (requested > 0)
180 if (XAllocColorCells (dpy, to_cmap, False, 0, 0, pixels, requested))
182 /* Got all the pixels we asked for. */
183 for (i = 0; i < requested; i++)
184 new_colors[i] = old_colors [pixels[i]];
185 XStoreColors (dpy, to_cmap, new_colors, requested);
189 /* We didn't get all/any of the pixels we asked for. This time, ask
190 for half as many. (If we do get all that we ask for, we ask for
191 the same number again next time, so we only do O(log(n)) server
193 requested = requested / 2;