http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.00.tar.gz
[xscreensaver] / utils / grabclient.c
1 /* xscreensaver, Copyright (c) 1992, 1993, 1994, 1997, 1998, 2001
2  *  Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 /* This file contains code for running an external program to grab an image
14    onto the given window.  The external program in question must take a
15    window ID as its argument, e.g., the "xscreensaver-getimage" program
16    in the hacks/ directory.
17
18    That program links against utils/grabimage.c, which happens to export the
19    same API as this program (utils/grabclient.c).
20  */
21
22 #include "utils.h"
23 #include "grabscreen.h"
24 #include "resources.h"
25
26 #include "vroot.h"
27 #include <X11/Xatom.h>
28
29 extern char *progname;
30
31
32 static Bool
33 xscreensaver_window_p (Display *dpy, Window window)
34 {
35   Atom type;
36   int format;
37   unsigned long nitems, bytesafter;
38   char *version;
39   if (XGetWindowProperty (dpy, window,
40                           XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
41                           0, 1, False, XA_STRING,
42                           &type, &format, &nitems, &bytesafter,
43                           (unsigned char **) &version)
44       == Success
45       && type != None)
46     return True;
47   return False;
48 }
49
50
51 /* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
52    on a window whose depth is not the maximal depth of the screen?  Or
53    something.  Anyway, things don't work unless we: use SubwindowMode for
54    the real root window (or a legitimate virtual root window); but do not
55    use SubwindowMode for the xscreensaver window.  I make no attempt to
56    explain.
57  */
58 Bool
59 use_subwindow_mode_p(Screen *screen, Window window)
60 {
61   if (window != VirtualRootWindowOfScreen(screen))
62     return False;
63   else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
64     return False;
65   else
66     return True;
67 }
68
69
70 static void
71 checkerboard (Screen *screen, Window window)
72 {
73   Display *dpy = DisplayOfScreen (screen);
74   int x, y;
75   int size = 24;
76   XColor fg, bg;
77   XGCValues gcv;
78   GC gc = XCreateGC (dpy, window, 0, &gcv);
79   XWindowAttributes xgwa;
80   XGetWindowAttributes (dpy, window, &xgwa);
81   fg.flags = bg.flags = DoRed|DoGreen|DoBlue;
82   fg.red = fg.green = fg.blue = 0x0000;
83   bg.red = bg.green = bg.blue = 0x4444;
84   fg.pixel = 0;
85   bg.pixel = 1;
86
87   /* Allocate black and gray, but don't hold them locked. */
88   if (XAllocColor (dpy, xgwa.colormap, &fg))
89     XFreeColors (dpy, xgwa.colormap, &fg.pixel, 1, 0);
90   if (XAllocColor (dpy, xgwa.colormap, &bg))
91     XFreeColors (dpy, xgwa.colormap, &bg.pixel, 1, 0);
92
93   XSetForeground (dpy, gc, bg.pixel);
94   XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height);
95   XSetForeground (dpy, gc, fg.pixel);
96   for (y = 0; y < xgwa.height; y += size+size)
97     for (x = 0; x < xgwa.width; x += size+size)
98       {
99         XFillRectangle (dpy, window, gc, x,      y,      size, size);
100         XFillRectangle (dpy, window, gc, x+size, y+size, size, size);
101       }
102 }
103
104 static void
105 hack_subproc_environment (Display *dpy)
106 {
107   /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
108      the spawned processes inherit is what we are actually using.
109    */
110   const char *odpy = DisplayString (dpy);
111   char *ndpy = (char *) malloc(strlen(odpy) + 20);
112   strcpy (ndpy, "DISPLAY=");
113   strcat (ndpy, odpy);
114
115   /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
116      any more, right?  It's not Posix, but everyone seems to have it. */
117 #ifdef HAVE_PUTENV
118   if (putenv (ndpy))
119     abort ();
120 #endif /* HAVE_PUTENV */
121 }
122
123
124 void
125 grab_screen_image (Screen *screen, Window window)
126 {
127   Display *dpy = DisplayOfScreen (screen);
128   char *grabber = get_string_resource ("desktopGrabber", "DesktopGrabber");
129   char *cmd;
130   char id[20];
131
132   if (!grabber || !*grabber)
133     {
134       fprintf (stderr,
135          "%s: resources installed incorrectly: \"desktopGrabber\" is unset!\n",
136                progname);
137       exit (1);
138     }
139
140   sprintf (id, "0x%x", (unsigned long) window);
141   cmd = (char *) malloc (strlen(grabber) + strlen(id) + 1);
142
143   /* Needn't worry about buffer overflows here, because the buffer is
144      longer than the length of the format string, and the length of what
145      we're putting into it.  So the only way to crash would be if the
146      format string itself was corrupted, but that comes from the
147      resource database, and if hostile forces have access to that,
148      then the game is already over.
149    */
150   sprintf (cmd, grabber, id);
151
152   /* In case "cmd" fails, leave some random image on the screen, not just
153      black or white, so that it's more obvious what went wrong. */
154   checkerboard (screen, window);
155
156   XSync (dpy, True);
157   hack_subproc_environment (dpy);
158   system (cmd);
159   free (cmd);
160   XSync (dpy, True);
161 }