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 typedef char * caddr_t;
29 #include <X11/Xatom.h>
30 #include <X11/Xutil.h>
33 MapNotify_event_p (dpy, event, window)
38 return (event->xany.type == MapNotify &&
39 event->xvisibility.window == (Window) window);
44 static Bool screensaver_window_p (Display *, Window);
48 screensaver_window_p (dpy, window)
54 unsigned long nitems, bytesafter;
56 if (XGetWindowProperty (dpy, window,
57 XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
58 0, 1, False, XA_STRING,
59 &type, &format, &nitems, &bytesafter,
60 (unsigned char **) &version)
68 grab_screen_image (dpy, window, root_p)
74 XWindowAttributes xgwa;
76 XGetWindowAttributes (dpy, window, &xgwa);
78 if (screensaver_window_p (dpy, window))
80 /* note: this assumes vroot.h didn't encapsulate the XRootWindowOfScreen
81 function, only the RootWindowOfScreen macro... */
82 Window real_root = XRootWindowOfScreen (DefaultScreenOfDisplay (dpy));
84 XSetWindowBackgroundPixmap (dpy, window, None);
86 /* prevent random viewer of the screen saver (locker) from messing
87 with windows. We don't check whether it succeeded, because what
88 are our options, really... */
89 XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
90 GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
91 XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
94 XUnmapWindow (dpy, window);
96 sleep (5); /* wait for everyone to swap in and handle exposes... */
97 XMapRaised (dpy, window);
99 XUngrabPointer (dpy, CurrentTime);
100 XUngrabKeyboard (dpy, CurrentTime);
108 gcv.function = GXcopy;
109 gcv.subwindow_mode = IncludeInferiors;
110 gc = XCreateGC (dpy, window, GCFunction | GCSubwindowMode, &gcv);
111 pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
112 XCopyArea (dpy, RootWindowOfScreen (xgwa.screen), pixmap, gc,
113 xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
115 XSetWindowBackgroundPixmap (dpy, window, pixmap);
120 XSetWindowBackgroundPixmap (dpy, window, None);
121 XMapWindow (dpy, window);
123 XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
130 /* When we are grabbing and manipulating a screen image, it's important that
131 we use the same colormap it originally had. So, if the screensaver was
132 started with -install, we need to copy the contents of the default colormap
133 into the screensaver's colormap.
136 copy_default_colormap_contents (dpy, to_cmap, to_visual)
141 Screen *screen = DefaultScreenOfDisplay (dpy);
142 Visual *from_visual = DefaultVisualOfScreen (screen);
143 Colormap from_cmap = XDefaultColormapOfScreen (screen);
145 XColor *old_colors, *new_colors;
146 unsigned long *pixels;
147 XVisualInfo vi_in, *vi_out;
149 int from_cells, to_cells, max_cells;
153 if (from_cmap == to_cmap)
156 vi_in.screen = XScreenNumberOfScreen (screen);
157 vi_in.visualid = XVisualIDFromVisual (from_visual);
158 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
160 if (! vi_out) abort ();
161 from_cells = vi_out [0].colormap_size;
162 XFree ((char *) vi_out);
164 vi_in.screen = XScreenNumberOfScreen (screen);
165 vi_in.visualid = XVisualIDFromVisual (to_visual);
166 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
168 if (! vi_out) abort ();
169 to_cells = vi_out [0].colormap_size;
170 XFree ((char *) vi_out);
172 max_cells = (from_cells > to_cells ? to_cells : from_cells);
174 old_colors = (XColor *) calloc (sizeof (XColor), max_cells);
175 new_colors = (XColor *) calloc (sizeof (XColor), max_cells);
176 pixels = (unsigned long *) calloc (sizeof (unsigned long), max_cells);
177 for (i = 0; i < max_cells; i++)
178 old_colors[i].pixel = i;
179 XQueryColors (dpy, from_cmap, old_colors, max_cells);
181 requested = max_cells;
182 while (requested > 0)
184 if (XAllocColorCells (dpy, to_cmap, False, 0, 0, pixels, requested))
186 /* Got all the pixels we asked for. */
187 for (i = 0; i < requested; i++)
188 new_colors[i] = old_colors [pixels[i]];
189 XStoreColors (dpy, to_cmap, new_colors, requested);
193 /* We didn't get all/any of the pixels we asked for. This time, ask
194 for half as many. (If we do get all that we ask for, we ask for
195 the same number again next time, so we only do O(log(n)) server
197 requested = requested / 2;