~ubuntu-branches/ubuntu/dapper/xscreensaver/dapper

« back to all changes in this revision

Viewing changes to driver/xscreensaver-getimage.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-11 21:00:42 UTC
  • mfrom: (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20051011210042-u7q6zslgevdxspr3
Tags: 4.21-4ubuntu17
updated pt_BR again, fixed to UTF-8 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* xscreensaver, Copyright (c) 2001 by Jamie Zawinski <jwz@jwz.org>
 
1
/* xscreensaver, Copyright (c) 2001-2004 by Jamie Zawinski <jwz@jwz.org>
2
2
 *
3
3
 * Permission to use, copy, modify, distribute, and sell this software and its
4
4
 * documentation for any purpose is hereby granted without fee, provided that
9
9
 * implied warranty.
10
10
 */
11
11
 
12
 
/* xscreensaver-getimage -- helper program that puts an image
13
 
   (e.g., a snapshot of the desktop) onto the given window.
 
12
/* xscreensaver-getimage -- helper program that puts a random image
 
13
   onto the given window or pixmap.  That image is either a screen-grab,
 
14
   a file loaded from disk, or a frame grabbed from the system's video
 
15
   input.
14
16
 */
15
17
 
16
18
#include "utils.h"
17
19
 
18
20
#include <X11/Intrinsic.h>
 
21
#include <ctype.h>
19
22
#include <errno.h>
 
23
#include <sys/stat.h>
 
24
#include <sys/time.h>
 
25
 
 
26
#ifdef HAVE_SYS_WAIT_H
 
27
# include <sys/wait.h>          /* for waitpid() and associated macros */
 
28
#endif
 
29
 
 
30
#ifdef HAVE_XMU
 
31
# ifndef VMS
 
32
#  include <X11/Xmu/Error.h>
 
33
# else /* VMS */
 
34
#  include <Xmu/Error.h>
 
35
# endif
 
36
#else
 
37
# include "xmu.h"
 
38
#endif
20
39
 
21
40
#include "yarandom.h"
22
41
#include "grabscreen.h"
23
42
#include "resources.h"
24
43
#include "colorbars.h"
 
44
#include "visual.h"
25
45
#include "prefs.h"
 
46
#include "version.h"
26
47
#include "vroot.h"
27
48
 
 
49
#ifndef _XSCREENSAVER_VROOT_H_
 
50
# error Error!  You have an old version of vroot.h!  Check -I args.
 
51
#endif /* _XSCREENSAVER_VROOT_H_ */
 
52
 
 
53
#ifdef HAVE_GDK_PIXBUF
 
54
# undef HAVE_JPEGLIB
 
55
# ifdef HAVE_GTK2
 
56
#  include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
 
57
# else  /* !HAVE_GTK2 */
 
58
#  include <gdk-pixbuf/gdk-pixbuf-xlib.h>
 
59
# endif /* !HAVE_GTK2 */
 
60
#endif /* HAVE_GDK_PIXBUF */
 
61
 
 
62
#ifdef HAVE_JPEGLIB
 
63
# undef HAVE_GDK_PIXBUF
 
64
# include <jpeglib.h>
 
65
#endif
 
66
 
 
67
 
 
68
#ifdef __APPLE__
 
69
  /* On MacOSX / XDarwin, the usual X11 mechanism of getting a screen shot
 
70
     doesn't work, and we need to use an external program. */
 
71
# define USE_EXTERNAL_SCREEN_GRABBER
 
72
#endif
 
73
 
 
74
 
 
75
#ifdef __GNUC__
 
76
 __extension__     /* shut up about "string length is greater than the length
 
77
                      ISO C89 compilers are required to support" when including
 
78
                      the .ad file... */
 
79
#endif
28
80
 
29
81
static char *defaults[] = {
30
82
#include "../driver/XScreenSaver_ad.h"
40
92
 
41
93
extern void grabscreen_verbose (void);
42
94
 
43
 
 
44
 
#define GETIMAGE_VIDEO_PROGRAM "xscreensaver-getimage-video"
45
 
#define GETIMAGE_FILE_PROGRAM  "xscreensaver-getimage-file"
46
 
 
 
95
typedef enum {
 
96
  GRAB_DESK, GRAB_VIDEO, GRAB_FILE, GRAB_BARS
 
97
} grab_type;
 
98
 
 
99
 
 
100
#define GETIMAGE_VIDEO_PROGRAM   "xscreensaver-getimage-video"
 
101
#define GETIMAGE_FILE_PROGRAM    "xscreensaver-getimage-file"
 
102
#define GETIMAGE_SCREEN_PROGRAM  "xscreensaver-getimage-desktop"
47
103
 
48
104
const char *
49
105
blurb (void)
52
108
}
53
109
 
54
110
 
55
 
static void
56
 
exec_error (char **av)
57
 
{
58
 
  char buf [512];
59
 
  char *token;
60
 
 
61
 
  sprintf (buf, "%s: could not execute \"%s\"", progname, av[0]);
62
 
  perror (buf);
63
 
 
64
 
  if (errno == ENOENT &&
65
 
      (token = getenv("PATH")))
66
 
    {
67
 
# ifndef PATH_MAX
68
 
#  ifdef MAXPATHLEN
69
 
#   define PATH_MAX MAXPATHLEN
70
 
#  else
71
 
#   define PATH_MAX 2048
72
 
#  endif
73
 
# endif
74
 
      char path[PATH_MAX];
75
 
      fprintf (stderr, "\n");
76
 
      *path = 0;
77
 
# if defined(HAVE_GETCWD)
78
 
      getcwd (path, sizeof(path));
79
 
# elif defined(HAVE_GETWD)
80
 
      getwd (path);
81
 
# endif
82
 
      if (*path)
83
 
        fprintf (stderr, "    Current directory is: %s\n", path);
84
 
      fprintf (stderr, "    PATH is:\n");
85
 
      token = strtok (strdup(token), ":");
86
 
      while (token)
87
 
        {
88
 
          fprintf (stderr, "        %s\n", token);
89
 
          token = strtok(0, ":");
90
 
        }
91
 
      fprintf (stderr, "\n");
92
 
    }
93
 
 
 
111
static int
 
112
x_ehandler (Display *dpy, XErrorEvent *error)
 
113
{
 
114
  if (error->error_code == BadWindow || error->error_code == BadDrawable)
 
115
    {
 
116
      fprintf (stderr, "%s: target %s 0x%lx unexpectedly deleted\n", progname,
 
117
               (error->error_code == BadWindow ? "window" : "pixmap"),
 
118
               (unsigned long) error->resourceid);
 
119
    }
 
120
  else
 
121
    {
 
122
      fprintf (stderr, "\nX error in %s:\n", progname);
 
123
      XmuPrintDefaultErrorMessage (dpy, error, stderr);
 
124
    }
 
125
  exit (-1);
 
126
  return 0;
 
127
}
 
128
 
 
129
 
 
130
static Bool error_handler_hit_p = False;
 
131
 
 
132
static int
 
133
ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
 
134
{
 
135
  error_handler_hit_p = True;
 
136
  return 0;
 
137
}
 
138
 
 
139
static int
 
140
ignore_badmatch_ehandler (Display *dpy, XErrorEvent *error)
 
141
{
 
142
  if (error->error_code == BadMatch)
 
143
    return ignore_all_errors_ehandler (dpy, error);
 
144
  else
 
145
    return x_ehandler (dpy, error);
 
146
}
 
147
 
 
148
 
 
149
/* Returns True if the given Drawable is a Window; False if it's a Pixmap.
 
150
 */
 
151
static Bool
 
152
drawable_window_p (Display *dpy, Drawable d)
 
153
{
 
154
  XErrorHandler old_handler;
 
155
  XWindowAttributes xgwa;
 
156
 
 
157
  XSync (dpy, False);
 
158
  old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
 
159
  error_handler_hit_p = False;
 
160
  XGetWindowAttributes (dpy, d, &xgwa);
 
161
  XSync (dpy, False);
 
162
  XSetErrorHandler (old_handler);
 
163
  XSync (dpy, False);
 
164
 
 
165
  if (!error_handler_hit_p)
 
166
    return True;   /* It's a Window. */
 
167
  else
 
168
    return False;  /* It's a Pixmap, or an invalid ID. */
 
169
}
 
170
 
 
171
 
 
172
/* Returns true if the window is the root window, or a virtual root window,
 
173
   but *not* the xscreensaver window.  That is, if it's a "real" desktop
 
174
   root window of some kind.
 
175
 */
 
176
static Bool
 
177
root_window_p (Screen *screen, Window window)
 
178
{
 
179
  Display *dpy = DisplayOfScreen (screen);
 
180
  Atom type;
 
181
  int format;
 
182
  unsigned long nitems, bytesafter;
 
183
  unsigned char *version;
 
184
 
 
185
  if (window != RootWindowOfScreen (screen))
 
186
    return False;
 
187
 
 
188
  if (XGetWindowProperty (dpy, window,
 
189
                          XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
 
190
                          0, 1, False, XA_STRING,
 
191
                          &type, &format, &nitems, &bytesafter,
 
192
                          &version)
 
193
      == Success
 
194
      && type != None)
 
195
    return False;
 
196
 
 
197
  return True;
 
198
}
 
199
 
 
200
 
 
201
/* Clear the window or pixmap to black, or its background color.
 
202
 */
 
203
static void
 
204
clear_drawable (Screen *screen, Drawable drawable)
 
205
{
 
206
  Display *dpy = DisplayOfScreen (screen);
 
207
  XGCValues gcv;
 
208
  GC gc;
 
209
  Window root;
 
210
  int x, y;
 
211
  unsigned int w, h, bw, d;
 
212
  XGetGeometry (dpy, drawable, &root, &x, &y, &w, &h, &bw, &d);
 
213
 
 
214
  /* The window might have no-op background of None, so to clear it,
 
215
     draw a black rectangle first, then do XClearWindow (in case the
 
216
     actual background color is non-black...) */
 
217
 
 
218
  /* #### really we should allocate "black" instead, but I'm lazy... */
 
219
  gcv.foreground = BlackPixelOfScreen (screen);
 
220
  gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
 
221
  XFillRectangle (dpy, drawable, gc, 0, 0, w, h);
 
222
  XFreeGC (dpy, gc);
 
223
  if (drawable_window_p (dpy, drawable))
 
224
    XClearWindow (dpy, (Window) drawable);
 
225
  XFlush (dpy);
 
226
}
 
227
 
 
228
 
 
229
/* Figure out what kind of scaling/positioning we ought to do to display
 
230
   a src-sized image in a dest-sized window/pixmap.  Returns the width
 
231
   and height to which the image should be scaled, and the position where
 
232
   it should be displayed to center it.
 
233
 */
 
234
static void
 
235
compute_image_scaling (int src_w, int src_h,
 
236
                       int dest_w, int dest_h,
 
237
                       Bool verbose_p,
 
238
                       int *scaled_from_x_ret, int *scaled_from_y_ret,
 
239
                       int *scaled_to_x_ret, int *scaled_to_y_ret,
 
240
                       int *scaled_w_ret, int *scaled_h_ret)
 
241
{
 
242
  int srcx, srcy, destx, desty;
 
243
 
 
244
  Bool exact_fit_p = ((src_w == dest_w && src_h <= dest_h) ||
 
245
                      (src_h == dest_h && src_w <= dest_w));
 
246
 
 
247
  if (!exact_fit_p)  /* scale the image up or down */
 
248
    {
 
249
      float rw = (float) dest_w  / src_w;
 
250
      float rh = (float) dest_h / src_h;
 
251
      float r = (rw < rh ? rw : rh);
 
252
      int tw = src_w * r;
 
253
      int th = src_h * r;
 
254
      int pct = (r * 100);
 
255
 
 
256
#if 0
 
257
      /* this optimization breaks things */
 
258
      if (pct < 95 || pct > 105)  /* don't scale if it's close */
 
259
#endif
 
260
        {
 
261
          if (verbose_p)
 
262
            fprintf (stderr, "%s: scaling image by %d%% (%dx%d -> %dx%d)\n",
 
263
                     progname, pct, src_w, src_h, tw, th);
 
264
          src_w = tw;
 
265
          src_h = th;
 
266
        }
 
267
    }
 
268
 
 
269
  /* Center the image on the window/pixmap. */
 
270
  srcx = 0;
 
271
  srcy = 0;
 
272
  destx = (dest_w - src_w) / 2;
 
273
  desty = (dest_h - src_h) / 2;
 
274
  if (destx < 0) srcx = -destx, destx = 0;
 
275
  if (desty < 0) srcy = -desty, desty = 0;
 
276
 
 
277
  if (dest_w < src_w) src_w = dest_w;
 
278
  if (dest_h < src_h) src_h = dest_h;
 
279
 
 
280
  *scaled_w_ret = src_w;
 
281
  *scaled_h_ret = src_h;
 
282
  *scaled_from_x_ret = srcx;
 
283
  *scaled_from_y_ret = srcy;
 
284
  *scaled_to_x_ret = destx;
 
285
  *scaled_to_y_ret = desty;
 
286
 
 
287
  if (verbose_p)
 
288
    fprintf (stderr, "%s: displaying %dx%d image at %d,%d in %dx%d.\n",
 
289
             progname, src_w, src_h, destx, desty, dest_w, dest_h);
 
290
}
 
291
 
 
292
 
 
293
/* Scales an XImage, modifying it in place.
 
294
   This doesn't do dithering or smoothing, so it might have artifacts.
 
295
   If out of memory, returns False, and the XImage will have been
 
296
   destroyed and freed.
 
297
 */
 
298
static Bool
 
299
scale_ximage (Screen *screen, Visual *visual,
 
300
              XImage *ximage, int new_width, int new_height)
 
301
{
 
302
  Display *dpy = DisplayOfScreen (screen);
 
303
  int depth = visual_depth (screen, visual);
 
304
  int x, y;
 
305
  double xscale, yscale;
 
306
 
 
307
  XImage *ximage2 = XCreateImage (dpy, visual, depth,
 
308
                                  ZPixmap, 0, 0,
 
309
                                  new_width, new_height, 8, 0);
 
310
  ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
 
311
 
 
312
  if (!ximage2->data)
 
313
    {
 
314
      fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
 
315
               progname,
 
316
               ximage->width, ximage->height,
 
317
               ximage2->width, ximage2->height);
 
318
      if (ximage->data) free (ximage->data);
 
319
      if (ximage2->data) free (ximage2->data);
 
320
      ximage->data = 0;
 
321
      ximage2->data = 0;
 
322
      XDestroyImage (ximage);
 
323
      XDestroyImage (ximage2);
 
324
      return False;
 
325
    }
 
326
 
 
327
  /* Brute force scaling... */
 
328
  xscale = (double) ximage->width  / ximage2->width;
 
329
  yscale = (double) ximage->height / ximage2->height;
 
330
  for (y = 0; y < ximage2->height; y++)
 
331
    for (x = 0; x < ximage2->width; x++)
 
332
      XPutPixel (ximage2, x, y,
 
333
                 XGetPixel (ximage, x * xscale, y * yscale));
 
334
 
 
335
  free (ximage->data);
 
336
  ximage->data = 0;
 
337
 
 
338
  (*ximage) = (*ximage2);
 
339
 
 
340
  ximage2->data = 0;
 
341
  XDestroyImage (ximage2);
 
342
 
 
343
  return True;
 
344
}
 
345
 
 
346
 
 
347
#ifdef HAVE_GDK_PIXBUF
 
348
 
 
349
/* Reads the given image file and renders it on the Drawable, using GDK.
 
350
   Returns False if it fails.
 
351
 */
 
352
static Bool
 
353
read_file_gdk (Screen *screen, Window window, Drawable drawable,
 
354
               const char *filename, Bool verbose_p,
 
355
               XRectangle *geom_ret)
 
356
{
 
357
  GdkPixbuf *pb;
 
358
  Display *dpy = DisplayOfScreen (screen);
 
359
  unsigned int win_width, win_height, win_depth;
 
360
# ifdef HAVE_GTK2
 
361
  GError *gerr = 0;
 
362
# endif /* HAVE_GTK2 */
 
363
 
 
364
  /* Find the size of the Drawable. */
 
365
  {
 
366
    Window root;
 
367
    int x, y;
 
368
    unsigned int bw;
 
369
    XGetGeometry (dpy, drawable,
 
370
                  &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
 
371
  }
 
372
 
 
373
  gdk_pixbuf_xlib_init (dpy, screen_number (screen));
 
374
# ifdef HAVE_GTK2
 
375
  g_type_init();
 
376
# else  /* !HAVE_GTK2 */
 
377
  xlib_rgb_init (dpy, screen);
 
378
# endif /* !HAVE_GTK2 */
 
379
 
 
380
  pb = gdk_pixbuf_new_from_file (filename
 
381
# ifdef HAVE_GTK2
 
382
                                 , &gerr
 
383
# endif /* HAVE_GTK2 */
 
384
                                 );
 
385
 
 
386
  if (!pb)
 
387
    {
 
388
      fprintf (stderr, "%s: unable to load \"%s\"\n", progname, filename);
 
389
#  ifdef HAVE_GTK2
 
390
      if (gerr && gerr->message && *gerr->message)
 
391
        fprintf (stderr, "%s: reason: %s\n", progname, gerr->message);
 
392
#  endif /* HAVE_GTK2 */
 
393
      return False;
 
394
    }
 
395
  else
 
396
    {
 
397
      int w = gdk_pixbuf_get_width (pb);
 
398
      int h = gdk_pixbuf_get_height (pb);
 
399
      int srcx, srcy, destx, desty, w2, h2;
 
400
      Bool bg_p = False;
 
401
 
 
402
      compute_image_scaling (w, h, win_width, win_height, verbose_p,
 
403
                             &srcx, &srcy, &destx, &desty, &w2, &h2);
 
404
      if (w != w2 || h != h2)
 
405
        {
 
406
          GdkPixbuf *pb2 = gdk_pixbuf_scale_simple (pb, w2, h2,
 
407
                                                    GDK_INTERP_BILINEAR);
 
408
          if (pb2)
 
409
            {
 
410
              gdk_pixbuf_unref (pb);
 
411
              pb = pb2;
 
412
              w = w2;
 
413
              h = h2;
 
414
            }
 
415
          else
 
416
            fprintf (stderr, "%s: out of memory when scaling?\n", progname);
 
417
        }
 
418
 
 
419
      /* If we're rendering onto the root window (and it's not the
 
420
         xscreensaver pseudo-root) then put the image in the window's
 
421
         background.  Otherwise, just paint the image onto the window.
 
422
       */
 
423
      bg_p = (window == drawable && root_window_p (screen, window));
 
424
 
 
425
      if (bg_p)
 
426
        {
 
427
          XGCValues gcv;
 
428
          GC gc;
 
429
          drawable = XCreatePixmap (dpy, window,
 
430
                                    win_width, win_height, win_depth);
 
431
          gcv.foreground = BlackPixelOfScreen (screen);
 
432
          gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
 
433
          XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
 
434
          XFreeGC (dpy, gc);
 
435
        }
 
436
      else
 
437
        clear_drawable (screen, drawable);
 
438
 
 
439
      /* #### Note that this always uses the default colormap!  Morons!
 
440
         Owen says that in Gnome 2.0, I should try using
 
441
         gdk_pixbuf_render_pixmap_and_mask_for_colormap() instead.
 
442
         But I haven't tried.
 
443
       */
 
444
      gdk_pixbuf_xlib_render_to_drawable_alpha (pb, drawable,
 
445
                                                srcx, srcy, destx, desty,
 
446
                                                w, h,
 
447
                                                GDK_PIXBUF_ALPHA_FULL, 127,
 
448
                                                XLIB_RGB_DITHER_NORMAL,
 
449
                                                0, 0);
 
450
      if (bg_p)
 
451
        {
 
452
          XSetWindowBackgroundPixmap (dpy, window, drawable);
 
453
          XClearWindow (dpy, window);
 
454
        }
 
455
 
 
456
      if (geom_ret)
 
457
        {
 
458
          geom_ret->x = destx;
 
459
          geom_ret->y = desty;
 
460
          geom_ret->width  = w;
 
461
          geom_ret->height = h;
 
462
        }
 
463
    }
 
464
 
 
465
  XSync (dpy, False);
 
466
  return True;
 
467
}
 
468
 
 
469
#endif /* HAVE_GDK_PIXBUF */
 
470
 
 
471
 
 
472
 
 
473
#ifdef HAVE_JPEGLIB
 
474
 
 
475
/* Allocates a colormap that makes a PseudoColor or DirectColor
 
476
   visual behave like a TrueColor visual of the same depth.
 
477
 */
 
478
static void
 
479
allocate_cubic_colormap (Screen *screen, Visual *visual, Colormap cmap,
 
480
                         Bool verbose_p)
 
481
{
 
482
  Display *dpy = DisplayOfScreen (screen);
 
483
  int nr, ng, nb, cells;
 
484
  int r, g, b;
 
485
  int depth;
 
486
  XColor colors[4097];
 
487
  int i;
 
488
 
 
489
  depth = visual_depth (screen, visual);
 
490
 
 
491
  switch (depth)
 
492
    {
 
493
    case 8:  nr = 3; ng = 3; nb = 2; cells = 256;  break;
 
494
    case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
 
495
    default: abort(); break;
 
496
    }
 
497
 
 
498
  memset(colors, 0, sizeof(colors));
 
499
  for (r = 0; r < (1 << nr); r++)
 
500
    for (g = 0; g < (1 << ng); g++)
 
501
      for (b = 0; b < (1 << nb); b++)
 
502
        {
 
503
          i = (r | (g << nr) | (b << (nr + ng)));
 
504
          colors[i].pixel = i;
 
505
          colors[i].flags = DoRed|DoGreen|DoBlue;
 
506
          if (depth == 8)
 
507
            {
 
508
              colors[i].red   = ((r << 13) | (r << 10) | (r << 7) |
 
509
                                 (r <<  4) | (r <<  1));
 
510
              colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
 
511
                                 (g <<  4) | (g <<  1));
 
512
              colors[i].blue  = ((b << 14) | (b << 12) | (b << 10) |
 
513
                                 (b <<  8) | (b <<  6) | (b <<  4) |
 
514
                                 (b <<  2) | b);
 
515
            }
 
516
          else
 
517
            {
 
518
              colors[i].red   = (r << 12) | (r << 8) | (r << 4) | r;
 
519
              colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
 
520
              colors[i].blue  = (b << 12) | (b << 8) | (b << 4) | b;
 
521
            }
 
522
        }
 
523
 
 
524
  {
 
525
    int j;
 
526
    int allocated = 0;
 
527
    int interleave = cells / 8;  /* skip around, rather than allocating in
 
528
                                    order, so that we get better coverage if
 
529
                                    we can't allocated all of them. */
 
530
    for (j = 0; j < interleave; j++)
 
531
      for (i = 0; i < cells; i += interleave)
 
532
        if (XAllocColor (dpy, cmap, &colors[i + j]))
 
533
          allocated++;
 
534
 
 
535
    if (verbose_p)
 
536
      fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
 
537
               progname, allocated, cells);
 
538
  }
 
539
}
 
540
 
 
541
/* Find the pixel index that is closest to the given color
 
542
   (using linear distance in RGB space -- which is far from the best way.)
 
543
 */
 
544
static unsigned long
 
545
find_closest_pixel (XColor *colors, int ncolors,
 
546
                    unsigned long r, unsigned long g, unsigned long b)
 
547
{
 
548
  unsigned long distance = ~0;
 
549
  int i, found = 0;
 
550
 
 
551
  if (ncolors == 0)
 
552
    abort();
 
553
  for (i = 0; i < ncolors; i++)
 
554
    {
 
555
      unsigned long d;
 
556
      int rd, gd, bd;
 
557
 
 
558
      rd = r - colors[i].red;
 
559
      gd = g - colors[i].green;
 
560
      bd = b - colors[i].blue;
 
561
      if (rd < 0) rd = -rd;
 
562
      if (gd < 0) gd = -gd;
 
563
      if (bd < 0) bd = -bd;
 
564
      d = (rd << 1) + (gd << 2) + bd;
 
565
      
 
566
      if (d < distance)
 
567
        {
 
568
          distance = d;
 
569
          found = i;
 
570
          if (distance == 0)
 
571
              break;
 
572
        }
 
573
    }
 
574
 
 
575
  return found;
 
576
}
 
577
 
 
578
 
 
579
/* Given an XImage with 8-bit or 12-bit RGB data, convert it to be 
 
580
   displayable with the given X colormap.  The farther from a perfect
 
581
   color cube the contents of the colormap are, the lossier the 
 
582
   transformation will be.  No dithering is done.
 
583
 */
 
584
static void
 
585
remap_image (Screen *screen, Colormap cmap, XImage *image, Bool verbose_p)
 
586
{
 
587
  Display *dpy = DisplayOfScreen (screen);
 
588
  unsigned long map[4097];
 
589
  int x, y, i;
 
590
  int cells;
 
591
  XColor colors[4097];
 
592
 
 
593
  if (image->depth == 8)
 
594
    cells = 256;
 
595
  else if (image->depth == 12)
 
596
    cells = 4096;
 
597
  else
 
598
    abort();
 
599
 
 
600
  memset(map,    -1, sizeof(*map));
 
601
  memset(colors, -1, sizeof(*colors));
 
602
 
 
603
  for (i = 0; i < cells; i++)
 
604
    colors[i].pixel = i;
 
605
  XQueryColors (dpy, cmap, colors, cells);
 
606
 
 
607
  if (verbose_p)
 
608
    fprintf(stderr, "%s: building color cube for %d bit image\n",
 
609
            progname, image->depth);
 
610
 
 
611
  for (i = 0; i < cells; i++)
 
612
    {
 
613
      unsigned short r, g, b;
 
614
 
 
615
      if (cells == 256)
 
616
        {
 
617
          /* "RRR GGG BB" In an 8 bit map.  Convert that to
 
618
             "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
 
619
             an even spread. */
 
620
          r = (i & 0x07);
 
621
          g = (i & 0x38) >> 3;
 
622
          b = (i & 0xC0) >> 6;
 
623
 
 
624
          r = ((r << 13) | (r << 10) | (r << 7) | (r <<  4) | (r <<  1));
 
625
          g = ((g << 13) | (g << 10) | (g << 7) | (g <<  4) | (g <<  1));
 
626
          b = ((b << 14) | (b << 12) | (b << 10) | (b <<  8) |
 
627
               (b <<  6) | (b <<  4) | (b <<  2) | b);
 
628
        }
 
629
      else
 
630
        {
 
631
          /* "RRRR GGGG BBBB" In a 12 bit map.  Convert that to
 
632
             "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
 
633
             spread. */
 
634
          r = (i & 0x00F);
 
635
          g = (i & 0x0F0) >> 4;
 
636
          b = (i & 0xF00) >> 8;
 
637
 
 
638
          r = (r << 12) | (r << 8) | (r << 4) | r;
 
639
          g = (g << 12) | (g << 8) | (g << 4) | g;
 
640
          b = (b << 12) | (b << 8) | (b << 4) | b;
 
641
        }
 
642
 
 
643
      map[i] = find_closest_pixel (colors, cells, r, g, b);
 
644
    }
 
645
 
 
646
  if (verbose_p)
 
647
    fprintf(stderr, "%s: remapping colors in %d bit image\n",
 
648
            progname, image->depth);
 
649
 
 
650
  for (y = 0; y < image->height; y++)
 
651
    for (x = 0; x < image->width; x++)
 
652
      {
 
653
        unsigned long pixel = XGetPixel(image, x, y);
 
654
        if (pixel >= cells) abort();
 
655
        XPutPixel(image, x, y, map[pixel]);
 
656
      }
 
657
}
 
658
 
 
659
 
 
660
/* If the file has a PPM (P6) on it, read it and return an XImage.
 
661
   Otherwise, rewind the fd back to the beginning, and return 0.
 
662
 */
 
663
static XImage *
 
664
maybe_read_ppm (Screen *screen, Visual *visual,
 
665
                const char *filename, FILE *in, Bool verbose_p)
 
666
{
 
667
  Display *dpy = DisplayOfScreen (screen);
 
668
  int depth = visual_depth (screen, visual);
 
669
  struct stat st;
 
670
  char *buf = 0;
 
671
  int bufsiz = 0;
 
672
  char *s, dummy;
 
673
  int i, j;
 
674
  int x, y, w, h, maxval;
 
675
  XImage *ximage = 0;
 
676
 
 
677
  if (fstat (fileno (in), &st))
 
678
    goto FAIL;
 
679
 
 
680
  bufsiz = st.st_size;
 
681
  buf = (char *) malloc (bufsiz + 1);
 
682
  if (!buf)
 
683
    {
 
684
      fprintf (stderr, "%s: out of memory loading %d byte PPM file %s\n",
 
685
               progname, bufsiz, filename);
 
686
      goto FAIL;
 
687
    }
 
688
 
 
689
  if (! (s = fgets (buf, bufsiz, in)))   /* line 1 */
 
690
    goto FAIL;
 
691
 
 
692
  if (!strncmp (buf, "\107\111", 2))
 
693
    {
 
694
      fprintf (stderr, "%s: %s: sorry, GIF files not supported"
 
695
               " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
 
696
               progname, filename);
 
697
      goto FAIL;
 
698
    }
 
699
  else if (!strncmp (buf, "\211\120", 2))
 
700
    {
 
701
      fprintf (stderr, "%s: %s: sorry, PNG files not supported"
 
702
               " when compiled with JPEGlib instead of GDK_Pixbuf.\n",
 
703
               progname, filename);
 
704
      goto FAIL;
 
705
    }
 
706
 
 
707
  if (strncmp (s, "P6", 2))
 
708
    goto FAIL;
 
709
 
 
710
  if (! (s = fgets (buf, bufsiz, in)))   /* line 2 */
 
711
    goto FAIL;
 
712
  if (2 != sscanf (s, " %d %d %c", &w, &h, &dummy))
 
713
    {
 
714
      fprintf (stderr, "%s: %s: invalid PPM (line 2)\n", progname, filename);
 
715
      goto FAIL;
 
716
    }
 
717
 
 
718
  if (! (s = fgets (buf, bufsiz, in)))   /* line 3 */
 
719
    goto FAIL;
 
720
  if (1 != sscanf (s, " %d %c", &maxval, &dummy))
 
721
    {
 
722
      fprintf (stderr, "%s: %s: invalid PPM (line 3)\n", progname, filename);
 
723
      goto FAIL;
 
724
    }
 
725
  if (maxval != 255)
 
726
    {
 
727
      fprintf (stderr, "%s: %s: unparsable PPM: maxval is %d\n",
 
728
               progname, filename, maxval);
 
729
      goto FAIL;
 
730
    }
 
731
 
 
732
  ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
 
733
                         w, h, 8, 0);
 
734
  if (ximage)
 
735
    ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
 
736
  if (!ximage || !ximage->data)
 
737
    {
 
738
      fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
 
739
               progname, ximage->width, ximage->height, filename);
 
740
      goto FAIL;
 
741
    }
 
742
 
 
743
  s = buf;
 
744
  j = bufsiz;
 
745
  while ((i = fread (s, 1, j, in)) > 0)
 
746
    s += i, j -= i;
 
747
 
 
748
  i = 0;
 
749
  for (y = 0; y < ximage->height; y++)
 
750
    for (x = 0; x < ximage->width; x++)
 
751
      {
 
752
        unsigned char r = buf[i++];
 
753
        unsigned char g = buf[i++];
 
754
        unsigned char b = buf[i++];
 
755
        unsigned long pixel;
 
756
 
 
757
        if (depth > 16)
 
758
          pixel = (r << 16) | (g << 8) | b;
 
759
        else if (depth == 8)
 
760
          pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
 
761
        else if (depth == 12)
 
762
          pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
 
763
        else if (depth == 16 || depth == 15)
 
764
          pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
 
765
        else
 
766
          abort();
 
767
 
 
768
        XPutPixel (ximage, x, y, pixel);
 
769
      }
 
770
 
 
771
  free (buf);
 
772
  return ximage;
 
773
 
 
774
 FAIL:
 
775
  if (buf) free (buf);
 
776
  if (ximage && ximage->data)
 
777
    {
 
778
      free (ximage->data);
 
779
      ximage->data = 0;
 
780
    }
 
781
  if (ximage) XDestroyImage (ximage);
 
782
  fseek (in, 0, SEEK_SET);
 
783
  return 0;
 
784
}
 
785
 
 
786
 
 
787
typedef struct {
 
788
  struct jpeg_error_mgr pub;   /* this is what passes for subclassing in C */
 
789
  const char *filename;
 
790
  Screen *screen;
 
791
  Visual *visual;
 
792
  Drawable drawable;
 
793
  Colormap cmap;
 
794
} getimg_jpg_error_mgr;
 
795
 
 
796
 
 
797
static void
 
798
jpg_output_message (j_common_ptr cinfo)
 
799
{
 
800
  getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
 
801
  char buf[JMSG_LENGTH_MAX];
 
802
  cinfo->err->format_message (cinfo, buf);
 
803
  fprintf (stderr, "%s: %s: %s\n", progname, err->filename, buf);
 
804
}
 
805
 
 
806
 
 
807
static void
 
808
jpg_error_exit (j_common_ptr cinfo)
 
809
{
 
810
  getimg_jpg_error_mgr *err = (getimg_jpg_error_mgr *) cinfo->err;
 
811
  cinfo->err->output_message (cinfo);
 
812
  draw_colorbars (err->screen, err->visual, err->drawable, err->cmap,
 
813
                  0, 0, 0, 0);
 
814
  XSync (DisplayOfScreen (err->screen), False);
94
815
  exit (1);
95
816
}
96
817
 
97
818
 
 
819
/* Reads a JPEG file, returns an RGB XImage of it.
 
820
 */
 
821
static XImage *
 
822
read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable,
 
823
                  Colormap cmap, const char *filename, Bool verbose_p)
 
824
{
 
825
  Display *dpy = DisplayOfScreen (screen);
 
826
  int depth = visual_depth (screen, visual);
 
827
 
 
828
  FILE *in = 0;
 
829
  XImage *ximage = 0;
 
830
  struct jpeg_decompress_struct cinfo;
 
831
  getimg_jpg_error_mgr jerr;
 
832
  JSAMPARRAY scanbuf = 0;
 
833
  int y;
 
834
 
 
835
  jerr.filename = filename;
 
836
  jerr.screen = screen;
 
837
  jerr.visual = visual;
 
838
  jerr.drawable = drawable;
 
839
  jerr.cmap = cmap;
 
840
 
 
841
  if (! (depth >= 15 || depth == 12 || depth == 8))
 
842
    {
 
843
      fprintf (stderr, "%s: unsupported depth: %d\n", progname, depth);
 
844
      goto FAIL;
 
845
    }
 
846
 
 
847
  in = fopen (filename, "rb");
 
848
  if (!in)
 
849
    {
 
850
      fprintf (stderr, "%s: %s: unreadable\n", progname, filename);
 
851
      goto FAIL;
 
852
    }
 
853
 
 
854
  /* Check to see if it's a PPM, and if so, read that instead of using
 
855
     the JPEG library.  Yeah, this is all modular and stuff.
 
856
   */
 
857
  if ((ximage = maybe_read_ppm (screen, visual, filename, in, verbose_p)))
 
858
    {
 
859
      fclose (in);
 
860
      return ximage;
 
861
    }
 
862
 
 
863
  cinfo.err = jpeg_std_error (&jerr.pub);
 
864
  jerr.pub.output_message = jpg_output_message;
 
865
  jerr.pub.error_exit = jpg_error_exit;
 
866
 
 
867
  jpeg_create_decompress (&cinfo);
 
868
  jpeg_stdio_src (&cinfo, in);
 
869
  jpeg_read_header (&cinfo, TRUE);
 
870
 
 
871
  /* set some decode parameters */
 
872
  cinfo.out_color_space = JCS_RGB;
 
873
  cinfo.quantize_colors = FALSE;
 
874
 
 
875
  jpeg_start_decompress (&cinfo);
 
876
 
 
877
  ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
 
878
                         cinfo.output_width, cinfo.output_height,
 
879
                         8, 0);
 
880
  if (ximage)
 
881
    ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
 
882
 
 
883
  if (ximage && ximage->data)
 
884
    scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
 
885
                                          cinfo.rec_outbuf_height *
 
886
                                          cinfo.output_width *
 
887
                                          cinfo.output_components,
 
888
                                          1);
 
889
  if (!ximage || !ximage->data || !scanbuf)
 
890
    {
 
891
      fprintf (stderr, "%s: out of memory loading %dx%d file %s\n",
 
892
               progname, ximage->width, ximage->height, filename);
 
893
      goto FAIL;
 
894
    }
 
895
 
 
896
  y = 0;
 
897
  while (cinfo.output_scanline < cinfo.output_height)
 
898
    {
 
899
      int n = jpeg_read_scanlines (&cinfo, scanbuf, 1);
 
900
      int i;
 
901
      for (i = 0; i < n; i++)
 
902
        {
 
903
          int x;
 
904
          for (x = 0; x < ximage->width; x++)
 
905
            {
 
906
              int j = x * cinfo.output_components;
 
907
              unsigned char r = scanbuf[i][j];
 
908
              unsigned char g = scanbuf[i][j+1];
 
909
              unsigned char b = scanbuf[i][j+2];
 
910
              unsigned long pixel;
 
911
 
 
912
              if (depth > 16)
 
913
                pixel = (r << 16) | (g << 8) | b;
 
914
              else if (depth == 8)
 
915
                pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
 
916
              else if (depth == 12)
 
917
                pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
 
918
              else if (depth == 15)
 
919
                /* Gah! I don't understand why these are in the other
 
920
                   order. */
 
921
                pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
 
922
              else if (depth == 16)
 
923
                pixel = (((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3)));
 
924
              else
 
925
                abort();
 
926
 
 
927
              XPutPixel (ximage, x, y, pixel);
 
928
            }
 
929
          y++;
 
930
        }
 
931
    }
 
932
 
 
933
  if (cinfo.output_scanline < cinfo.output_height)
 
934
    /* don't goto FAIL -- we might have viewable partial data. */
 
935
    jpeg_abort_decompress (&cinfo);
 
936
  else
 
937
    jpeg_finish_decompress (&cinfo);
 
938
 
 
939
  jpeg_destroy_decompress (&cinfo);
 
940
  fclose (in);
 
941
  in = 0;
 
942
 
 
943
  return ximage;
 
944
 
 
945
 FAIL:
 
946
  if (in) fclose (in);
 
947
  if (ximage && ximage->data)
 
948
    {
 
949
      free (ximage->data);
 
950
      ximage->data = 0;
 
951
    }
 
952
  if (ximage) XDestroyImage (ximage);
 
953
  if (scanbuf) free (scanbuf);
 
954
  return 0;
 
955
}
 
956
 
 
957
 
 
958
/* Reads the given image file and renders it on the Drawable, using JPEG lib.
 
959
   Returns False if it fails.
 
960
 */
 
961
static Bool
 
962
read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
 
963
                   const char *filename, Bool verbose_p,
 
964
                   XRectangle *geom_ret)
 
965
{
 
966
  Display *dpy = DisplayOfScreen (screen);
 
967
  XImage *ximage;
 
968
  Visual *visual;
 
969
  int class, depth;
 
970
  Colormap cmap;
 
971
  unsigned int win_width, win_height, win_depth;
 
972
  int srcx, srcy, destx, desty, w2, h2;
 
973
 
 
974
  /* Find the size of the Drawable, and the Visual/Colormap of the Window. */
 
975
  {
 
976
    Window root;
 
977
    int x, y;
 
978
    unsigned int bw;
 
979
    XWindowAttributes xgwa;
 
980
    XGetWindowAttributes (dpy, window, &xgwa);
 
981
    visual = xgwa.visual;
 
982
    cmap = xgwa.colormap;
 
983
    XGetGeometry (dpy, drawable,
 
984
                  &root, &x, &y, &win_width, &win_height, &bw, &win_depth);
 
985
  }
 
986
 
 
987
  /* Make sure we're not on some weirdo visual...
 
988
   */
 
989
  class = visual_class (screen, visual);
 
990
  depth = visual_depth (screen, visual);
 
991
  if ((class == PseudoColor || class == DirectColor) &&
 
992
      (depth != 8 && depth != 12))
 
993
    {
 
994
      fprintf (stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
 
995
               progname, depth);
 
996
      return False;
 
997
    }
 
998
 
 
999
  /* Read the file...
 
1000
   */
 
1001
  ximage = read_jpeg_ximage (screen, visual, drawable, cmap,
 
1002
                             filename, verbose_p);
 
1003
  if (!ximage) return False;
 
1004
 
 
1005
  /* Scale it, if necessary...
 
1006
   */
 
1007
  compute_image_scaling (ximage->width, ximage->height,
 
1008
                         win_width, win_height, verbose_p,
 
1009
                         &srcx, &srcy, &destx, &desty, &w2, &h2);
 
1010
  if (ximage->width != w2 || ximage->height != h2)
 
1011
    if (! scale_ximage (screen, visual, ximage, w2, h2))
 
1012
      return False;
 
1013
 
 
1014
  /* Allocate a colormap, if we need to...
 
1015
   */
 
1016
  if (class == PseudoColor || class == DirectColor)
 
1017
    {
 
1018
      allocate_cubic_colormap (screen, visual, cmap, verbose_p);
 
1019
      remap_image (screen, cmap, ximage, verbose_p);
 
1020
    }
 
1021
 
 
1022
  /* Finally, put the resized image on the window.
 
1023
   */
 
1024
  {
 
1025
    GC gc;
 
1026
    XGCValues gcv;
 
1027
 
 
1028
    /* If we're rendering onto the root window (and it's not the xscreensaver
 
1029
       pseudo-root) then put the image in the window's background.  Otherwise,
 
1030
       just paint the image onto the window.
 
1031
     */
 
1032
    if (window == drawable && root_window_p (screen, window))
 
1033
      {
 
1034
        Pixmap bg = XCreatePixmap (dpy, window,
 
1035
                                   win_width, win_height, win_depth);
 
1036
        gcv.foreground = BlackPixelOfScreen (screen);
 
1037
        gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
 
1038
        XFillRectangle (dpy, bg, gc, 0, 0, win_width, win_height);
 
1039
        XPutImage (dpy, bg, gc, ximage,
 
1040
                   srcx, srcy, destx, desty, ximage->width, ximage->height);
 
1041
        XSetWindowBackgroundPixmap (dpy, window, bg);
 
1042
        XClearWindow (dpy, window);
 
1043
      }
 
1044
    else
 
1045
      {
 
1046
        gc = XCreateGC (dpy, drawable, 0, &gcv);
 
1047
        clear_drawable (screen, drawable);
 
1048
        XPutImage (dpy, drawable, gc, ximage,
 
1049
                   srcx, srcy, destx, desty, ximage->width, ximage->height);
 
1050
      }
 
1051
 
 
1052
    XFreeGC (dpy, gc);
 
1053
  }
 
1054
 
 
1055
  if (geom_ret)
 
1056
    {
 
1057
      geom_ret->x = destx;
 
1058
      geom_ret->y = desty;
 
1059
      geom_ret->width  = ximage->width;
 
1060
      geom_ret->height = ximage->height;
 
1061
    }
 
1062
 
 
1063
  free (ximage->data);
 
1064
  ximage->data = 0;
 
1065
  XDestroyImage (ximage);
 
1066
  XSync (dpy, False);
 
1067
  return True;
 
1068
}
 
1069
 
 
1070
#endif /* HAVE_JPEGLIB */
 
1071
 
 
1072
 
 
1073
/* Reads the given image file and renders it on the Drawable.
 
1074
   Returns False if it fails.
 
1075
 */
 
1076
static Bool
 
1077
display_file (Screen *screen, Window window, Drawable drawable,
 
1078
              const char *filename, Bool verbose_p,
 
1079
              XRectangle *geom_ret)
 
1080
{
 
1081
  if (verbose_p)
 
1082
    fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
 
1083
 
 
1084
# if defined(HAVE_GDK_PIXBUF)
 
1085
  if (read_file_gdk (screen, window, drawable, filename, verbose_p, geom_ret))
 
1086
    return True;
 
1087
# elif defined(HAVE_JPEGLIB)
 
1088
  if (read_file_jpeglib (screen, window, drawable, filename, verbose_p,
 
1089
                         geom_ret))
 
1090
    return True;
 
1091
# else  /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
 
1092
  /* shouldn't get here if we have no image-loading methods available. */
 
1093
  abort();
 
1094
# endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
 
1095
 
 
1096
  return False;
 
1097
}
 
1098
 
 
1099
 
 
1100
/* Invokes a sub-process and returns its output (presumably, a file to
 
1101
   load.)  Free the string when done.  'grab_type' controls which program
 
1102
   to run.
 
1103
 */
 
1104
static char *
 
1105
get_filename_1 (Screen *screen, const char *directory, grab_type type,
 
1106
                Bool verbose_p)
 
1107
{
 
1108
  Display *dpy = DisplayOfScreen (screen);
 
1109
  pid_t forked;
 
1110
  int fds [2];
 
1111
  int in, out;
 
1112
  char buf[1024];
 
1113
  char *av[20];
 
1114
  int ac = 0;
 
1115
 
 
1116
  switch (type)
 
1117
    {
 
1118
    case GRAB_FILE:
 
1119
      av[ac++] = GETIMAGE_FILE_PROGRAM;
 
1120
      if (verbose_p)
 
1121
        av[ac++] = "--verbose";
 
1122
      av[ac++] = "--name";
 
1123
      av[ac++] = (char *) directory;
 
1124
      break;
 
1125
 
 
1126
    case GRAB_VIDEO:
 
1127
      av[ac++] = GETIMAGE_VIDEO_PROGRAM;
 
1128
      if (verbose_p)
 
1129
        av[ac++] = "--verbose";
 
1130
      av[ac++] = "--name";
 
1131
      break;
 
1132
 
 
1133
# ifdef USE_EXTERNAL_SCREEN_GRABBER
 
1134
    case GRAB_DESK:
 
1135
      av[ac++] = GETIMAGE_SCREEN_PROGRAM;
 
1136
      if (verbose_p)
 
1137
        av[ac++] = "--verbose";
 
1138
      av[ac++] = "--name";
 
1139
      break;
 
1140
# endif
 
1141
 
 
1142
    default:
 
1143
      abort();
 
1144
    }
 
1145
  av[ac] = 0;
 
1146
 
 
1147
  if (verbose_p)
 
1148
    {
 
1149
      int i;
 
1150
      fprintf (stderr, "%s: executing:", progname);
 
1151
      for (i = 0; i < ac; i++)
 
1152
        fprintf (stderr, " %s", av[i]);
 
1153
      fprintf (stderr, "\n");
 
1154
    }
 
1155
 
 
1156
  if (pipe (fds))
 
1157
    {
 
1158
      sprintf (buf, "%s: error creating pipe", progname);
 
1159
      perror (buf);
 
1160
      return 0;
 
1161
    }
 
1162
 
 
1163
  in = fds [0];
 
1164
  out = fds [1];
 
1165
 
 
1166
  switch ((int) (forked = fork ()))
 
1167
    {
 
1168
    case -1:
 
1169
      {
 
1170
        sprintf (buf, "%s: couldn't fork", progname);
 
1171
        perror (buf);
 
1172
        return 0;
 
1173
      }
 
1174
    case 0:
 
1175
      {
 
1176
        int stdout_fd = 1;
 
1177
 
 
1178
        close (in);  /* don't need this one */
 
1179
        close (ConnectionNumber (dpy));         /* close display fd */
 
1180
 
 
1181
        if (dup2 (out, stdout_fd) < 0)          /* pipe stdout */
 
1182
          {
 
1183
            sprintf (buf, "%s: could not dup() a new stdout", progname);
 
1184
            exit (-1);                          /* exits fork */
 
1185
          }
 
1186
 
 
1187
        execvp (av[0], av);                     /* shouldn't return. */
 
1188
        exit (-1);                              /* exits fork */
 
1189
        break;
 
1190
      }
 
1191
    default:
 
1192
      {
 
1193
        struct stat st;
 
1194
        int wait_status = 0;
 
1195
        FILE *f = fdopen (in, "r");
 
1196
        int L;
 
1197
 
 
1198
        close (out);  /* don't need this one */
 
1199
        *buf = 0;
 
1200
        fgets (buf, sizeof(buf)-1, f);
 
1201
        fclose (f);
 
1202
 
 
1203
        /* Wait for the child to die. */
 
1204
        waitpid (-1, &wait_status, 0);
 
1205
 
 
1206
        L = strlen (buf);
 
1207
        while (L && buf[L-1] == '\n')
 
1208
          buf[--L] = 0;
 
1209
          
 
1210
        if (!*buf)
 
1211
          return 0;
 
1212
        if (stat(buf, &st))
 
1213
          {
 
1214
            fprintf (stderr, "%s: file does not exist: \"%s\"\n",
 
1215
                     progname, buf);
 
1216
            return 0;
 
1217
          }
 
1218
        else
 
1219
          return strdup (buf);
 
1220
      }
 
1221
    }
 
1222
 
 
1223
  abort();
 
1224
}
 
1225
 
 
1226
 
 
1227
/* Returns a pathname to an image file.  Free the string when you're done.
 
1228
 */
 
1229
static char *
 
1230
get_filename (Screen *screen, const char *directory, Bool verbose_p)
 
1231
{
 
1232
  return get_filename_1 (screen, directory, GRAB_FILE, verbose_p);
 
1233
}
 
1234
 
 
1235
 
 
1236
/* Grabs a video frame to a file, and returns a pathname to that file.
 
1237
   Delete that file when you are done with it (and free the string.)
 
1238
 */
 
1239
static char *
 
1240
get_video_filename (Screen *screen, Bool verbose_p)
 
1241
{
 
1242
  return get_filename_1 (screen, 0, GRAB_VIDEO, verbose_p);
 
1243
}
 
1244
 
 
1245
/* Grabs a desktop image to a file, and returns a pathname to that file.
 
1246
   Delete that file when you are done with it (and free the string.)
 
1247
 */
 
1248
# ifdef USE_EXTERNAL_SCREEN_GRABBER
 
1249
static char *
 
1250
get_desktop_filename (Screen *screen, Bool verbose_p)
 
1251
{
 
1252
  return get_filename_1 (screen, 0, GRAB_DESK, verbose_p);
 
1253
}
 
1254
#endif /* USE_EXTERNAL_SCREEN_GRABBER */
 
1255
 
 
1256
 
 
1257
/* Grabs a video frame, and renders it on the Drawable.
 
1258
   Returns False if it fails;
 
1259
 */
 
1260
static Bool
 
1261
display_video (Screen *screen, Window window, Drawable drawable,
 
1262
               Bool verbose_p, XRectangle *geom_ret)
 
1263
{
 
1264
  char *filename = get_video_filename (screen, verbose_p);
 
1265
  Bool status;
 
1266
 
 
1267
  if (!filename)
 
1268
    {
 
1269
      if (verbose_p)
 
1270
        fprintf (stderr, "%s: video grab failed.\n", progname);
 
1271
      return False;
 
1272
    }
 
1273
 
 
1274
  status = display_file (screen, window, drawable, filename, verbose_p,
 
1275
                         geom_ret);
 
1276
 
 
1277
  if (unlink (filename))
 
1278
    {
 
1279
      char buf[512];
 
1280
      sprintf (buf, "%s: rm %.100s", progname, filename);
 
1281
      perror (buf);
 
1282
    }
 
1283
  else if (verbose_p)
 
1284
    fprintf (stderr, "%s: rm %s\n", progname, filename);
 
1285
 
 
1286
  if (filename) free (filename);
 
1287
  return status;
 
1288
}
 
1289
 
 
1290
 
 
1291
/* Grabs a desktop screen shot onto the window and the drawable.
 
1292
   If the window and drawable are not the same size, the image in
 
1293
   the drawable is scaled to fit.
 
1294
   Returns False if it fails.
 
1295
 */
 
1296
static Bool
 
1297
display_desktop (Screen *screen, Window window, Drawable drawable,
 
1298
                 Bool verbose_p, XRectangle *geom_ret)
 
1299
{
 
1300
# ifdef USE_EXTERNAL_SCREEN_GRABBER
 
1301
 
 
1302
  Display *dpy = DisplayOfScreen (screen);
 
1303
  Bool top_p = top_level_window_p (screen, window);
 
1304
  char *filename;
 
1305
  Bool status;
 
1306
 
 
1307
  if (top_p)
 
1308
    {
 
1309
      if (verbose_p)
 
1310
        fprintf (stderr, "%s: unmapping 0x%lx.\n", progname,
 
1311
                 (unsigned long) window);
 
1312
      XUnmapWindow (dpy, window);
 
1313
      XSync (dpy, False);
 
1314
    }
 
1315
 
 
1316
  filename = get_desktop_filename (screen, verbose_p);
 
1317
 
 
1318
  if (top_p)
 
1319
    {
 
1320
      if (verbose_p)
 
1321
        fprintf (stderr, "%s: mapping 0x%lx.\n", progname,
 
1322
                 (unsigned long) window);
 
1323
      XMapRaised (dpy, window);
 
1324
      XSync (dpy, False);
 
1325
    }
 
1326
 
 
1327
  if (!filename)
 
1328
    {
 
1329
      if (verbose_p)
 
1330
        fprintf (stderr, "%s: desktop grab failed.\n", progname);
 
1331
      return False;
 
1332
    }
 
1333
 
 
1334
  status = display_file (screen, window, drawable, filename, verbose_p,
 
1335
                         geom_ret);
 
1336
 
 
1337
  if (unlink (filename))
 
1338
    {
 
1339
      char buf[512];
 
1340
      sprintf (buf, "%s: rm %.100s", progname, filename);
 
1341
      perror (buf);
 
1342
    }
 
1343
  else if (verbose_p)
 
1344
    fprintf (stderr, "%s: rm %s\n", progname, filename);
 
1345
 
 
1346
  if (filename) free (filename);
 
1347
  return status;
 
1348
 
 
1349
# else /* !USE_EXTERNAL_SCREEN_GRABBER */
 
1350
 
 
1351
  Display *dpy = DisplayOfScreen (screen);
 
1352
  XGCValues gcv;
 
1353
  XWindowAttributes xgwa;
 
1354
  Window root;
 
1355
  int px, py;
 
1356
  unsigned int pw, ph, pbw, pd;
 
1357
  int srcx, srcy, destx, desty, w2, h2;
 
1358
 
 
1359
  if (verbose_p)
 
1360
    {
 
1361
      fprintf (stderr, "%s: grabbing desktop image\n", progname);
 
1362
      grabscreen_verbose();
 
1363
    }
 
1364
 
 
1365
  XGetWindowAttributes (dpy, window, &xgwa);
 
1366
  XGetGeometry (dpy, drawable, &root, &px, &py, &pw, &ph, &pbw, &pd);
 
1367
 
 
1368
  grab_screen_image_internal (screen, window);
 
1369
 
 
1370
  compute_image_scaling (xgwa.width, xgwa.height,
 
1371
                         pw, ph, verbose_p,
 
1372
                         &srcx, &srcy, &destx, &desty, &w2, &h2);
 
1373
 
 
1374
  if (pw == w2 && ph == h2)  /* it fits -- just copy server-side pixmaps */
 
1375
    {
 
1376
      GC gc = XCreateGC (dpy, drawable, 0, &gcv);
 
1377
      XCopyArea (dpy, window, drawable, gc,
 
1378
                 0, 0, xgwa.width, xgwa.height, 0, 0);
 
1379
      XFreeGC (dpy, gc);
 
1380
    }
 
1381
  else  /* size mismatch -- must scale client-side images to fit drawable */
 
1382
    {
 
1383
      GC gc;
 
1384
      XImage *ximage = 0;
 
1385
      XErrorHandler old_handler;
 
1386
 
 
1387
      XSync (dpy, False);
 
1388
      old_handler = XSetErrorHandler (ignore_badmatch_ehandler);
 
1389
      error_handler_hit_p = False;
 
1390
 
 
1391
      /* This can return BadMatch if the window is not fully on screen.
 
1392
         Trap that error and return color bars in that case.
 
1393
         (Note that this only happens with XGetImage, not with XCopyArea:
 
1394
         yet another totally gratuitous inconsistency in X, thanks.)
 
1395
       */
 
1396
      ximage = XGetImage (dpy, window, 0, 0, xgwa.width, xgwa.height,
 
1397
                          ~0L, ZPixmap);
 
1398
 
 
1399
      XSync (dpy, False);
 
1400
      XSetErrorHandler (old_handler);
 
1401
      XSync (dpy, False);
 
1402
 
 
1403
      if (error_handler_hit_p)
 
1404
        {
 
1405
          ximage = 0;
 
1406
          if (verbose_p)
 
1407
            fprintf (stderr, "%s: BadMatch reading window 0x%x contents!\n",
 
1408
                     progname, (unsigned int) window);
 
1409
        }
 
1410
 
 
1411
      if (!ximage ||
 
1412
          !scale_ximage (xgwa.screen, xgwa.visual, ximage, w2, h2))
 
1413
        return False;
 
1414
 
 
1415
      gc = XCreateGC (dpy, drawable, 0, &gcv);
 
1416
      clear_drawable (screen, drawable);
 
1417
      XPutImage (dpy, drawable, gc, ximage, 
 
1418
                 srcx, srcy, destx, desty, ximage->width, ximage->height);
 
1419
      XDestroyImage (ximage);
 
1420
      XFreeGC (dpy, gc);
 
1421
    }
 
1422
 
 
1423
  if (geom_ret)
 
1424
    {
 
1425
      geom_ret->x = destx;
 
1426
      geom_ret->y = desty;
 
1427
      geom_ret->width  = w2;
 
1428
      geom_ret->height = h2;
 
1429
    }
 
1430
 
 
1431
  XSync (dpy, False);
 
1432
  return True;
 
1433
 
 
1434
# endif /* !USE_EXTERNAL_SCREEN_GRABBER */
 
1435
}
 
1436
 
 
1437
 
 
1438
/* Grabs an image (from a file, video, or the desktop) and renders it on
 
1439
   the Drawable.  If `file' is specified, always use that file.  Otherwise,
 
1440
   select randomly, based on the other arguments.
 
1441
 */
98
1442
static void
99
 
get_image (Screen *screen, Window window, Bool verbose_p)
 
1443
get_image (Screen *screen,
 
1444
           Window window, Drawable drawable,
 
1445
           Bool verbose_p,
 
1446
           Bool desk_p,
 
1447
           Bool video_p,
 
1448
           Bool image_p,
 
1449
           const char *dir,
 
1450
           const char *file)
100
1451
{
101
1452
  Display *dpy = DisplayOfScreen (screen);
102
 
  Bool desk_p  = get_boolean_resource ("grabDesktopImages",  "Boolean");
103
 
  Bool video_p = get_boolean_resource ("grabVideoFrames",    "Boolean");
104
 
  Bool image_p = get_boolean_resource ("chooseRandomImages", "Boolean");
105
 
  char *dir    = get_string_resource ("imageDirectory", "ImageDirectory");
106
 
 
107
 
  enum { do_desk, do_video, do_image, do_bars } which = do_bars;
108
 
  int count = 0;
109
 
  if (desk_p) count++;
110
 
  if (video_p) count++;
111
 
  if (image_p) count++;
 
1453
  grab_type which = GRAB_BARS;
 
1454
  struct stat st;
 
1455
  const char *file_prop = 0;
 
1456
  XRectangle geom = { 0, 0, 0, 0 };
 
1457
 
 
1458
  if (! drawable_window_p (dpy, window))
 
1459
    {
 
1460
      fprintf (stderr, "%s: 0x%lx is a pixmap, not a window!\n",
 
1461
               progname, (unsigned long) window);
 
1462
      exit (1);
 
1463
    }
 
1464
 
 
1465
  /* Make sure the Screen and the Window correspond. */
 
1466
  {
 
1467
    XWindowAttributes xgwa;
 
1468
    XGetWindowAttributes (dpy, window, &xgwa);
 
1469
    screen = xgwa.screen;
 
1470
  }
 
1471
 
 
1472
  if (file && stat (file, &st))
 
1473
    {
 
1474
      fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);
 
1475
      file = 0;
 
1476
    }
112
1477
 
113
1478
  if (verbose_p)
114
1479
    {
119
1484
      fprintf (stderr, "%s: chooseRandomImages: %s\n",
120
1485
               progname, image_p ? "True" : "False");
121
1486
      fprintf (stderr, "%s: imageDirectory:     %s\n",
122
 
               progname, (dir ? dir : ""));
123
 
    }
124
 
 
125
 
  if (!dir || !*dir)
 
1487
               progname, (file ? file : dir ? dir : ""));
 
1488
    }
 
1489
 
 
1490
# if !(defined(HAVE_GDK_PIXBUF) || defined(HAVE_JPEGLIB))
 
1491
  image_p = False;    /* can't load images from files... */
 
1492
#  ifdef USE_EXTERNAL_SCREEN_GRABBER
 
1493
  desk_p = False;     /* ...or from desktops grabbed to files. */
 
1494
#  endif
 
1495
 
 
1496
  if (file)
 
1497
    {
 
1498
      fprintf (stderr,
 
1499
               "%s: image file loading not available at compile-time\n",
 
1500
               progname);
 
1501
      fprintf (stderr, "%s: can't load \"%s\"\n", progname, file);
 
1502
      file = 0;
 
1503
    }
 
1504
# endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
 
1505
 
 
1506
  if (file)
 
1507
    {
 
1508
      desk_p = False;
 
1509
      video_p = False;
 
1510
      image_p = True;
 
1511
    }
 
1512
  else if (!dir || !*dir)
126
1513
    {
127
1514
      if (verbose_p && image_p)
128
1515
        fprintf (stderr,
131
1518
      image_p = False;
132
1519
    }
133
1520
 
 
1521
 
134
1522
# ifndef _VROOT_H_
135
1523
#  error Error!  This file definitely needs vroot.h!
136
1524
# endif
137
1525
 
138
 
  /* If the window is not the root window (real or virtual!) then the hack
139
 
     that called this program is running in "-window" mode instead of in
140
 
     "-root" mode.
141
 
 
142
 
     If the window is not the root window, then it's not possible to grab
143
 
     video or images onto it (the contract with those programs is to draw on
144
 
     the root.)  So turn off those options in that case, and turn on desktop
145
 
     grabbing.  (Since we're running in a window on the desktop already, we
146
 
     know it's not a security problem to expose desktop bits.)
147
 
   */
148
 
 
149
 
  if (window != VirtualRootWindowOfScreen (screen))
150
 
    {
151
 
      Bool changed_p = False;
152
 
      if (!desk_p) desk_p  = True,  changed_p = True;
153
 
      if (video_p) video_p = False, changed_p = True;
154
 
      if (image_p) image_p = False, changed_p = True;
155
 
      if (changed_p && verbose_p)
156
 
        fprintf (stderr,
157
 
                 "%s: not running on root window: grabbing desktop.\n",
158
 
                 progname);
159
 
    }
160
 
 
161
 
  if (count == 0)
162
 
    which = do_bars;
163
 
  else
164
 
    while (1)  /* loop until we get one that's permitted */
165
 
      {
166
 
        which = (random() % 3);
167
 
        if (which == do_desk  && desk_p)  break;
168
 
        if (which == do_video && video_p) break;
169
 
        if (which == do_image && image_p) break;
170
 
      }
171
 
 
172
 
  if (which == do_desk)
173
 
    {
174
 
      if (verbose_p)
175
 
        {
176
 
          fprintf (stderr, "%s: grabbing desktop image\n", progname);
177
 
          grabscreen_verbose();
178
 
        }
179
 
      grab_screen_image (screen, window);
180
 
      XSync (dpy, False);
181
 
    }
182
 
  else if (which == do_bars)
183
 
    {
184
 
      XWindowAttributes xgwa;
185
 
      XGetWindowAttributes (dpy, window, &xgwa);
186
 
      if (verbose_p)
187
 
        fprintf (stderr, "%s: drawing colorbars\n", progname);
188
 
      draw_colorbars (dpy, window, 0, 0, xgwa.width, xgwa.height);
189
 
      XSync (dpy, False);
190
 
    }
191
 
  else
192
 
    {
193
 
      char *av[10];
194
 
      memset (av, 0, sizeof(av));
195
 
      switch (which)
196
 
        {
197
 
        case do_video:
198
 
          if (verbose_p)
199
 
            fprintf (stderr, "%s: grabbing video\n", progname);
200
 
          av[0] = GETIMAGE_VIDEO_PROGRAM;
201
 
          break;
202
 
        case do_image:
203
 
          if (verbose_p)
204
 
            fprintf (stderr, "%s: loading random image file\n", progname);
205
 
          av[0] = GETIMAGE_FILE_PROGRAM;
206
 
          av[1] = dir;
207
 
          break;
208
 
        default:
209
 
          abort();
210
 
          break;
211
 
        }
212
 
 
213
 
      if (verbose_p)
214
 
        {
215
 
          int i;
216
 
          for (i = (sizeof(av)/sizeof(*av))-1; i > 1; i--)
217
 
            av[i] = av[i-1];
218
 
          av[1] = strdup ("--verbose");
219
 
        }
220
 
 
221
 
      if (verbose_p)
222
 
        {
223
 
          int i = 0;
224
 
          fprintf (stderr, "%s: executing \"", progname);
225
 
          while (av[i])
226
 
            {
227
 
              fprintf (stderr, "%s", av[i]);
228
 
              if (av[++i]) fprintf (stderr, " ");
229
 
            }
230
 
          fprintf (stderr, "\"\n");
231
 
        }
232
 
 
233
 
# ifdef HAVE_PUTENV
234
 
      /* Store our "-display" argument into the $DISPLAY variable,
235
 
         so that the subprocess gets the right display if the
236
 
         prevailing $DISPLAY is different. */
237
 
      {
238
 
        const char *odpy = DisplayString (dpy);
239
 
        char *ndpy = (char *) malloc(strlen(odpy) + 20);
240
 
        strcpy (ndpy, "DISPLAY=");
241
 
        strcat (ndpy, odpy);
242
 
        if (putenv (ndpy))
243
 
          abort ();
244
 
      }
245
 
# endif /* HAVE_PUTENV */
246
 
 
247
 
      close (ConnectionNumber (dpy));   /* close display fd */
248
 
 
249
 
      execvp (av[0], av);               /* shouldn't return */
250
 
      exec_error (av);
251
 
    }
 
1526
  /* We can grab desktop images (using the normal X11 method) if:
 
1527
       - the window is the real root window;
 
1528
       - the window is a toplevel window.
 
1529
     We cannot grab desktop images that way if:
 
1530
       - the window is a non-top-level window.
 
1531
 
 
1532
     Using the MacOS X way, desktops are just like loaded image files.
 
1533
   */
 
1534
# ifndef USE_EXTERNAL_SCREEN_GRABBER
 
1535
  if (desk_p)
 
1536
    {
 
1537
      if (!top_level_window_p (screen, window))
 
1538
        {
 
1539
          desk_p = False;
 
1540
          if (verbose_p)
 
1541
            fprintf (stderr,
 
1542
                    "%s: 0x%x not top-level: turning off grabDesktopImages.\n",
 
1543
                     progname, (unsigned int) window);
 
1544
        }
 
1545
    }
 
1546
# endif /* !USE_EXTERNAL_SCREEN_GRABBER */
 
1547
 
 
1548
  if (! (desk_p || video_p || image_p))
 
1549
    which = GRAB_BARS;
 
1550
  else
 
1551
    {
 
1552
      int i = 0;
 
1553
      int n;
 
1554
      /* Loop until we get one that's permitted.
 
1555
         If files or video are permitted, do them more often
 
1556
         than desktop.
 
1557
 
 
1558
             D+V+I: 10% + 45% + 45%.
 
1559
             V+I:   50% + 50%
 
1560
             D+V:   18% + 82%
 
1561
             D+I:   18% + 82%
 
1562
       */
 
1563
    AGAIN:
 
1564
      n = (random() % 100);
 
1565
      if (++i > 300) abort();
 
1566
      else if (desk_p  && n < 10) which = GRAB_DESK;   /* 10% */
 
1567
      else if (video_p && n < 55) which = GRAB_VIDEO;  /* 45% */
 
1568
      else if (image_p)           which = GRAB_FILE;   /* 45% */
 
1569
      else goto AGAIN;
 
1570
    }
 
1571
 
 
1572
 
 
1573
  /* If we're to search a directory to find an image file, do so now.
 
1574
   */
 
1575
  if (which == GRAB_FILE && !file)
 
1576
    {
 
1577
      file = get_filename (screen, dir, verbose_p);
 
1578
      if (!file)
 
1579
        {
 
1580
          which = GRAB_BARS;
 
1581
          if (verbose_p)
 
1582
            fprintf (stderr, "%s: no image files found.\n", progname);
 
1583
        }
 
1584
    }
 
1585
 
 
1586
  /* Now actually render something.
 
1587
   */
 
1588
  switch (which)
 
1589
    {
 
1590
    case GRAB_BARS:
 
1591
      {
 
1592
        XWindowAttributes xgwa;
 
1593
      COLORBARS:
 
1594
        if (verbose_p)
 
1595
          fprintf (stderr, "%s: drawing colorbars.\n", progname);
 
1596
        XGetWindowAttributes (dpy, window, &xgwa);
 
1597
        draw_colorbars (screen, xgwa.visual, drawable, xgwa.colormap,
 
1598
                        0, 0, 0, 0);
 
1599
        XSync (dpy, False);
 
1600
      }
 
1601
      break;
 
1602
 
 
1603
    case GRAB_DESK:
 
1604
      if (! display_desktop (screen, window, drawable, verbose_p, &geom))
 
1605
        goto COLORBARS;
 
1606
      file_prop = "desktop";
 
1607
      break;
 
1608
 
 
1609
    case GRAB_FILE:
 
1610
      if (! display_file (screen, window, drawable, file, verbose_p, &geom))
 
1611
        goto COLORBARS;
 
1612
      file_prop = file;
 
1613
      break;
 
1614
 
 
1615
    case GRAB_VIDEO:
 
1616
      if (! display_video (screen, window, drawable, verbose_p, &geom))
 
1617
        goto COLORBARS;
 
1618
      file_prop = "video";
 
1619
      break;
 
1620
 
 
1621
    default:
 
1622
      abort();
 
1623
      break;
 
1624
    }
 
1625
 
 
1626
  {
 
1627
    Atom a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, False);
 
1628
    if (file_prop && *file_prop)
 
1629
      XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace, 
 
1630
                       (unsigned char *) file_prop, strlen(file_prop));
 
1631
    else
 
1632
      XDeleteProperty (dpy, window, a);
 
1633
 
 
1634
    a = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_GEOMETRY, False);
 
1635
    if (geom.width > 0)
 
1636
      {
 
1637
        char gstr[30];
 
1638
        sprintf (gstr, "%dx%d+%d+%d", geom.width, geom.height, geom.x, geom.y);
 
1639
        XChangeProperty (dpy, window, a, XA_STRING, 8, PropModeReplace, 
 
1640
                         (unsigned char *) gstr, strlen (gstr));
 
1641
      }
 
1642
    else
 
1643
      XDeleteProperty (dpy, window, a);
 
1644
  }
 
1645
 
 
1646
  XSync (dpy, False);
252
1647
}
253
1648
 
254
1649
 
255
 
#if 0
 
1650
#ifdef DEBUG
256
1651
static Bool
257
1652
mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
258
1653
        XrmRepresentation *type, XrmValue *value, XPointer closure)
273
1668
 
274
1669
  return False;
275
1670
}
276
 
#endif
277
 
 
 
1671
#endif /* DEBUG */
 
1672
 
 
1673
 
 
1674
#define USAGE "usage: %s [ -options... ] window-id [pixmap-id]\n"             \
 
1675
   "\n"                                                                       \
 
1676
   "    %s\n"                                                                 \
 
1677
   "\n"                                                                       \
 
1678
   "    %s puts an image on the given window or pixmap.\n"                    \
 
1679
   "\n"                                                                       \
 
1680
   "    It is used by those xscreensaver demos that operate on images.\n"     \
 
1681
   "    The image may be a file loaded from disk, a frame grabbed from\n"     \
 
1682
   "    the system's video camera, or a screenshot of the desktop,\n"         \
 
1683
   "    depending on command-line options or the ~/.xscreensaver file.\n"     \
 
1684
   "\n"                                                                       \
 
1685
   "    Options include:\n"                                                   \
 
1686
   "\n"                                                                       \
 
1687
   "      -display host:dpy.screen    which display to use\n"                 \
 
1688
   "      -root                       draw to the root window\n"              \
 
1689
   "      -verbose                    print diagnostics\n"                    \
 
1690
   "      -images  / -no-images       whether to allow image file loading\n"  \
 
1691
   "      -video   / -no-video        whether to allow video grabs\n"         \
 
1692
   "      -desktop / -no-desktop      whether to allow desktop screen grabs\n"\
 
1693
   "      -directory <path>           where to find image files to load\n"    \
 
1694
   "      -file <filename>            load this image file\n"                 \
 
1695
   "\n"                                                                       \
 
1696
   "    The XScreenSaver Control Panel (xscreensaver-demo) lets you set the\n"\
 
1697
   "    defaults for these options in your ~/.xscreensaver file.\n"           \
 
1698
   "\n"
278
1699
 
279
1700
int
280
1701
main (int argc, char **argv)
283
1704
  Widget toplevel;
284
1705
  Display *dpy;
285
1706
  Screen *screen;
 
1707
  char *oprogname = progname;
 
1708
  char *file = 0;
 
1709
  char version[255];
 
1710
 
286
1711
  Window window = (Window) 0;
287
 
  Bool verbose_p = False;
 
1712
  Drawable drawable = (Drawable) 0;
 
1713
  const char *window_str = 0;
 
1714
  const char *drawable_str = 0;
288
1715
  char *s;
289
1716
  int i;
290
1717
 
291
1718
  progname = argv[0];
292
1719
  s = strrchr (progname, '/');
293
1720
  if (s) progname = s+1;
 
1721
  oprogname = progname;
 
1722
 
 
1723
  /* half-assed way of avoiding buffer-overrun attacks. */
 
1724
  if (strlen (progname) >= 100) progname[100] = 0;
 
1725
 
 
1726
# ifndef _VROOT_H_
 
1727
#  error Error!  This file definitely needs vroot.h!
 
1728
# endif
 
1729
 
 
1730
  /* Get the version number, for error messages. */
 
1731
  {
 
1732
    char *v = (char *) strdup(strchr(screensaver_id, ' '));
 
1733
    char *s1, *s2, *s3, *s4;
 
1734
    s1 = (char *) strchr(v,  ' '); s1++;
 
1735
    s2 = (char *) strchr(s1, ' ');
 
1736
    s3 = (char *) strchr(v,  '('); s3++;
 
1737
    s4 = (char *) strchr(s3, ')');
 
1738
    *s2 = 0;
 
1739
    *s4 = 0;
 
1740
    sprintf (version, "Part of XScreenSaver %s -- %s.", s1, s3);
 
1741
    free(v);
 
1742
  }
294
1743
 
295
1744
  /* We must read exactly the same resources as xscreensaver.
296
1745
     That means we must have both the same progclass *and* progname,
297
1746
     at least as far as the resource database is concerned.  So,
298
1747
     put "xscreensaver" in argv[0] while initializing Xt.
299
1748
   */
300
 
  argv[0] = "xscreensaver";
 
1749
  progname = argv[0] = "xscreensaver";
 
1750
 
 
1751
  /* allow one dash or two. */
 
1752
  for (i = 1; i < argc; i++)
 
1753
    if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
 
1754
 
301
1755
  toplevel = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
302
 
                              defaults, 0, 0);
303
 
  argv[0] = progname;
 
1756
                              defaults, 0, 0);
304
1757
  dpy = XtDisplay (toplevel);
305
1758
  screen = XtScreen (toplevel);
306
1759
  db = XtDatabase (dpy);
307
 
 
308
1760
  XtGetApplicationNameAndClass (dpy, &s, &progclass);
309
 
 
310
 
  /* half-assed way of avoiding buffer-overrun attacks. */
311
 
  if (strlen (progname) >= 100) progname[100] = 0;
312
 
 
313
 
  for (i = 1; i < argc; i++)
314
 
    {
315
 
      if (argv[i][0] == '-' && argv[i][1] == '-') argv[i]++;
316
 
      if (!strcmp (argv[i], "-v") ||
317
 
          !strcmp (argv[i], "-verbose"))
318
 
        verbose_p = True;
319
 
      else if (window == 0)
320
 
        {
321
 
          unsigned long w;
322
 
          char dummy;
323
 
 
324
 
          if (!strcmp (argv[i], "root") ||
325
 
              !strcmp (argv[i], "-root") ||
326
 
              !strcmp (argv[i], "--root"))
327
 
            window = RootWindowOfScreen (screen);
328
 
 
329
 
          else if ((1 == sscanf (argv[i], " 0x%x %c", &w, &dummy) ||
330
 
                    1 == sscanf (argv[i], " %d %c",   &w, &dummy)) &&
331
 
                   w != 0)
332
 
            window = (Window) w;
333
 
          else
334
 
            goto LOSE;
335
 
        }
336
 
      else
337
 
        {
338
 
         LOSE:
339
 
          fprintf (stderr,
340
 
            "usage: %s [ -display host:dpy.screen ] [ -v ] window-id\n",
341
 
                   progname);
342
 
          fprintf (stderr, "\n"
343
 
        "\tThis program puts an image of the desktop on the given window.\n"
344
 
        "\tIt is used by those xscreensaver demos that operate on images.\n"
345
 
        "\n");
346
 
          exit (1);
347
 
        }
348
 
    }
349
 
 
350
 
  if (window == 0) goto LOSE;
 
1761
  XSetErrorHandler (x_ehandler);
 
1762
  XSync (dpy, False);
351
1763
 
352
1764
  /* Randomize -- only need to do this here because this program
353
1765
     doesn't use the `screenhack.h' or `lockmore.h' APIs. */
358
1770
  P.db = db;
359
1771
  load_init_file (&P);
360
1772
 
361
 
  if (P.verbose_p)
362
 
    verbose_p = True;
363
 
 
364
 
#if 0
365
 
  /* Print out all the resources we read. */
366
 
  {
367
 
    XrmName name = { 0 };
368
 
    XrmClass class = { 0 };
369
 
    int count = 0;
370
 
    XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
371
 
                          (XtPointer) &count);
372
 
  }
373
 
#endif
374
 
 
375
 
  get_image (screen, window, verbose_p);
 
1773
  progname = argv[0] = oprogname;
 
1774
 
 
1775
  for (i = 1; i < argc; i++)
 
1776
    {
 
1777
      unsigned long w;
 
1778
      char dummy;
 
1779
 
 
1780
      /* Have to re-process these, or else the .xscreensaver file
 
1781
         has priority over the command line...
 
1782
       */
 
1783
      if (!strcmp (argv[i], "-v") || !strcmp (argv[i], "-verbose"))
 
1784
        P.verbose_p = True;
 
1785
      else if (!strcmp (argv[i], "-desktop"))    P.grab_desktop_p = True;
 
1786
      else if (!strcmp (argv[i], "-no-desktop")) P.grab_desktop_p = False;
 
1787
      else if (!strcmp (argv[i], "-video"))      P.grab_video_p = True;
 
1788
      else if (!strcmp (argv[i], "-no-video"))   P.grab_video_p = False;
 
1789
      else if (!strcmp (argv[i], "-images"))     P.random_image_p = True;
 
1790
      else if (!strcmp (argv[i], "-no-images"))  P.random_image_p = False;
 
1791
      else if (!strcmp (argv[i], "-file"))       file = argv[++i];
 
1792
      else if (!strcmp (argv[i], "-directory") || !strcmp (argv[i], "-dir"))
 
1793
        P.image_directory = argv[++i];
 
1794
      else if (!strcmp (argv[i], "-root") || !strcmp (argv[i], "root"))
 
1795
        {
 
1796
          if (window)
 
1797
            {
 
1798
              fprintf (stderr, "%s: both %s and %s specified?\n",
 
1799
                       progname, argv[i], window_str);
 
1800
              goto LOSE;
 
1801
            }
 
1802
          window_str = argv[i];
 
1803
          window = VirtualRootWindowOfScreen (screen);
 
1804
        }
 
1805
      else if ((1 == sscanf (argv[i], " 0x%lx %c", &w, &dummy) ||
 
1806
                1 == sscanf (argv[i], " %lu %c",   &w, &dummy)) &&
 
1807
               w != 0)
 
1808
        {
 
1809
          if (drawable)
 
1810
            {
 
1811
              fprintf (stderr, "%s: both %s and %s specified?\n",
 
1812
                       progname, drawable_str, argv[i]);
 
1813
              goto LOSE;
 
1814
            }
 
1815
          else if (window)
 
1816
            {
 
1817
              drawable_str = argv[i];
 
1818
              drawable = (Drawable) w;
 
1819
            }
 
1820
          else
 
1821
            {
 
1822
              window_str = argv[i];
 
1823
              window = (Window) w;
 
1824
            }
 
1825
        }
 
1826
      else
 
1827
        {
 
1828
          if (argv[i][0] == '-')
 
1829
            fprintf (stderr, "\n%s: unknown option \"%s\"\n",
 
1830
                     progname, argv[i]);
 
1831
          else
 
1832
            fprintf (stderr, "\n%s: unparsable window/pixmap ID: \"%s\"\n",
 
1833
                     progname, argv[i]);
 
1834
        LOSE:
 
1835
# ifdef __GNUC__
 
1836
          __extension__   /* don't warn about "string length is greater than
 
1837
                             the length ISO C89 compilers are required to
 
1838
                             support" in the usage string... */
 
1839
# endif
 
1840
          fprintf (stderr, USAGE, progname, version, progname);
 
1841
          exit (1);
 
1842
        }
 
1843
    }
 
1844
 
 
1845
  if (window == 0)
 
1846
    {
 
1847
      fprintf (stderr, "\n%s: no window ID specified!\n", progname);
 
1848
      goto LOSE;
 
1849
    }
 
1850
 
 
1851
 
 
1852
#ifdef DEBUG
 
1853
  if (P.verbose_p)       /* Print out all the resources we can see. */
 
1854
    {
 
1855
      XrmName name = { 0 };
 
1856
      XrmClass class = { 0 };
 
1857
      int count = 0;
 
1858
      XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
 
1859
                            (XtPointer) &count);
 
1860
    }
 
1861
#endif /* DEBUG */
 
1862
 
 
1863
  if (!window) abort();
 
1864
  if (!drawable) drawable = window;
 
1865
 
 
1866
  get_image (screen, window, drawable, P.verbose_p,
 
1867
             P.grab_desktop_p, P.grab_video_p, P.random_image_p,
 
1868
             P.image_directory, file);
376
1869
  exit (0);
377
1870
}