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