http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.01.tar.gz
[xscreensaver] / driver / xscreensaver-getimage.c
1 /* xscreensaver, Copyright (c) 2001 by Jamie Zawinski <jwz@jwz.org>
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 /* xscreensaver-getimage -- helper program that puts an image
13    (e.g., a snapshot of the desktop) onto the given window.
14  */
15
16 #include "utils.h"
17
18 #include <X11/Intrinsic.h>
19 #include <ctype.h>
20 #include <errno.h>
21
22 #ifdef HAVE_XMU
23 # ifndef VMS
24 #  include <X11/Xmu/Error.h>
25 # else /* VMS */
26 #  include <Xmu/Error.h>
27 # endif
28 #else
29 # include "xmu.h"
30 #endif
31
32 #include "yarandom.h"
33 #include "grabscreen.h"
34 #include "resources.h"
35 #include "colorbars.h"
36 #include "visual.h"
37 #include "prefs.h"
38 #include "vroot.h"
39
40
41 static char *defaults[] = {
42 #include "../driver/XScreenSaver_ad.h"
43  0
44 };
45
46
47
48 char *progname = 0;
49 char *progclass = "XScreenSaver";
50 XrmDatabase db;
51 XtAppContext app;
52
53 extern void grabscreen_verbose (void);
54
55
56 #define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video"
57 #define GETIMAGE_FILE_PROGRAM  "xscreensaver-getimage-file"
58
59
60 const char *
61 blurb (void)
62 {
63   return progname;
64 }
65
66
67 static void
68 exec_error (char **av)
69 {
70   char buf [512];
71   char *token;
72
73   sprintf (buf, "%s: could not execute \"%s\"", progname, av[0]);
74   perror (buf);
75
76   if (errno == ENOENT &&
77       (token = getenv("PATH")))
78     {
79 # ifndef PATH_MAX
80 #  ifdef MAXPATHLEN
81 #   define PATH_MAX MAXPATHLEN
82 #  else
83 #   define PATH_MAX 2048
84 #  endif
85 # endif
86       char path[PATH_MAX];
87       fprintf (stderr, "\n");
88       *path = 0;
89 # if defined(HAVE_GETCWD)
90       getcwd (path, sizeof(path));
91 # elif defined(HAVE_GETWD)
92       getwd (path);
93 # endif
94       if (*path)
95         fprintf (stderr, "    Current directory is: %s\n", path);
96       fprintf (stderr, "    PATH is:\n");
97       token = strtok (strdup(token), ":");
98       while (token)
99         {
100           fprintf (stderr, "        %s\n", token);
101           token = strtok(0, ":");
102         }
103       fprintf (stderr, "\n");
104     }
105
106   exit (1);
107 }
108
109 static int
110 x_ehandler (Display *dpy, XErrorEvent *error)
111 {
112   fprintf (stderr, "\nX error in %s:\n", progname);
113   if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
114     exit (-1);
115   else
116     fprintf (stderr, " (nonfatal.)\n");
117   return 0;
118 }
119
120
121
122 static void
123 get_image (Screen *screen, Window window, Bool verbose_p)
124 {
125   Display *dpy = DisplayOfScreen (screen);
126   Bool desk_p  = get_boolean_resource ("grabDesktopImages",  "Boolean");
127   Bool video_p = get_boolean_resource ("grabVideoFrames",    "Boolean");
128   Bool image_p = get_boolean_resource ("chooseRandomImages", "Boolean");
129   char *dir    = get_string_resource ("imageDirectory", "ImageDirectory");
130
131   enum { do_desk, do_video, do_image, do_bars } which = do_bars;
132   int count = 0;
133
134   XWindowAttributes xgwa;
135   XGetWindowAttributes (dpy, window, &xgwa);
136   screen = xgwa.screen;
137
138   if (verbose_p)
139     {
140       fprintf (stderr, "%s: grabDesktopImages:  %s\n",
141                progname, desk_p ? "True" : "False");
142       fprintf (stderr, "%s: grabVideoFrames:    %s\n",
143                progname, video_p ? "True" : "False");
144       fprintf (stderr, "%s: chooseRandomImages: %s\n",
145                progname, image_p ? "True" : "False");
146       fprintf (stderr, "%s: imageDirectory:     %s\n",
147                progname, (dir ? dir : ""));
148     }
149
150   if (!dir || !*dir)
151     {
152       if (verbose_p && image_p)
153         fprintf (stderr,
154                  "%s: no imageDirectory: turning off chooseRandomImages.\n",
155                  progname);
156       image_p = False;
157     }
158
159 # ifndef _VROOT_H_
160 #  error Error!  This file definitely needs vroot.h!
161 # endif
162
163   /* If the window is not the root window (real or virtual!) then the hack
164      that called this program is running in "-window" mode instead of in
165      "-root" mode.
166
167      If the window is not the root window, then it's not possible to grab
168      video or images onto it (the contract with those programs is to draw on
169      the root.)  So turn off those options in that case, and turn on desktop
170      grabbing.  (Since we're running in a window on the desktop already, we
171      know it's not a security problem to expose desktop bits.)
172    */
173
174   if ((desk_p || video_p || image_p) &&
175       !top_level_window_p (screen, window))
176     {
177       desk_p  = False;
178       video_p = False;
179       image_p = False;
180       if (verbose_p)
181         fprintf (stderr, "%s: not a top-level window: using colorbars.\n",
182                  progname);
183     }
184   else if (window != VirtualRootWindowOfScreen (screen))
185     {
186       Bool changed_p = False;
187       if (!desk_p) desk_p  = True,  changed_p = True;
188       if (video_p) video_p = False, changed_p = True;
189       if (image_p) image_p = False, changed_p = True;
190       if (changed_p && verbose_p)
191         fprintf (stderr,
192                  "%s: not running on root window: grabbing desktop.\n",
193                  progname);
194     }
195
196   count = 0;
197   if (desk_p)  count++;
198   if (video_p) count++;
199   if (image_p) count++;
200
201   if (count == 0)
202     which = do_bars;
203   else
204     {
205       int i = 0;
206       while (1)  /* loop until we get one that's permitted */
207         {
208           which = (random() % 3);
209           if (which == do_desk  && desk_p)  break;
210           if (which == do_video && video_p) break;
211           if (which == do_image && image_p) break;
212           if (++i > 200) abort();
213         }
214     }
215
216   if (which == do_desk)
217     {
218       if (verbose_p)
219         {
220           fprintf (stderr, "%s: grabbing desktop image\n", progname);
221           grabscreen_verbose();
222         }
223       grab_screen_image (screen, window);
224       XSync (dpy, False);
225     }
226   else if (which == do_bars)
227     {
228       if (verbose_p)
229         fprintf (stderr, "%s: drawing colorbars\n", progname);
230       draw_colorbars (dpy, window, 0, 0, xgwa.width, xgwa.height);
231       XSync (dpy, False);
232     }
233   else
234     {
235       char *av[10];
236       memset (av, 0, sizeof(av));
237       switch (which)
238         {
239         case do_video:
240           if (verbose_p)
241             fprintf (stderr, "%s: grabbing video\n", progname);
242           av[0] = GETIMAGE_VIDEO_PROGRAM;
243           break;
244         case do_image:
245           if (verbose_p)
246             fprintf (stderr, "%s: loading random image file\n", progname);
247           av[0] = GETIMAGE_FILE_PROGRAM;
248           av[1] = dir;
249           break;
250         default:
251           abort();
252           break;
253         }
254
255       if (verbose_p)
256         {
257           int i;
258           for (i = (sizeof(av)/sizeof(*av))-1; i > 1; i--)
259             av[i] = av[i-1];
260           av[1] = strdup ("--verbose");
261         }
262
263       if (verbose_p)
264         {
265           int i = 0;
266           fprintf (stderr, "%s: executing \"", progname);
267           while (av[i])
268             {
269               fprintf (stderr, "%s", av[i]);
270               if (av[++i]) fprintf (stderr, " ");
271             }
272           fprintf (stderr, "\"\n");
273         }
274
275 # ifdef HAVE_PUTENV
276       /* Store our "-display" argument into the $DISPLAY variable,
277          so that the subprocess gets the right display if the
278          prevailing $DISPLAY is different. */
279       {
280         const char *odpy = DisplayString (dpy);
281         char *ndpy = (char *) malloc(strlen(odpy) + 20);
282         char *s;
283         int screen_no = screen_number (screen);  /* might not be default now */
284
285         strcpy (ndpy, "DISPLAY=");
286         s = ndpy + strlen(ndpy);
287         strcpy (s, odpy);
288
289         while (*s && *s != ':') s++;            /* skip to colon */
290         while (*s == ':') s++;                  /* skip over colons */
291         while (isdigit(*s)) s++;                /* skip over dpy number */
292         while (*s == '.') s++;                  /* skip over dot */
293         if (s[-1] != '.') *s++ = '.';           /* put on a dot */
294         sprintf(s, "%d", screen_no);            /* put on screen number */
295
296         if (putenv (ndpy))
297           abort ();
298       }
299 # endif /* HAVE_PUTENV */
300
301       close (ConnectionNumber (dpy));   /* close display fd */
302
303       execvp (av[0], av);               /* shouldn't return */
304       exec_error (av);
305     }
306 }
307
308
309 #if 0
310 static Bool
311 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
312         XrmRepresentation *type, XrmValue *value, XPointer closure)
313 {
314   int i;
315   for (i = 0; quarks[i]; i++)
316     {
317       if (bindings[i] == XrmBindTightly)
318         fprintf (stderr, (i == 0 ? "" : "."));
319       else if (bindings[i] == XrmBindLoosely)
320         fprintf (stderr, "*");
321       else
322         fprintf (stderr, " ??? ");
323       fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
324     }
325
326   fprintf (stderr, ": %s\n", (char *) value->addr);
327
328   return False;
329 }
330 #endif
331
332
333 int
334 main (int argc, char **argv)
335 {
336   saver_preferences P;
337   Widget toplevel;
338   Display *dpy;
339   Screen *screen;
340   Window window = (Window) 0;
341   Bool verbose_p = False;
342   char *s;
343   int i;
344
345   progname = argv[0];
346   s = strrchr (progname, '/');
347   if (s) progname = s+1;
348
349   /* We must read exactly the same resources as xscreensaver.
350      That means we must have both the same progclass *and* progname,
351      at least as far as the resource database is concerned.  So,
352      put "xscreensaver" in argv[0] while initializing Xt.
353    */
354   argv[0] = "xscreensaver";
355   toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
356                               defaults, 0, 0);
357   argv[0] = progname;
358   dpy = XtDisplay (toplevel);
359   screen = XtScreen (toplevel);
360   db = XtDatabase (dpy);
361
362   XtGetApplicationNameAndClass (dpy, &s, &progclass);
363   XSetErrorHandler (x_ehandler);
364   XSync (dpy, False);
365
366   /* half-assed way of avoiding buffer-overrun attacks. */
367   if (strlen (progname) >= 100) progname[100] = 0;
368
369   for (i = 1; i < argc; i++)
370     {
371       if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
372       if (!strcmp (argv[i], "-v") ||
373           !strcmp (argv[i], "-verbose"))
374         verbose_p = True;
375       else if (window == 0)
376         {
377           unsigned long w;
378           char dummy;
379
380           if (!strcmp (argv[i], "root") ||
381               !strcmp (argv[i], "-root") ||
382               !strcmp (argv[i], "--root"))
383             window = RootWindowOfScreen (screen);
384
385           else if ((1 == sscanf (argv[i], " 0x%x %c", &w, &dummy) ||
386                     1 == sscanf (argv[i], " %d %c",   &w, &dummy)) &&
387                    w != 0)
388             window = (Window) w;
389           else
390             goto LOSE;
391         }
392       else
393         {
394          LOSE:
395           fprintf (stderr,
396             "usage: %s [ -display host:dpy.screen ] [ -v ] window-id\n",
397                    progname);
398           fprintf (stderr, "\n"
399         "\tThis program puts an image of the desktop on the given window.\n"
400         "\tIt is used by those xscreensaver demos that operate on images.\n"
401         "\n");
402           exit (1);
403         }
404     }
405
406   if (window == 0) goto LOSE;
407
408   /* Randomize -- only need to do this here because this program
409      doesn't use the `screenhack.h' or `lockmore.h' APIs. */
410 # undef ya_rand_init
411   ya_rand_init (0);
412
413   memset (&P, 0, sizeof(P));
414   P.db = db;
415   load_init_file (&P);
416
417   if (P.verbose_p)
418     verbose_p = True;
419
420 #if 0
421   /* Print out all the resources we read. */
422   {
423     XrmName name = { 0 };
424     XrmClass class = { 0 };
425     int count = 0;
426     XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
427                           (XtPointer) &count);
428   }
429 #endif
430
431   get_image (screen, window, verbose_p);
432   exit (0);
433 }