http://se.aminet.net/pub/X11/ftp.x.org/contrib/vms/xscreensaver-124.zip
[xscreensaver] / utils / grabscreen.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994 Jamie Zawinski <jwz@mcom.com>
2  *
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 
9  * implied warranty.
10  */
11
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 
16    breaks down...
17  */
18
19 #if __STDC__
20 #include <stdlib.h>
21 #include <unistd.h>
22 #endif
23
24 #ifdef __DECC
25 typedef char * caddr_t;
26 #endif
27
28 #include <X11/Xlib.h>
29 #include <X11/Xatom.h>
30 #include <X11/Xutil.h>
31
32 static Bool
33 MapNotify_event_p (dpy, event, window)
34      Display *dpy;
35      XEvent *event;
36      XPointer window;
37 {
38   return (event->xany.type == MapNotify &&
39           event->xvisibility.window == (Window) window);
40 }
41
42
43 #if __STDC__
44 static Bool screensaver_window_p (Display *, Window);
45 #endif
46
47 static Bool
48 screensaver_window_p (dpy, window)
49      Display *dpy;
50      Window window;
51 {
52   Atom type;
53   int format;
54   unsigned long nitems, bytesafter;
55   char *version;
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)
61       == Success
62       && type != None)
63     return True;
64   return False;
65 }
66
67 Pixmap
68 grab_screen_image (dpy, window, root_p)
69      Display *dpy;
70      Window window;
71      int root_p;
72 {
73   Pixmap pixmap = 0;
74   XWindowAttributes xgwa;
75
76   XGetWindowAttributes (dpy, window, &xgwa);
77
78   if (screensaver_window_p (dpy, window))
79     {
80       /* note: this assumes vroot.h didn't encapsulate the XRootWindowOfScreen
81          function, only the RootWindowOfScreen macro... */
82       Window real_root = XRootWindowOfScreen (DefaultScreenOfDisplay (dpy));
83
84       XSetWindowBackgroundPixmap (dpy, window, None);
85
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,
92                      CurrentTime);
93
94       XUnmapWindow (dpy, window);
95       XSync (dpy, True);
96       sleep (5);     /* wait for everyone to swap in and handle exposes... */
97       XMapRaised (dpy, window);
98
99       XUngrabPointer (dpy, CurrentTime);
100       XUngrabKeyboard (dpy, CurrentTime);
101
102       XSync (dpy, True);
103     }
104   else if (root_p)
105     {
106       XGCValues gcv;
107       GC gc;
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);
114       XFreeGC (dpy, gc);
115       XSetWindowBackgroundPixmap (dpy, window, pixmap);
116     }
117   else
118     {
119       XEvent event;
120       XSetWindowBackgroundPixmap (dpy, window, None);
121       XMapWindow (dpy, window);
122       XFlush (dpy);
123       XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
124       XSync (dpy, True);
125     }
126   return pixmap;
127 }
128
129
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.
134  */
135 void
136 copy_default_colormap_contents (dpy, to_cmap, to_visual)
137      Display *dpy;
138      Colormap to_cmap;
139      Visual *to_visual;
140 {
141   Screen *screen = DefaultScreenOfDisplay (dpy);
142   Visual *from_visual = DefaultVisualOfScreen (screen);
143   Colormap from_cmap = XDefaultColormapOfScreen (screen);
144
145   XColor *old_colors, *new_colors;
146   unsigned long *pixels;
147   XVisualInfo vi_in, *vi_out;
148   int out_count;
149   int from_cells, to_cells, max_cells;
150   int requested;
151   int i;
152
153   if (from_cmap == to_cmap)
154     return;
155
156   vi_in.screen = XScreenNumberOfScreen (screen);
157   vi_in.visualid = XVisualIDFromVisual (from_visual);
158   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
159                            &vi_in, &out_count);
160   if (! vi_out) abort ();
161   from_cells = vi_out [0].colormap_size;
162   XFree ((char *) vi_out);
163
164   vi_in.screen = XScreenNumberOfScreen (screen);
165   vi_in.visualid = XVisualIDFromVisual (to_visual);
166   vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
167                            &vi_in, &out_count);
168   if (! vi_out) abort ();
169   to_cells = vi_out [0].colormap_size;
170   XFree ((char *) vi_out);
171
172   max_cells = (from_cells > to_cells ? to_cells : from_cells);
173
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);
180
181   requested = max_cells;
182   while (requested > 0)
183     {
184       if (XAllocColorCells (dpy, to_cmap, False, 0, 0, pixels, requested))
185         {
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);
190         }
191       else
192         {
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
196              roundtrips.) */
197           requested = requested / 2;
198         }
199     }
200
201   free (old_colors);
202   free (new_colors);
203   free (pixels);
204 }