56
exec_error (char **av)
61
sprintf (buf, "%s: could not execute \"%s\"", progname, av[0]);
64
if (errno == ENOENT &&
65
(token = getenv("PATH")))
69
# define PATH_MAX MAXPATHLEN
71
# define PATH_MAX 2048
75
fprintf (stderr, "\n");
77
# if defined(HAVE_GETCWD)
78
getcwd (path, sizeof(path));
79
# elif defined(HAVE_GETWD)
83
fprintf (stderr, " Current directory is: %s\n", path);
84
fprintf (stderr, " PATH is:\n");
85
token = strtok (strdup(token), ":");
88
fprintf (stderr, " %s\n", token);
89
token = strtok(0, ":");
91
fprintf (stderr, "\n");
112
x_ehandler (Display *dpy, XErrorEvent *error)
114
if (error->error_code == BadWindow || error->error_code == BadDrawable)
116
fprintf (stderr, "%s: target %s 0x%lx unexpectedly deleted\n", progname,
117
(error->error_code == BadWindow ? "window" : "pixmap"),
118
(unsigned long) error->resourceid);
122
fprintf (stderr, "\nX error in %s:\n", progname);
123
XmuPrintDefaultErrorMessage (dpy, error, stderr);
130
static Bool error_handler_hit_p = False;
133
ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
135
error_handler_hit_p = True;
140
ignore_badmatch_ehandler (Display *dpy, XErrorEvent *error)
142
if (error->error_code == BadMatch)
143
return ignore_all_errors_ehandler (dpy, error);
145
return x_ehandler (dpy, error);
149
/* Returns True if the given Drawable is a Window; False if it's a Pixmap.
152
drawable_window_p (Display *dpy, Drawable d)
154
XErrorHandler old_handler;
155
XWindowAttributes xgwa;
158
old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
159
error_handler_hit_p = False;
160
XGetWindowAttributes (dpy, d, &xgwa);
162
XSetErrorHandler (old_handler);
165
if (!error_handler_hit_p)
166
return True; /* It's a Window. */
168
return False; /* It's a Pixmap, or an invalid ID. */
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.
177
root_window_p (Screen *screen, Window window)
179
Display *dpy = DisplayOfScreen (screen);
182
unsigned long nitems, bytesafter;
183
unsigned char *version;
185
if (window != RootWindowOfScreen (screen))
188
if (XGetWindowProperty (dpy, window,
189
XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
190
0, 1, False, XA_STRING,
191
&type, &format, &nitems, &bytesafter,
201
/* Clear the window or pixmap to black, or its background color.
204
clear_drawable (Screen *screen, Drawable drawable)
206
Display *dpy = DisplayOfScreen (screen);
211
unsigned int w, h, bw, d;
212
XGetGeometry (dpy, drawable, &root, &x, &y, &w, &h, &bw, &d);
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...) */
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);
223
if (drawable_window_p (dpy, drawable))
224
XClearWindow (dpy, (Window) drawable);
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.
235
compute_image_scaling (int src_w, int src_h,
236
int dest_w, int dest_h,
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)
242
int srcx, srcy, destx, desty;
244
Bool exact_fit_p = ((src_w == dest_w && src_h <= dest_h) ||
245
(src_h == dest_h && src_w <= dest_w));
247
if (!exact_fit_p) /* scale the image up or down */
249
float rw = (float) dest_w / src_w;
250
float rh = (float) dest_h / src_h;
251
float r = (rw < rh ? rw : rh);
257
/* this optimization breaks things */
258
if (pct < 95 || pct > 105) /* don't scale if it's close */
262
fprintf (stderr, "%s: scaling image by %d%% (%dx%d -> %dx%d)\n",
263
progname, pct, src_w, src_h, tw, th);
269
/* Center the image on the window/pixmap. */
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;
277
if (dest_w < src_w) src_w = dest_w;
278
if (dest_h < src_h) src_h = dest_h;
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;
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);
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
299
scale_ximage (Screen *screen, Visual *visual,
300
XImage *ximage, int new_width, int new_height)
302
Display *dpy = DisplayOfScreen (screen);
303
int depth = visual_depth (screen, visual);
305
double xscale, yscale;
307
XImage *ximage2 = XCreateImage (dpy, visual, depth,
309
new_width, new_height, 8, 0);
310
ximage2->data = (char *) calloc (ximage2->height, ximage2->bytes_per_line);
314
fprintf (stderr, "%s: out of memory scaling %dx%d image to %dx%d\n",
316
ximage->width, ximage->height,
317
ximage2->width, ximage2->height);
318
if (ximage->data) free (ximage->data);
319
if (ximage2->data) free (ximage2->data);
322
XDestroyImage (ximage);
323
XDestroyImage (ximage2);
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));
338
(*ximage) = (*ximage2);
341
XDestroyImage (ximage2);
347
#ifdef HAVE_GDK_PIXBUF
349
/* Reads the given image file and renders it on the Drawable, using GDK.
350
Returns False if it fails.
353
read_file_gdk (Screen *screen, Window window, Drawable drawable,
354
const char *filename, Bool verbose_p,
355
XRectangle *geom_ret)
358
Display *dpy = DisplayOfScreen (screen);
359
unsigned int win_width, win_height, win_depth;
362
# endif /* HAVE_GTK2 */
364
/* Find the size of the Drawable. */
369
XGetGeometry (dpy, drawable,
370
&root, &x, &y, &win_width, &win_height, &bw, &win_depth);
373
gdk_pixbuf_xlib_init (dpy, screen_number (screen));
376
# else /* !HAVE_GTK2 */
377
xlib_rgb_init (dpy, screen);
378
# endif /* !HAVE_GTK2 */
380
pb = gdk_pixbuf_new_from_file (filename
383
# endif /* HAVE_GTK2 */
388
fprintf (stderr, "%s: unable to load \"%s\"\n", progname, filename);
390
if (gerr && gerr->message && *gerr->message)
391
fprintf (stderr, "%s: reason: %s\n", progname, gerr->message);
392
# endif /* HAVE_GTK2 */
397
int w = gdk_pixbuf_get_width (pb);
398
int h = gdk_pixbuf_get_height (pb);
399
int srcx, srcy, destx, desty, w2, h2;
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)
406
GdkPixbuf *pb2 = gdk_pixbuf_scale_simple (pb, w2, h2,
407
GDK_INTERP_BILINEAR);
410
gdk_pixbuf_unref (pb);
416
fprintf (stderr, "%s: out of memory when scaling?\n", progname);
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.
423
bg_p = (window == drawable && root_window_p (screen, window));
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);
437
clear_drawable (screen, drawable);
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.
444
gdk_pixbuf_xlib_render_to_drawable_alpha (pb, drawable,
445
srcx, srcy, destx, desty,
447
GDK_PIXBUF_ALPHA_FULL, 127,
448
XLIB_RGB_DITHER_NORMAL,
452
XSetWindowBackgroundPixmap (dpy, window, drawable);
453
XClearWindow (dpy, window);
461
geom_ret->height = h;
469
#endif /* HAVE_GDK_PIXBUF */
475
/* Allocates a colormap that makes a PseudoColor or DirectColor
476
visual behave like a TrueColor visual of the same depth.
479
allocate_cubic_colormap (Screen *screen, Visual *visual, Colormap cmap,
482
Display *dpy = DisplayOfScreen (screen);
483
int nr, ng, nb, cells;
489
depth = visual_depth (screen, visual);
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;
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++)
503
i = (r | (g << nr) | (b << (nr + ng)));
505
colors[i].flags = DoRed|DoGreen|DoBlue;
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) |
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;
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]))
536
fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
537
progname, allocated, cells);
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.)
545
find_closest_pixel (XColor *colors, int ncolors,
546
unsigned long r, unsigned long g, unsigned long b)
548
unsigned long distance = ~0;
553
for (i = 0; i < ncolors; i++)
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;
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.
585
remap_image (Screen *screen, Colormap cmap, XImage *image, Bool verbose_p)
587
Display *dpy = DisplayOfScreen (screen);
588
unsigned long map[4097];
593
if (image->depth == 8)
595
else if (image->depth == 12)
600
memset(map, -1, sizeof(*map));
601
memset(colors, -1, sizeof(*colors));
603
for (i = 0; i < cells; i++)
605
XQueryColors (dpy, cmap, colors, cells);
608
fprintf(stderr, "%s: building color cube for %d bit image\n",
609
progname, image->depth);
611
for (i = 0; i < cells; i++)
613
unsigned short r, g, b;
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
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);
631
/* "RRRR GGGG BBBB" In a 12 bit map. Convert that to
632
"RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
635
g = (i & 0x0F0) >> 4;
636
b = (i & 0xF00) >> 8;
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;
643
map[i] = find_closest_pixel (colors, cells, r, g, b);
647
fprintf(stderr, "%s: remapping colors in %d bit image\n",
648
progname, image->depth);
650
for (y = 0; y < image->height; y++)
651
for (x = 0; x < image->width; x++)
653
unsigned long pixel = XGetPixel(image, x, y);
654
if (pixel >= cells) abort();
655
XPutPixel(image, x, y, map[pixel]);
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.
664
maybe_read_ppm (Screen *screen, Visual *visual,
665
const char *filename, FILE *in, Bool verbose_p)
667
Display *dpy = DisplayOfScreen (screen);
668
int depth = visual_depth (screen, visual);
674
int x, y, w, h, maxval;
677
if (fstat (fileno (in), &st))
681
buf = (char *) malloc (bufsiz + 1);
684
fprintf (stderr, "%s: out of memory loading %d byte PPM file %s\n",
685
progname, bufsiz, filename);
689
if (! (s = fgets (buf, bufsiz, in))) /* line 1 */
692
if (!strncmp (buf, "\107\111", 2))
694
fprintf (stderr, "%s: %s: sorry, GIF files not supported"
695
" when compiled with JPEGlib instead of GDK_Pixbuf.\n",
699
else if (!strncmp (buf, "\211\120", 2))
701
fprintf (stderr, "%s: %s: sorry, PNG files not supported"
702
" when compiled with JPEGlib instead of GDK_Pixbuf.\n",
707
if (strncmp (s, "P6", 2))
710
if (! (s = fgets (buf, bufsiz, in))) /* line 2 */
712
if (2 != sscanf (s, " %d %d %c", &w, &h, &dummy))
714
fprintf (stderr, "%s: %s: invalid PPM (line 2)\n", progname, filename);
718
if (! (s = fgets (buf, bufsiz, in))) /* line 3 */
720
if (1 != sscanf (s, " %d %c", &maxval, &dummy))
722
fprintf (stderr, "%s: %s: invalid PPM (line 3)\n", progname, filename);
727
fprintf (stderr, "%s: %s: unparsable PPM: maxval is %d\n",
728
progname, filename, maxval);
732
ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
735
ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
736
if (!ximage || !ximage->data)
738
fprintf (stderr, "%s: out of memory loading %dx%d PPM file %s\n",
739
progname, ximage->width, ximage->height, filename);
745
while ((i = fread (s, 1, j, in)) > 0)
749
for (y = 0; y < ximage->height; y++)
750
for (x = 0; x < ximage->width; x++)
752
unsigned char r = buf[i++];
753
unsigned char g = buf[i++];
754
unsigned char b = buf[i++];
758
pixel = (r << 16) | (g << 8) | b;
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)));
768
XPutPixel (ximage, x, y, pixel);
776
if (ximage && ximage->data)
781
if (ximage) XDestroyImage (ximage);
782
fseek (in, 0, SEEK_SET);
788
struct jpeg_error_mgr pub; /* this is what passes for subclassing in C */
789
const char *filename;
794
} getimg_jpg_error_mgr;
798
jpg_output_message (j_common_ptr cinfo)
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);
808
jpg_error_exit (j_common_ptr cinfo)
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,
814
XSync (DisplayOfScreen (err->screen), False);
819
/* Reads a JPEG file, returns an RGB XImage of it.
822
read_jpeg_ximage (Screen *screen, Visual *visual, Drawable drawable,
823
Colormap cmap, const char *filename, Bool verbose_p)
825
Display *dpy = DisplayOfScreen (screen);
826
int depth = visual_depth (screen, visual);
830
struct jpeg_decompress_struct cinfo;
831
getimg_jpg_error_mgr jerr;
832
JSAMPARRAY scanbuf = 0;
835
jerr.filename = filename;
836
jerr.screen = screen;
837
jerr.visual = visual;
838
jerr.drawable = drawable;
841
if (! (depth >= 15 || depth == 12 || depth == 8))
843
fprintf (stderr, "%s: unsupported depth: %d\n", progname, depth);
847
in = fopen (filename, "rb");
850
fprintf (stderr, "%s: %s: unreadable\n", progname, filename);
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.
857
if ((ximage = maybe_read_ppm (screen, visual, filename, in, verbose_p)))
863
cinfo.err = jpeg_std_error (&jerr.pub);
864
jerr.pub.output_message = jpg_output_message;
865
jerr.pub.error_exit = jpg_error_exit;
867
jpeg_create_decompress (&cinfo);
868
jpeg_stdio_src (&cinfo, in);
869
jpeg_read_header (&cinfo, TRUE);
871
/* set some decode parameters */
872
cinfo.out_color_space = JCS_RGB;
873
cinfo.quantize_colors = FALSE;
875
jpeg_start_decompress (&cinfo);
877
ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0,
878
cinfo.output_width, cinfo.output_height,
881
ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
883
if (ximage && ximage->data)
884
scanbuf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE,
885
cinfo.rec_outbuf_height *
887
cinfo.output_components,
889
if (!ximage || !ximage->data || !scanbuf)
891
fprintf (stderr, "%s: out of memory loading %dx%d file %s\n",
892
progname, ximage->width, ximage->height, filename);
897
while (cinfo.output_scanline < cinfo.output_height)
899
int n = jpeg_read_scanlines (&cinfo, scanbuf, 1);
901
for (i = 0; i < n; i++)
904
for (x = 0; x < ximage->width; x++)
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];
913
pixel = (r << 16) | (g << 8) | b;
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
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)));
927
XPutPixel (ximage, x, y, pixel);
933
if (cinfo.output_scanline < cinfo.output_height)
934
/* don't goto FAIL -- we might have viewable partial data. */
935
jpeg_abort_decompress (&cinfo);
937
jpeg_finish_decompress (&cinfo);
939
jpeg_destroy_decompress (&cinfo);
947
if (ximage && ximage->data)
952
if (ximage) XDestroyImage (ximage);
953
if (scanbuf) free (scanbuf);
958
/* Reads the given image file and renders it on the Drawable, using JPEG lib.
959
Returns False if it fails.
962
read_file_jpeglib (Screen *screen, Window window, Drawable drawable,
963
const char *filename, Bool verbose_p,
964
XRectangle *geom_ret)
966
Display *dpy = DisplayOfScreen (screen);
971
unsigned int win_width, win_height, win_depth;
972
int srcx, srcy, destx, desty, w2, h2;
974
/* Find the size of the Drawable, and the Visual/Colormap of the Window. */
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);
987
/* Make sure we're not on some weirdo visual...
989
class = visual_class (screen, visual);
990
depth = visual_depth (screen, visual);
991
if ((class == PseudoColor || class == DirectColor) &&
992
(depth != 8 && depth != 12))
994
fprintf (stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
1001
ximage = read_jpeg_ximage (screen, visual, drawable, cmap,
1002
filename, verbose_p);
1003
if (!ximage) return False;
1005
/* Scale it, if necessary...
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))
1014
/* Allocate a colormap, if we need to...
1016
if (class == PseudoColor || class == DirectColor)
1018
allocate_cubic_colormap (screen, visual, cmap, verbose_p);
1019
remap_image (screen, cmap, ximage, verbose_p);
1022
/* Finally, put the resized image on the window.
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.
1032
if (window == drawable && root_window_p (screen, window))
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);
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);
1057
geom_ret->x = destx;
1058
geom_ret->y = desty;
1059
geom_ret->width = ximage->width;
1060
geom_ret->height = ximage->height;
1063
free (ximage->data);
1065
XDestroyImage (ximage);
1070
#endif /* HAVE_JPEGLIB */
1073
/* Reads the given image file and renders it on the Drawable.
1074
Returns False if it fails.
1077
display_file (Screen *screen, Window window, Drawable drawable,
1078
const char *filename, Bool verbose_p,
1079
XRectangle *geom_ret)
1082
fprintf (stderr, "%s: loading \"%s\"\n", progname, filename);
1084
# if defined(HAVE_GDK_PIXBUF)
1085
if (read_file_gdk (screen, window, drawable, filename, verbose_p, geom_ret))
1087
# elif defined(HAVE_JPEGLIB)
1088
if (read_file_jpeglib (screen, window, drawable, filename, verbose_p,
1091
# else /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
1092
/* shouldn't get here if we have no image-loading methods available. */
1094
# endif /* !(HAVE_GDK_PIXBUF || HAVE_JPEGLIB) */
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
1105
get_filename_1 (Screen *screen, const char *directory, grab_type type,
1108
Display *dpy = DisplayOfScreen (screen);
1119
av[ac++] = GETIMAGE_FILE_PROGRAM;
1121
av[ac++] = "--verbose";
1122
av[ac++] = "--name";
1123
av[ac++] = (char *) directory;
1127
av[ac++] = GETIMAGE_VIDEO_PROGRAM;
1129
av[ac++] = "--verbose";
1130
av[ac++] = "--name";
1133
# ifdef USE_EXTERNAL_SCREEN_GRABBER
1135
av[ac++] = GETIMAGE_SCREEN_PROGRAM;
1137
av[ac++] = "--verbose";
1138
av[ac++] = "--name";
1150
fprintf (stderr, "%s: executing:", progname);
1151
for (i = 0; i < ac; i++)
1152
fprintf (stderr, " %s", av[i]);
1153
fprintf (stderr, "\n");
1158
sprintf (buf, "%s: error creating pipe", progname);
1166
switch ((int) (forked = fork ()))
1170
sprintf (buf, "%s: couldn't fork", progname);
1178
close (in); /* don't need this one */
1179
close (ConnectionNumber (dpy)); /* close display fd */
1181
if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
1183
sprintf (buf, "%s: could not dup() a new stdout", progname);
1184
exit (-1); /* exits fork */
1187
execvp (av[0], av); /* shouldn't return. */
1188
exit (-1); /* exits fork */
1194
int wait_status = 0;
1195
FILE *f = fdopen (in, "r");
1198
close (out); /* don't need this one */
1200
fgets (buf, sizeof(buf)-1, f);
1203
/* Wait for the child to die. */
1204
waitpid (-1, &wait_status, 0);
1207
while (L && buf[L-1] == '\n')
1214
fprintf (stderr, "%s: file does not exist: \"%s\"\n",
1219
return strdup (buf);
1227
/* Returns a pathname to an image file. Free the string when you're done.
1230
get_filename (Screen *screen, const char *directory, Bool verbose_p)
1232
return get_filename_1 (screen, directory, GRAB_FILE, verbose_p);
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.)
1240
get_video_filename (Screen *screen, Bool verbose_p)
1242
return get_filename_1 (screen, 0, GRAB_VIDEO, verbose_p);
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.)
1248
# ifdef USE_EXTERNAL_SCREEN_GRABBER
1250
get_desktop_filename (Screen *screen, Bool verbose_p)
1252
return get_filename_1 (screen, 0, GRAB_DESK, verbose_p);
1254
#endif /* USE_EXTERNAL_SCREEN_GRABBER */
1257
/* Grabs a video frame, and renders it on the Drawable.
1258
Returns False if it fails;
1261
display_video (Screen *screen, Window window, Drawable drawable,
1262
Bool verbose_p, XRectangle *geom_ret)
1264
char *filename = get_video_filename (screen, verbose_p);
1270
fprintf (stderr, "%s: video grab failed.\n", progname);
1274
status = display_file (screen, window, drawable, filename, verbose_p,
1277
if (unlink (filename))
1280
sprintf (buf, "%s: rm %.100s", progname, filename);
1284
fprintf (stderr, "%s: rm %s\n", progname, filename);
1286
if (filename) free (filename);
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.
1297
display_desktop (Screen *screen, Window window, Drawable drawable,
1298
Bool verbose_p, XRectangle *geom_ret)
1300
# ifdef USE_EXTERNAL_SCREEN_GRABBER
1302
Display *dpy = DisplayOfScreen (screen);
1303
Bool top_p = top_level_window_p (screen, window);
1310
fprintf (stderr, "%s: unmapping 0x%lx.\n", progname,
1311
(unsigned long) window);
1312
XUnmapWindow (dpy, window);
1316
filename = get_desktop_filename (screen, verbose_p);
1321
fprintf (stderr, "%s: mapping 0x%lx.\n", progname,
1322
(unsigned long) window);
1323
XMapRaised (dpy, window);
1330
fprintf (stderr, "%s: desktop grab failed.\n", progname);
1334
status = display_file (screen, window, drawable, filename, verbose_p,
1337
if (unlink (filename))
1340
sprintf (buf, "%s: rm %.100s", progname, filename);
1344
fprintf (stderr, "%s: rm %s\n", progname, filename);
1346
if (filename) free (filename);
1349
# else /* !USE_EXTERNAL_SCREEN_GRABBER */
1351
Display *dpy = DisplayOfScreen (screen);
1353
XWindowAttributes xgwa;
1356
unsigned int pw, ph, pbw, pd;
1357
int srcx, srcy, destx, desty, w2, h2;
1361
fprintf (stderr, "%s: grabbing desktop image\n", progname);
1362
grabscreen_verbose();
1365
XGetWindowAttributes (dpy, window, &xgwa);
1366
XGetGeometry (dpy, drawable, &root, &px, &py, &pw, &ph, &pbw, &pd);
1368
grab_screen_image_internal (screen, window);
1370
compute_image_scaling (xgwa.width, xgwa.height,
1372
&srcx, &srcy, &destx, &desty, &w2, &h2);
1374
if (pw == w2 && ph == h2) /* it fits -- just copy server-side pixmaps */
1376
GC gc = XCreateGC (dpy, drawable, 0, &gcv);
1377
XCopyArea (dpy, window, drawable, gc,
1378
0, 0, xgwa.width, xgwa.height, 0, 0);
1381
else /* size mismatch -- must scale client-side images to fit drawable */
1385
XErrorHandler old_handler;
1388
old_handler = XSetErrorHandler (ignore_badmatch_ehandler);
1389
error_handler_hit_p = False;
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.)
1396
ximage = XGetImage (dpy, window, 0, 0, xgwa.width, xgwa.height,
1400
XSetErrorHandler (old_handler);
1403
if (error_handler_hit_p)
1407
fprintf (stderr, "%s: BadMatch reading window 0x%x contents!\n",
1408
progname, (unsigned int) window);
1412
!scale_ximage (xgwa.screen, xgwa.visual, ximage, w2, h2))
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);
1425
geom_ret->x = destx;
1426
geom_ret->y = desty;
1427
geom_ret->width = w2;
1428
geom_ret->height = h2;
1434
# endif /* !USE_EXTERNAL_SCREEN_GRABBER */
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.
99
get_image (Screen *screen, Window window, Bool verbose_p)
1443
get_image (Screen *screen,
1444
Window window, Drawable drawable,
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");
107
enum { do_desk, do_video, do_image, do_bars } which = do_bars;
110
if (video_p) count++;
111
if (image_p) count++;
1453
grab_type which = GRAB_BARS;
1455
const char *file_prop = 0;
1456
XRectangle geom = { 0, 0, 0, 0 };
1458
if (! drawable_window_p (dpy, window))
1460
fprintf (stderr, "%s: 0x%lx is a pixmap, not a window!\n",
1461
progname, (unsigned long) window);
1465
/* Make sure the Screen and the Window correspond. */
1467
XWindowAttributes xgwa;
1468
XGetWindowAttributes (dpy, window, &xgwa);
1469
screen = xgwa.screen;
1472
if (file && stat (file, &st))
1474
fprintf (stderr, "%s: file \"%s\" does not exist\n", progname, file);