http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.02.tar.gz
[xscreensaver] / driver / xscreensaver-getimage.c
1 /* xscreensaver, Copyright (c) 2001, 2002 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         /* don't free (ndpy) -- some implementations of putenv (BSD
300            4.4, glibc 2.0) copy the argument, but some (libc4,5, glibc
301            2.1.2) do not.  So we must leak it (and/or the previous
302            setting).  Yay.
303          */
304       }
305 # endif /* HAVE_PUTENV */
306
307       close (ConnectionNumber (dpy));   /* close display fd */
308
309       execvp (av[0], av);               /* shouldn't return */
310       exec_error (av);
311     }
312 }
313
314
315 #if 0
316 static Bool
317 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
318         XrmRepresentation *type, XrmValue *value, XPointer closure)
319 {
320   int i;
321   for (i = 0; quarks[i]; i++)
322     {
323       if (bindings[i] == XrmBindTightly)
324         fprintf (stderr, (i == 0 ? "" : "."));
325       else if (bindings[i] == XrmBindLoosely)
326         fprintf (stderr, "*");
327       else
328         fprintf (stderr, " ??? ");
329       fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
330     }
331
332   fprintf (stderr, ": %s\n", (char *) value->addr);
333
334   return False;
335 }
336 #endif
337
338
339 int
340 main (int argc, char **argv)
341 {
342   saver_preferences P;
343   Widget toplevel;
344   Display *dpy;
345   Screen *screen;
346   Window window = (Window) 0;
347   Bool verbose_p = False;
348   char *s;
349   int i;
350
351   progname = argv[0];
352   s = strrchr (progname, '/');
353   if (s) progname = s+1;
354
355   /* We must read exactly the same resources as xscreensaver.
356      That means we must have both the same progclass *and* progname,
357      at least as far as the resource database is concerned.  So,
358      put "xscreensaver" in argv[0] while initializing Xt.
359    */
360   argv[0] = "xscreensaver";
361   toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
362                               defaults, 0, 0);
363   argv[0] = progname;
364   dpy = XtDisplay (toplevel);
365   screen = XtScreen (toplevel);
366   db = XtDatabase (dpy);
367
368   XtGetApplicationNameAndClass (dpy, &s, &progclass);
369   XSetErrorHandler (x_ehandler);
370   XSync (dpy, False);
371
372   /* half-assed way of avoiding buffer-overrun attacks. */
373   if (strlen (progname) >= 100) progname[100] = 0;
374
375   for (i = 1; i < argc; i++)
376     {
377       if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
378       if (!strcmp (argv[i], "-v") ||
379           !strcmp (argv[i], "-verbose"))
380         verbose_p = True;
381       else if (window == 0)
382         {
383           unsigned long w;
384           char dummy;
385
386           if (!strcmp (argv[i], "root") ||
387               !strcmp (argv[i], "-root") ||
388               !strcmp (argv[i], "--root"))
389             window = RootWindowOfScreen (screen);
390
391           else if ((1 == sscanf (argv[i], " 0x%x %c", &w, &dummy) ||
392                     1 == sscanf (argv[i], " %d %c",   &w, &dummy)) &&
393                    w != 0)
394             window = (Window) w;
395           else
396             goto LOSE;
397         }
398       else
399         {
400          LOSE:
401           fprintf (stderr,
402             "usage: %s [ -display host:dpy.screen ] [ -v ] window-id\n",
403                    progname);
404           fprintf (stderr, "\n"
405         "\tThis program puts an image of the desktop on the given window.\n"
406         "\tIt is used by those xscreensaver demos that operate on images.\n"
407         "\n");
408           exit (1);
409         }
410     }
411
412   if (window == 0) goto LOSE;
413
414   /* Randomize -- only need to do this here because this program
415      doesn't use the `screenhack.h' or `lockmore.h' APIs. */
416 # undef ya_rand_init
417   ya_rand_init (0);
418
419   memset (&P, 0, sizeof(P));
420   P.db = db;
421   load_init_file (&P);
422
423   if (P.verbose_p)
424     verbose_p = True;
425
426 #if 0
427   /* Print out all the resources we read. */
428   {
429     XrmName name = { 0 };
430     XrmClass class = { 0 };
431     int count = 0;
432     XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
433                           (XtPointer) &count);
434   }
435 #endif
436
437   get_image (screen, window, verbose_p);
438   exit (0);
439 }