http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.03.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   XmuPrintDefaultErrorMessage (dpy, error, stderr);
114   exit (-1);
115   return 0;
116 }
117
118
119
120 static void
121 get_image (Screen *screen, Window window, Bool verbose_p)
122 {
123   Display *dpy = DisplayOfScreen (screen);
124   Bool desk_p  = get_boolean_resource ("grabDesktopImages",  "Boolean");
125   Bool video_p = get_boolean_resource ("grabVideoFrames",    "Boolean");
126   Bool image_p = get_boolean_resource ("chooseRandomImages", "Boolean");
127   char *dir    = get_string_resource ("imageDirectory", "ImageDirectory");
128
129   enum { do_desk, do_video, do_image, do_bars } which = do_bars;
130   int count = 0;
131
132   XWindowAttributes xgwa;
133   XGetWindowAttributes (dpy, window, &xgwa);
134   screen = xgwa.screen;
135
136   if (verbose_p)
137     {
138       fprintf (stderr, "%s: grabDesktopImages:  %s\n",
139                progname, desk_p ? "True" : "False");
140       fprintf (stderr, "%s: grabVideoFrames:    %s\n",
141                progname, video_p ? "True" : "False");
142       fprintf (stderr, "%s: chooseRandomImages: %s\n",
143                progname, image_p ? "True" : "False");
144       fprintf (stderr, "%s: imageDirectory:     %s\n",
145                progname, (dir ? dir : ""));
146     }
147
148   if (!dir || !*dir)
149     {
150       if (verbose_p && image_p)
151         fprintf (stderr,
152                  "%s: no imageDirectory: turning off chooseRandomImages.\n",
153                  progname);
154       image_p = False;
155     }
156
157 # ifndef _VROOT_H_
158 #  error Error!  This file definitely needs vroot.h!
159 # endif
160
161   /* If the window is not the root window (real or virtual!) then the hack
162      that called this program is running in "-window" mode instead of in
163      "-root" mode.
164
165      If the window is not the root window, then it's not possible to grab
166      video or images onto it (the contract with those programs is to draw on
167      the root.)  So turn off those options in that case, and turn on desktop
168      grabbing.  (Since we're running in a window on the desktop already, we
169      know it's not a security problem to expose desktop bits.)
170    */
171
172   if ((desk_p || video_p || image_p) &&
173       !top_level_window_p (screen, window))
174     {
175       desk_p  = False;
176       video_p = False;
177       image_p = False;
178       if (verbose_p)
179         fprintf (stderr, "%s: not a top-level window: using colorbars.\n",
180                  progname);
181     }
182   else if (window != VirtualRootWindowOfScreen (screen))
183     {
184       Bool changed_p = False;
185       if (!desk_p) desk_p  = True,  changed_p = True;
186       if (video_p) video_p = False, changed_p = True;
187       if (image_p) image_p = False, changed_p = True;
188       if (changed_p && verbose_p)
189         fprintf (stderr,
190                  "%s: not running on root window: grabbing desktop.\n",
191                  progname);
192     }
193
194   count = 0;
195   if (desk_p)  count++;
196   if (video_p) count++;
197   if (image_p) count++;
198
199   if (count == 0)
200     which = do_bars;
201   else
202     {
203       int i = 0;
204       while (1)  /* loop until we get one that's permitted */
205         {
206           which = (random() % 3);
207           if (which == do_desk  && desk_p)  break;
208           if (which == do_video && video_p) break;
209           if (which == do_image && image_p) break;
210           if (++i > 200) abort();
211         }
212     }
213
214   if (which == do_desk)
215     {
216       if (verbose_p)
217         {
218           fprintf (stderr, "%s: grabbing desktop image\n", progname);
219           grabscreen_verbose();
220         }
221       grab_screen_image (screen, window);
222       XSync (dpy, False);
223     }
224   else if (which == do_bars)
225     {
226       if (verbose_p)
227         fprintf (stderr, "%s: drawing colorbars\n", progname);
228       draw_colorbars (dpy, window, 0, 0, xgwa.width, xgwa.height);
229       XSync (dpy, False);
230     }
231   else
232     {
233       char *av[10];
234       memset (av, 0, sizeof(av));
235       switch (which)
236         {
237         case do_video:
238           if (verbose_p)
239             fprintf (stderr, "%s: grabbing video\n", progname);
240           av[0] = GETIMAGE_VIDEO_PROGRAM;
241           break;
242         case do_image:
243           if (verbose_p)
244             fprintf (stderr, "%s: loading random image file\n", progname);
245           av[0] = GETIMAGE_FILE_PROGRAM;
246           av[1] = dir;
247           break;
248         default:
249           abort();
250           break;
251         }
252
253       if (verbose_p)
254         {
255           int i;
256           for (i = (sizeof(av)/sizeof(*av))-1; i > 1; i--)
257             av[i] = av[i-1];
258           av[1] = strdup ("--verbose");
259         }
260
261       if (verbose_p)
262         {
263           int i = 0;
264           fprintf (stderr, "%s: executing \"", progname);
265           while (av[i])
266             {
267               fprintf (stderr, "%s", av[i]);
268               if (av[++i]) fprintf (stderr, " ");
269             }
270           fprintf (stderr, "\"\n");
271         }
272
273 # ifdef HAVE_PUTENV
274       /* Store our "-display" argument into the $DISPLAY variable,
275          so that the subprocess gets the right display if the
276          prevailing $DISPLAY is different. */
277       {
278         const char *odpy = DisplayString (dpy);
279         char *ndpy = (char *) malloc(strlen(odpy) + 20);
280         char *s;
281         int screen_no = screen_number (screen);  /* might not be default now */
282
283         strcpy (ndpy, "DISPLAY=");
284         s = ndpy + strlen(ndpy);
285         strcpy (s, odpy);
286
287         while (*s && *s != ':') s++;            /* skip to colon */
288         while (*s == ':') s++;                  /* skip over colons */
289         while (isdigit(*s)) s++;                /* skip over dpy number */
290         while (*s == '.') s++;                  /* skip over dot */
291         if (s[-1] != '.') *s++ = '.';           /* put on a dot */
292         sprintf(s, "%d", screen_no);            /* put on screen number */
293
294         if (putenv (ndpy))
295           abort ();
296
297         /* don't free (ndpy) -- some implementations of putenv (BSD
298            4.4, glibc 2.0) copy the argument, but some (libc4,5, glibc
299            2.1.2) do not.  So we must leak it (and/or the previous
300            setting).  Yay.
301          */
302       }
303 # endif /* HAVE_PUTENV */
304
305       close (ConnectionNumber (dpy));   /* close display fd */
306
307       execvp (av[0], av);               /* shouldn't return */
308       exec_error (av);
309     }
310 }
311
312
313 #if 0
314 static Bool
315 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
316         XrmRepresentation *type, XrmValue *value, XPointer closure)
317 {
318   int i;
319   for (i = 0; quarks[i]; i++)
320     {
321       if (bindings[i] == XrmBindTightly)
322         fprintf (stderr, (i == 0 ? "" : "."));
323       else if (bindings[i] == XrmBindLoosely)
324         fprintf (stderr, "*");
325       else
326         fprintf (stderr, " ??? ");
327       fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
328     }
329
330   fprintf (stderr, ": %s\n", (char *) value->addr);
331
332   return False;
333 }
334 #endif
335
336
337 int
338 main (int argc, char **argv)
339 {
340   saver_preferences P;
341   Widget toplevel;
342   Display *dpy;
343   Screen *screen;
344   Window window = (Window) 0;
345   Bool verbose_p = False;
346   char *s;
347   int i;
348
349   progname = argv[0];
350   s = strrchr (progname, '/');
351   if (s) progname = s+1;
352
353   /* We must read exactly the same resources as xscreensaver.
354      That means we must have both the same progclass *and* progname,
355      at least as far as the resource database is concerned.  So,
356      put "xscreensaver" in argv[0] while initializing Xt.
357    */
358   argv[0] = "xscreensaver";
359   toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
360                               defaults, 0, 0);
361   argv[0] = progname;
362   dpy = XtDisplay (toplevel);
363   screen = XtScreen (toplevel);
364   db = XtDatabase (dpy);
365
366   XtGetApplicationNameAndClass (dpy, &s, &progclass);
367   XSetErrorHandler (x_ehandler);
368   XSync (dpy, False);
369
370   /* half-assed way of avoiding buffer-overrun attacks. */
371   if (strlen (progname) >= 100) progname[100] = 0;
372
373   for (i = 1; i < argc; i++)
374     {
375       if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
376       if (!strcmp (argv[i], "-v") ||
377           !strcmp (argv[i], "-verbose"))
378         verbose_p = True;
379       else if (window == 0)
380         {
381           unsigned long w;
382           char dummy;
383
384           if (!strcmp (argv[i], "root") ||
385               !strcmp (argv[i], "-root") ||
386               !strcmp (argv[i], "--root"))
387             window = RootWindowOfScreen (screen);
388
389           else if ((1 == sscanf (argv[i], " 0x%x %c", &w, &dummy) ||
390                     1 == sscanf (argv[i], " %d %c",   &w, &dummy)) &&
391                    w != 0)
392             window = (Window) w;
393           else
394             goto LOSE;
395         }
396       else
397         {
398          LOSE:
399           fprintf (stderr,
400             "usage: %s [ -display host:dpy.screen ] [ -v ] window-id\n",
401                    progname);
402           fprintf (stderr, "\n"
403         "\tThis program puts an image of the desktop on the given window.\n"
404         "\tIt is used by those xscreensaver demos that operate on images.\n"
405         "\n");
406           exit (1);
407         }
408     }
409
410   if (window == 0) goto LOSE;
411
412   /* Randomize -- only need to do this here because this program
413      doesn't use the `screenhack.h' or `lockmore.h' APIs. */
414 # undef ya_rand_init
415   ya_rand_init (0);
416
417   memset (&P, 0, sizeof(P));
418   P.db = db;
419   load_init_file (&P);
420
421   if (P.verbose_p)
422     verbose_p = True;
423
424 #if 0
425   /* Print out all the resources we read. */
426   {
427     XrmName name = { 0 };
428     XrmClass class = { 0 };
429     int count = 0;
430     XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
431                           (XtPointer) &count);
432   }
433 #endif
434
435   get_image (screen, window, verbose_p);
436   exit (0);
437 }