ftp://netsw.org/x11/tools/desktop/xscreensaver-4.07.tar.gz
[xscreensaver] / driver / xscreensaver-getimage.c
1 /* xscreensaver, Copyright (c) 2001, 2002, 2003 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_SYS_WAIT_H
23 # include <sys/wait.h>          /* for waitpid() and associated macros */
24 #endif
25
26 #ifdef HAVE_XMU
27 # ifndef VMS
28 #  include <X11/Xmu/Error.h>
29 # else /* VMS */
30 #  include <Xmu/Error.h>
31 # endif
32 #else
33 # include "xmu.h"
34 #endif
35
36 #include "yarandom.h"
37 #include "grabscreen.h"
38 #include "resources.h"
39 #include "colorbars.h"
40 #include "visual.h"
41 #include "prefs.h"
42 #include "vroot.h"
43
44 #ifdef HAVE_GDK_PIXBUF
45
46 # ifdef HAVE_GTK2
47 #  include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
48 # else  /* !HAVE_GTK2 */
49 #  include <gdk-pixbuf/gdk-pixbuf-xlib.h>
50 # endif /* !HAVE_GTK2 */
51
52 # define HAVE_BUILTIN_IMAGE_LOADER
53 #endif /* HAVE_GDK_PIXBUF */
54
55
56 static char *defaults[] = {
57 #include "../driver/XScreenSaver_ad.h"
58  0
59 };
60
61
62
63 char *progname = 0;
64 char *progclass = "XScreenSaver";
65 XrmDatabase db;
66 XtAppContext app;
67
68 extern void grabscreen_verbose (void);
69
70
71 #define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video"
72 #define GETIMAGE_FILE_PROGRAM  "xscreensaver-getimage-file"
73
74
75 const char *
76 blurb (void)
77 {
78   return progname;
79 }
80
81
82 static void
83 exec_error (char **av)
84 {
85   char buf [512];
86   char *token;
87
88   sprintf (buf, "%s: could not execute \"%s\"", progname, av[0]);
89   perror (buf);
90
91   if (errno == ENOENT &&
92       (token = getenv("PATH")))
93     {
94 # ifndef PATH_MAX
95 #  ifdef MAXPATHLEN
96 #   define PATH_MAX MAXPATHLEN
97 #  else
98 #   define PATH_MAX 2048
99 #  endif
100 # endif
101       char path[PATH_MAX];
102       fprintf (stderr, "\n");
103       *path = 0;
104 # if defined(HAVE_GETCWD)
105       getcwd (path, sizeof(path));
106 # elif defined(HAVE_GETWD)
107       getwd (path);
108 # endif
109       if (*path)
110         fprintf (stderr, "    Current directory is: %s\n", path);
111       fprintf (stderr, "    PATH is:\n");
112       token = strtok (strdup(token), ":");
113       while (token)
114         {
115           fprintf (stderr, "        %s\n", token);
116           token = strtok(0, ":");
117         }
118       fprintf (stderr, "\n");
119     }
120
121   exit (-1);
122 }
123
124 static int
125 x_ehandler (Display *dpy, XErrorEvent *error)
126 {
127   fprintf (stderr, "\nX error in %s:\n", progname);
128   XmuPrintDefaultErrorMessage (dpy, error, stderr);
129   exit (-1);
130   return 0;
131 }
132
133
134
135 #ifdef HAVE_BUILTIN_IMAGE_LOADER
136 static void load_image_internal (Screen *screen, Window window,
137                                  int win_width, int win_height,
138                                  Bool verbose_p,
139                                  int ac, char **av);
140 #endif /* HAVE_BUILTIN_IMAGE_LOADER */
141
142
143 static void
144 get_image (Screen *screen, Window window,
145            Bool verbose_p,
146            Bool desk_p,
147            Bool video_p,
148            Bool image_p,
149            char *dir)
150 {
151   Display *dpy = DisplayOfScreen (screen);
152   enum { do_desk, do_video, do_image, do_bars } which = do_bars;
153   int count = 0;
154
155   XWindowAttributes xgwa;
156   XGetWindowAttributes (dpy, window, &xgwa);
157   screen = xgwa.screen;
158
159   if (verbose_p)
160     {
161       fprintf (stderr, "%s: grabDesktopImages:  %s\n",
162                progname, desk_p ? "True" : "False");
163       fprintf (stderr, "%s: grabVideoFrames:    %s\n",
164                progname, video_p ? "True" : "False");
165       fprintf (stderr, "%s: chooseRandomImages: %s\n",
166                progname, image_p ? "True" : "False");
167       fprintf (stderr, "%s: imageDirectory:     %s\n",
168                progname, (dir ? dir : ""));
169     }
170
171   if (!dir || !*dir)
172     {
173       if (verbose_p && image_p)
174         fprintf (stderr,
175                  "%s: no imageDirectory: turning off chooseRandomImages.\n",
176                  progname);
177       image_p = False;
178     }
179
180 # ifndef _VROOT_H_
181 #  error Error!  This file definitely needs vroot.h!
182 # endif
183
184   /* If the window is not the root window (real or virtual!) then the hack
185      that called this program is running in "-window" mode instead of in
186      "-root" mode.
187
188      If the window is not the root window, then it's not possible to grab
189      video or images onto it (the contract with those programs is to draw on
190      the root.)  So turn off those options in that case, and turn on desktop
191      grabbing.  (Since we're running in a window on the desktop already, we
192      know it's not a security problem to expose desktop bits.)
193    */
194
195   if ((desk_p || video_p || image_p) &&
196       !top_level_window_p (screen, window))
197     {
198       Bool changed_p = False;
199       if (desk_p)  desk_p  = False, changed_p = True;
200       if (video_p) video_p = False, changed_p = True;
201 # ifndef HAVE_BUILTIN_IMAGE_LOADER
202       /* We can display images on non-top-level windows with the builtin
203          loader, but not if we're using the external (chbg-based) loader. */
204       if (image_p) image_p = False, changed_p = True;
205 # endif /* !HAVE_BUILTIN_IMAGE_LOADER */
206
207       if (changed_p && verbose_p)
208         fprintf (stderr, "%s: not a top-level window: using colorbars.\n",
209                  progname);
210     }
211   else if (window != VirtualRootWindowOfScreen (screen))
212     {
213       /* We can display images on non-root windows with the builtin loader,
214          but not if we're using the external (chbg-based) loader.
215          We can never display video on non-root windows (since that always
216          uses the external image loader.)
217       */
218       Bool changed_p = False;
219       if (video_p) video_p = False, changed_p = True;
220 # ifndef HAVE_BUILTIN_IMAGE_LOADER
221       if (!desk_p) desk_p  = True,  changed_p = True;
222       if (image_p) image_p = False, changed_p = True;
223 # endif /* !HAVE_BUILTIN_IMAGE_LOADER */
224
225       if (changed_p && verbose_p)
226         fprintf (stderr,
227                  "%s: not running on root window: grabbing desktop.\n",
228                  progname);
229     }
230
231   count = 0;
232   if (desk_p)  count++;
233   if (video_p) count++;
234   if (image_p) count++;
235
236   if (count == 0)
237     which = do_bars;
238   else
239     {
240       int i = 0;
241       while (1)  /* loop until we get one that's permitted */
242         {
243           which = (random() % 3);
244           if (which == do_desk  && desk_p)  break;
245           if (which == do_video && video_p) break;
246           if (which == do_image && image_p) break;
247           if (++i > 200) abort();
248         }
249     }
250
251   if (which == do_desk)
252     {
253       if (verbose_p)
254         {
255           fprintf (stderr, "%s: grabbing desktop image\n", progname);
256           grabscreen_verbose();
257         }
258       grab_screen_image (screen, window);
259       XSync (dpy, False);
260     }
261   else if (which == do_bars)
262     {
263       if (verbose_p)
264         fprintf (stderr, "%s: drawing colorbars\n", progname);
265       draw_colorbars (dpy, window, 0, 0, xgwa.width, xgwa.height);
266       XSync (dpy, False);
267     }
268   else
269     {
270       char *av[10];
271       int ac = 0;
272       memset (av, 0, sizeof(av));
273       switch (which)
274         {
275         case do_video:
276           if (verbose_p)
277             fprintf (stderr, "%s: grabbing video\n", progname);
278           av[ac++] = GETIMAGE_VIDEO_PROGRAM;
279           break;
280         case do_image:
281           if (verbose_p)
282             fprintf (stderr, "%s: loading random image file\n", progname);
283           av[ac++] = GETIMAGE_FILE_PROGRAM;
284
285 # ifdef HAVE_BUILTIN_IMAGE_LOADER
286           av[ac++] = "--name";
287 # endif /* !HAVE_BUILTIN_IMAGE_LOADER */
288           av[ac++] = dir;
289           break;
290         default:
291           abort();
292           break;
293         }
294
295       if (verbose_p)
296         {
297           int i;
298           for (i = ac; i > 1; i--)
299             av[i] = av[i-1];
300           av[1] = strdup ("--verbose");
301           ac++;
302         }
303
304       if (verbose_p)
305         {
306           int i = 0;
307           fprintf (stderr, "%s: executing \"", progname);
308           while (av[i])
309             {
310               fprintf (stderr, "%s", av[i]);
311               if (av[++i]) fprintf (stderr, " ");
312             }
313           fprintf (stderr, "\"\n");
314         }
315
316 # ifdef HAVE_PUTENV
317       /* Store our "-display" argument into the $DISPLAY variable,
318          so that the subprocess gets the right display if the
319          prevailing $DISPLAY is different. */
320       {
321         const char *odpy = DisplayString (dpy);
322         char *ndpy = (char *) malloc(strlen(odpy) + 20);
323         char *s;
324         int screen_no = screen_number (screen);  /* might not be default now */
325
326         strcpy (ndpy, "DISPLAY=");
327         s = ndpy + strlen(ndpy);
328         strcpy (s, odpy);
329
330         while (*s && *s != ':') s++;            /* skip to colon */
331         while (*s == ':') s++;                  /* skip over colons */
332         while (isdigit(*s)) s++;                /* skip over dpy number */
333         while (*s == '.') s++;                  /* skip over dot */
334         if (s[-1] != '.') *s++ = '.';           /* put on a dot */
335         sprintf(s, "%d", screen_no);            /* put on screen number */
336
337         if (putenv (ndpy))
338           abort ();
339
340         /* don't free (ndpy) -- some implementations of putenv (BSD
341            4.4, glibc 2.0) copy the argument, but some (libc4,5, glibc
342            2.1.2) do not.  So we must leak it (and/or the previous
343            setting).  Yay.
344          */
345       }
346 # endif /* HAVE_PUTENV */
347
348 # ifdef HAVE_BUILTIN_IMAGE_LOADER
349       if (which == do_image)
350         {
351           load_image_internal (screen, window, xgwa.width, xgwa.height,
352                                verbose_p, ac, av);
353           return;
354         }
355 # endif /* HAVE_BUILTIN_IMAGE_LOADER */
356
357
358       close (ConnectionNumber (dpy));   /* close display fd */
359
360       execvp (av[0], av);               /* shouldn't return */
361       exec_error (av);
362     }
363 }
364
365
366 #ifdef HAVE_BUILTIN_IMAGE_LOADER
367
368 /* Reads a filename from "GETIMAGE_FILE_PROGRAM --name /DIR"
369  */
370 static char *
371 get_filename (Display *dpy, int ac, char **av)
372 {
373   pid_t forked;
374   int fds [2];
375   int in, out;
376   char buf[1024];
377
378   if (pipe (fds))
379     {
380       sprintf (buf, "%s: error creating pipe", progname);
381       perror (buf);
382       return 0;
383     }
384
385   in = fds [0];
386   out = fds [1];
387
388   switch ((int) (forked = fork ()))
389     {
390     case -1:
391       {
392         sprintf (buf, "%s: couldn't fork", progname);
393         perror (buf);
394         return 0;
395       }
396     case 0:
397       {
398         int stdout_fd = 1;
399
400         close (in);  /* don't need this one */
401         close (ConnectionNumber (dpy));         /* close display fd */
402
403         if (dup2 (out, stdout_fd) < 0)          /* pipe stdout */
404           {
405             sprintf (buf, "%s: could not dup() a new stdout", progname);
406             exit (-1);                          /* exits fork */
407           }
408
409         execvp (av[0], av);                     /* shouldn't return. */
410         exit (-1);                              /* exits fork */
411         break;
412       }
413     default:
414       {
415         int wait_status = 0;
416         FILE *f = fdopen (in, "r");
417         int L;
418
419         close (out);  /* don't need this one */
420         *buf = 0;
421         fgets (buf, sizeof(buf)-1, f);
422         fclose (f);
423
424         /* Wait for the child to die. */
425         waitpid (-1, &wait_status, 0);
426
427         L = strlen (buf);
428         while (L && buf[L-1] == '\n')
429           buf[--L] = 0;
430           
431         return strdup (buf);
432       }
433     }
434
435   abort();
436 }
437
438
439
440 static void
441 load_image_internal (Screen *screen, Window window,
442                      int win_width, int win_height,
443                      Bool verbose_p,
444                      int ac, char **av)
445 {
446   GdkPixbuf *pb;
447   Display *dpy = DisplayOfScreen (screen);
448   char *filename = get_filename (dpy, ac, av);
449 #ifdef HAVE_GTK2
450   GError *gerr = 0;
451 #endif /* HAVE_GTK2 */
452
453   if (!filename)
454     {
455       fprintf (stderr, "%s: no file name returned by %s\n",
456                progname, av[0]);
457       goto FAIL;
458     }
459   else if (verbose_p)
460     fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
461
462   gdk_pixbuf_xlib_init (dpy, screen_number (screen));
463 #ifdef HAVE_GTK2
464   g_type_init();
465 #else  /* !HAVE_GTK2 */
466   xlib_rgb_init (dpy, screen);
467 #endif /* !HAVE_GTK2 */
468
469   pb = gdk_pixbuf_new_from_file (filename
470 #ifdef HAVE_GTK2
471                                  , &gerr
472 #endif /* HAVE_GTK2 */
473           );
474
475   if (pb)
476     {
477       int w = gdk_pixbuf_get_width (pb);
478       int h = gdk_pixbuf_get_height (pb);
479       int srcx, srcy, destx, desty;
480
481       Bool exact_fit_p = ((w == win_width  && h <= win_height) ||
482                           (h == win_height && w <= win_width));
483
484       if (!exact_fit_p)  /* scale the image up or down */
485         {
486           float rw = (float) win_width  / w;
487           float rh = (float) win_height / h;
488           float r = (rw < rh ? rw : rh);
489           int tw = w * r;
490           int th = h * r;
491           int pct = (r * 100);
492
493           if (pct < 95 || pct > 105)  /* don't scale if it's close */
494             {
495               GdkPixbuf *pb2;
496               if (verbose_p)
497                 fprintf (stderr,
498                          "%s: scaling image by %d%% (%dx%d -> %dx%d)\n",
499                          progname, pct, w, h, tw, th);
500
501               pb2 = gdk_pixbuf_scale_simple (pb, tw, th, GDK_INTERP_BILINEAR);
502               if (pb2)
503                 {
504                   gdk_pixbuf_unref (pb);
505                   pb = pb2;
506                   w = tw;
507                   h = th;
508                 }
509               else
510                 fprintf (stderr, "%s: out of memory when scaling?\n",
511                          progname);
512             }
513         }
514
515       /* Center the image on the window. */
516       srcx = 0;
517       srcy = 0;
518       destx = (win_width  - w) / 2;
519       desty = (win_height - h) / 2;
520       if (destx < 0) srcx = -destx, destx = 0;
521       if (desty < 0) srcy = -desty, desty = 0;
522
523       if (win_width  < w) w = win_width;
524       if (win_height < h) h = win_height;
525
526       /* The window might have no-op background of None, so to clear it,
527          draw a black rectangle first, then do XClearWindow (in case the
528          actual background color is non-black...) */
529       {
530         XGCValues gcv;
531         GC gc;
532         /* #### really we should allocate "black" instead, but I'm lazy... */
533         gcv.foreground = BlackPixelOfScreen (screen);
534         gc = XCreateGC (dpy, window, GCForeground, &gcv);
535         XFillRectangle (dpy, window, gc, 0, 0, win_width, win_height);
536         XFreeGC (dpy, gc);
537         XClearWindow (dpy, window);
538         XFlush (dpy);
539       }
540
541       /* #### Note that this always uses the default colormap!  Morons!
542               Owen says that in Gnome 2.0, I should try using
543               gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead.
544               But I don't have Gnome 2.0 yet.
545        */
546       gdk_pixbuf_xlib_render_to_drawable_alpha (pb, window,
547                                                 srcx, srcy, destx, desty, w, h,
548                                                 GDK_PIXBUF_ALPHA_FULL, 127,
549                                                 XLIB_RGB_DITHER_NORMAL, 0, 0);
550       XSync (dpy, False);
551
552       if (verbose_p)
553         fprintf (stderr, "%s: displayed %dx%d image at %d,%d.\n",
554                  progname, w, h, destx, desty);
555     }
556   else if (filename)
557     {
558       fprintf (stderr, "%s: unable to load %s\n", progname, filename);
559 #ifdef HAVE_GTK2
560       if (gerr && gerr->message && *gerr->message)
561         fprintf (stderr, "%s: reason %s\n", progname, gerr->message);
562 #endif /* HAVE_GTK2 */
563
564       goto FAIL;
565     }
566   else
567     {
568       fprintf (stderr, "%s: unable to initialize built-in images\n", progname);
569       goto FAIL;
570     }
571
572   return;
573
574  FAIL:
575   if (verbose_p)
576     fprintf (stderr, "%s: drawing colorbars\n", progname);
577   draw_colorbars (dpy, window, 0, 0, win_width, win_height);
578   XSync (dpy, False);
579 }
580
581 #endif /* HAVE_BUILTIN_IMAGE_LOADER */
582
583
584
585 #ifdef DEBUG
586 static Bool
587 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
588         XrmRepresentation *type, XrmValue *value, XPointer closure)
589 {
590   int i;
591   for (i = 0; quarks[i]; i++)
592     {
593       if (bindings[i] == XrmBindTightly)
594         fprintf (stderr, (i == 0 ? "" : "."));
595       else if (bindings[i] == XrmBindLoosely)
596         fprintf (stderr, "*");
597       else
598         fprintf (stderr, " ??? ");
599       fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
600     }
601
602   fprintf (stderr, ": %s\n", (char *) value->addr);
603
604   return False;
605 }
606 #endif /* DEBUG */
607
608
609 #define USAGE "usage: %s [ -options... ] window-id\n"                         \
610    "\n"                                                                       \
611    "    This program puts an image on the given window.\n"                    \
612    "\n"                                                                       \
613    "    It is used by those xscreensaver demos that operate on images.\n"     \
614    "    The image may be a file loaded from disk, a frame grabbed from\n"     \
615    "    the system's video camera, or a screenshot of the desktop,\n"         \
616    "    depending on command-line options or the ~/.xscreensaver file.\n"     \
617    "\n"                                                                       \
618    "    Options include:\n"                                                   \
619    "\n"                                                                       \
620    "      -display host:dpy.screen    which display to use\n"                 \
621    "      -root                       draw to the root window\n"              \
622    "      -verbose                    print diagnostics\n"                    \
623    "      -images  / -no-images       whether to allow image file loading\n"  \
624    "      -video   / -no-video        whether to allow video grabs\n"         \
625    "      -desktop / -no-desktop      whether to allow desktop screen grabs\n"\
626    "      -directory <path>           where to find image files to load\n"    \
627    "\n"                                                                       \
628    "    The XScreenSaver Control Panel (xscreensaver-demo) lets you set the\n"\
629    "    defaults for these options in your ~/.xscreensaver file.\n"           \
630    "\n"
631
632 int
633 main (int argc, char **argv)
634 {
635   saver_preferences P;
636   Widget toplevel;
637   Display *dpy;
638   Screen *screen;
639   char *oprogname = progname;
640
641   Window window = (Window) 0;
642   char *s;
643   int i;
644
645   progname = argv[0];
646   s = strrchr (progname, '/');
647   if (s) progname = s+1;
648   oprogname = progname;
649
650   /* half-assed way of avoiding buffer-overrun attacks. */
651   if (strlen (progname) >= 100) progname[100] = 0;
652
653
654   /* We must read exactly the same resources as xscreensaver.
655      That means we must have both the same progclass *and* progname,
656      at least as far as the resource database is concerned.  So,
657      put "xscreensaver" in argv[0] while initializing Xt.
658    */
659   progname = argv[0] = "xscreensaver";
660
661   /* allow one dash or two. */
662   for (i = 1; i < argc; i++)
663     if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
664
665   toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
666                               defaults, 0, 0);
667   dpy = XtDisplay (toplevel);
668   screen = XtScreen (toplevel);
669   db = XtDatabase (dpy);
670   XtGetApplicationNameAndClass (dpy, &s, &progclass);
671   XSetErrorHandler (x_ehandler);
672   XSync (dpy, False);
673
674   /* Randomize -- only need to do this here because this program
675      doesn't use the `screenhack.h' or `lockmore.h' APIs. */
676 # undef ya_rand_init
677   ya_rand_init (0);
678
679   memset (&P, 0, sizeof(P));
680   P.db = db;
681   load_init_file (&P);
682
683   progname = argv[0] = oprogname;
684
685   for (i = 1; i < argc; i++)
686     {
687       /* Have to re-process these, or else the .xscreensaver file
688          has priority over the command line...
689        */
690       if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-verbose"))
691         P.verbose_p = True;
692       else if (!strcmp (argv[i], "-desktop"))    P.grab_desktop_p = True;
693       else if (!strcmp (argv[i], "-no-desktop")) P.grab_desktop_p = False;
694       else if (!strcmp (argv[i], "-video"))      P.grab_video_p = True;
695       else if (!strcmp (argv[i], "-no-video"))   P.grab_video_p = False;
696       else if (!strcmp (argv[i], "-images"))     P.random_image_p = True;
697       else if (!strcmp (argv[i], "-no-images"))  P.random_image_p = False;
698       else if (!strcmp (argv[i], "-directory") || !strcmp (argv[i], "-dir"))
699         P.image_directory = argv[++i];
700       else if (window == 0)
701         {
702           unsigned long w;
703           char dummy;
704
705           if (!strcmp (argv[i], "-root") ||
706               !strcmp (argv[i], "root"))
707             window = RootWindowOfScreen (screen);
708
709           else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
710                     1 == sscanf (argv[i], " %ld %c",   &w, &dummy)) &&
711                    w != 0)
712             window = (Window) w;
713           else
714             {
715               if (argv[i][0] == '-')
716                 fprintf (stderr, "\n%s: unknown option \"%s\"\n",
717                          progname, argv[i]);
718               else
719                 fprintf (stderr, "\n%s: unparsable window ID: \"%s\"\n",
720                          progname, argv[i]);
721               goto LOSE;
722             }
723         }
724       else
725         {
726           fprintf (stderr, "\n%s: unknown option \"%s\"\n",
727                    progname, argv[i]);
728          LOSE:
729           fprintf (stderr, USAGE, progname);
730           exit (1);
731         }
732     }
733
734   if (window == 0)
735     {
736       fprintf (stderr, "\n%s: no window specified!\n", progname);
737       goto LOSE;
738     }
739
740
741 #ifdef DEBUG
742   if (P.verbose_p)       /* Print out all the resources we can see. */
743     {
744       XrmName name = { 0 };
745       XrmClass class = { 0 };
746       int count = 0;
747       XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
748                             (XtPointer) &count);
749     }
750 #endif /* DEBUG */
751
752   get_image (screen, window, P.verbose_p,
753              P.grab_desktop_p, P.grab_video_p, P.random_image_p,
754              P.image_directory);
755   exit (0);
756 }