xwd.c revision 74a3f230
1/*
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/*
28 * xwd.c MIT Project Athena, X Window system window raster image dumper.
29 *
30 * This program will dump a raster image of the contents of a window into a
31 * file for output on graphics printers or for other uses.
32 *
33 *  Author:	Tony Della Fera, DEC
34 *		17-Jun-85
35 *
36 *  Modification history:
37 *
38 *  11/14/86 Bill Wyatt, Smithsonian Astrophysical Observatory
39 *    - Removed Z format option, changing it to an XY option. Monochrome
40 *      windows will always dump in XY format. Color windows will dump
41 *      in Z format by default, but can be dumped in XY format with the
42 *      -xy option.
43 *
44 *  11/18/86 Bill Wyatt
45 *    - VERSION 6 is same as version 5 for monchrome. For colors, the
46 *      appropriate number of Color structs are dumped after the header,
47 *      which has the number of colors (=0 for monochrome) in place of the
48 *      V5 padding at the end. Up to 16-bit displays are supported. I
49 *      don't yet know how 24- to 32-bit displays will be handled under
50 *      the Version 11 protocol.
51 *
52 *  6/15/87 David Krikorian, MIT Project Athena
53 *    - VERSION 7 runs under the X Version 11 servers, while the previous
54 *      versions of xwd were are for X Version 10.  This version is based
55 *      on xwd version 6, and should eventually have the same color
56 *      abilities. (Xwd V7 has yet to be tested on a color machine, so
57 *      all color-related code is commented out until color support
58 *      becomes practical.)
59 */
60
61/*%
62 *%    This is the format for commenting out color-related code until
63 *%  color can be supported.
64%*/
65
66#ifdef HAVE_CONFIG_H
67#include "config.h"
68#endif
69
70#include <stdio.h>
71#include <errno.h>
72#include <X11/Xos.h>
73#include <stdlib.h>
74
75#include <X11/Xlib.h>
76#include <X11/Xutil.h>
77
78#include "X11/XWDFile.h"
79
80#define FEEP_VOLUME 0
81
82/* Include routines to do parsing */
83#include "dsimple.h"
84#include "list.h"
85#include "wsutils.h"
86#include "multiVis.h"
87
88#ifdef XKB
89#include <X11/extensions/XKBbells.h>
90#endif
91
92/* Setable Options */
93
94static int format = ZPixmap;
95static Bool nobdrs = False;
96static Bool on_root = False;
97static Bool standard_out = True;
98static Bool debug = False;
99static Bool silent = False;
100static Bool use_installed = False;
101static long add_pixel_value = 0;
102
103
104extern int main(int, char **);
105extern void Window_Dump(Window, FILE *);
106extern int Image_Size(XImage *);
107extern int Get_XColors(XWindowAttributes *, XColor **);
108extern void _swapshort(register char *, register unsigned);
109extern void _swaplong(register char *, register unsigned);
110static long parse_long(char *);
111static int Get24bitDirectColors(XColor **);
112static int ReadColors(Visual *, Colormap, XColor **);
113
114
115static long parse_long (char *s)
116{
117    long retval = 0L;
118    int thesign = 1;
119
120    if (s && s[0]) {
121	switch(s[0]) {
122	    case '-':
123		(void) sscanf (s + 1, "%lu", &retval);
124        	thesign = -1;
125		break;
126	    case '0':
127		(void) sscanf (s + 1, "%lo", &retval);
128		break;
129	    case 'x':
130	    case 'X':
131		(void) sscanf (s + 1, "%lx", &retval);
132		break;
133	    default:
134		(void) sscanf (s, "%lu", &retval);
135		break;
136	}
137    }
138    return (thesign * retval);
139}
140
141int
142main(int argc, char **argv)
143{
144    register int i;
145    Window target_win;
146    FILE *out_file = stdout;
147    Bool frame_only = False;
148
149    INIT_NAME;
150
151    Setup_Display_And_Screen(&argc, argv);
152
153    /* Get window select on command line, if any */
154    target_win = Select_Window_Args(&argc, argv);
155
156    for (i = 1; i < argc; i++) {
157	if (!strcmp(argv[i], "-nobdrs")) {
158	    nobdrs = True;
159	    continue;
160	}
161	if (!strcmp(argv[i], "-debug")) {
162	    debug = True;
163	    continue;
164	}
165	if (!strcmp(argv[i], "-help"))
166	  usage();
167	if (!strcmp(argv[i], "-out")) {
168	    if (++i >= argc) usage();
169	    if (!(out_file = fopen(argv[i], "wb")))
170	      Fatal_Error("Can't open output file as specified.");
171	    standard_out = False;
172	    continue;
173	}
174	if (!strcmp(argv[i], "-xy")) {
175	    format = XYPixmap;
176	    continue;
177	}
178	if (!strcmp(argv[i], "-screen")) {
179	    on_root = True;
180	    continue;
181	}
182	if (!strcmp(argv[i], "-icmap")) {
183	    use_installed = True;
184	    continue;
185	}
186	if (!strcmp(argv[i], "-add")) {
187	    if (++i >= argc) usage();
188	    add_pixel_value = parse_long (argv[i]);
189	    continue;
190	}
191	if (!strcmp(argv[i], "-frame")) {
192	    frame_only = True;
193	    continue;
194	}
195	if (!strcmp(argv[i], "-silent")) {
196	    silent = True;
197	    continue;
198	}
199	usage();
200    }
201#ifdef WIN32
202    if (standard_out)
203	_setmode(fileno(out_file), _O_BINARY);
204#endif
205
206    /*
207     * Let the user select the target window.
208     */
209    if (target_win == None)
210	target_win = Select_Window(dpy, !frame_only);
211
212    /*
213     * Dump it!
214     */
215    Window_Dump(target_win, out_file);
216
217    XCloseDisplay(dpy);
218    if (fclose(out_file)) {
219	perror("xwd");
220	exit(1);
221    }
222    exit(0);
223}
224
225static int
226Get24bitDirectColors(XColor **colors)
227{
228    int i , ncolors = 256 ;
229    XColor *tcol ;
230
231    *colors = tcol = (XColor *)malloc(sizeof(XColor) * ncolors) ;
232
233    for(i=0 ; i < ncolors ; i++)
234    {
235	tcol[i].pixel = i << 16 | i << 8 | i ;
236	tcol[i].red = tcol[i].green = tcol[i].blue = i << 8   | i ;
237    }
238
239    return ncolors ;
240}
241
242
243/*
244 * Window_Dump: dump a window to a file which must already be open for
245 *              writting.
246 */
247
248void
249Window_Dump(Window window, FILE *out)
250{
251    unsigned long swaptest = 1;
252    XColor *colors;
253    unsigned buffer_size;
254    size_t win_name_size;
255    CARD32 header_size;
256    int ncolors, i;
257    char *win_name;
258    char default_win_name[] = "xwdump";
259    Bool got_win_name;
260    XWindowAttributes win_info;
261    XImage *image;
262    int absx, absy, x, y;
263    unsigned width, height;
264    int dwidth, dheight;
265    Window dummywin;
266    XWDFileHeader header;
267    XWDColor xwdcolor;
268
269    int                 transparentOverlays , multiVis;
270    int                 numVisuals;
271    XVisualInfo         *pVisuals;
272    int                 numOverlayVisuals;
273    OverlayInfo         *pOverlayVisuals;
274    int                 numImageVisuals;
275    XVisualInfo         **pImageVisuals;
276    list_ptr            vis_regions;    /* list of regions to read from */
277    list_ptr            vis_image_regions ;
278    Visual		vis_h,*vis ;
279    int			allImage = 0 ;
280
281    /*
282     * Inform the user not to alter the screen.
283     */
284    if (!silent) {
285#ifdef XKB
286	XkbStdBell(dpy,None,50,XkbBI_Wait);
287#else
288	XBell(dpy,FEEP_VOLUME);
289#endif
290	XFlush(dpy);
291    }
292
293    /*
294     * Get the parameters of the window being dumped.
295     */
296    if (debug) outl("xwd: Getting target window information.\n");
297    if(!XGetWindowAttributes(dpy, window, &win_info))
298      Fatal_Error("Can't get target window attributes.");
299
300    /* handle any frame window */
301    if (!XTranslateCoordinates (dpy, window, RootWindow (dpy, screen), 0, 0,
302				&absx, &absy, &dummywin)) {
303	fprintf (stderr,
304		 "%s:  unable to translate window coordinates (%d,%d)\n",
305		 program_name, absx, absy);
306	exit (1);
307    }
308    win_info.x = absx;
309    win_info.y = absy;
310    width = win_info.width;
311    height = win_info.height;
312
313    if (!nobdrs) {
314	absx -= win_info.border_width;
315	absy -= win_info.border_width;
316	width += (2 * win_info.border_width);
317	height += (2 * win_info.border_width);
318    }
319    dwidth = DisplayWidth (dpy, screen);
320    dheight = DisplayHeight (dpy, screen);
321
322
323    /* clip to window */
324    if (absx < 0) width += absx, absx = 0;
325    if (absy < 0) height += absy, absy = 0;
326    if (absx + width > dwidth) width = dwidth - absx;
327    if (absy + height > dheight) height = dheight - absy;
328
329    XFetchName(dpy, window, &win_name);
330    if (!win_name || !win_name[0]) {
331	win_name = default_win_name;
332	got_win_name = False;
333    } else {
334	got_win_name = True;
335    }
336
337    /* sizeof(char) is included for the null string terminator. */
338    win_name_size = strlen(win_name) + sizeof(char);
339
340    /*
341     * Snarf the pixmap with XGetImage.
342     */
343
344    x = absx - win_info.x;
345    y = absy - win_info.y;
346
347    multiVis = GetMultiVisualRegions(dpy,RootWindow(dpy, screen),
348               absx, absy,
349	       width, height,&transparentOverlays,&numVisuals, &pVisuals,
350               &numOverlayVisuals,&pOverlayVisuals,&numImageVisuals,
351               &pImageVisuals,&vis_regions,&vis_image_regions,&allImage) ;
352    if (on_root || multiVis)
353    {
354	if(!multiVis)
355	    image = XGetImage (dpy, RootWindow(dpy, screen), absx, absy,
356                    width, height, AllPlanes, format);
357	else
358	    image = ReadAreaToImage(dpy, RootWindow(dpy, screen), absx, absy,
359                width, height,
360    		numVisuals,pVisuals,numOverlayVisuals,pOverlayVisuals,
361                numImageVisuals, pImageVisuals,vis_regions,
362                vis_image_regions,format,allImage);
363    }
364    else
365	image = XGetImage (dpy, window, x, y, width, height, AllPlanes, format);
366    if (!image) {
367	fprintf (stderr, "%s:  unable to get image at %dx%d+%d+%d\n",
368		 program_name, width, height, x, y);
369	exit (1);
370    }
371
372    if (add_pixel_value != 0) XAddPixel (image, add_pixel_value);
373
374    /*
375     * Determine the pixmap size.
376     */
377    buffer_size = Image_Size(image);
378
379    if (debug) outl("xwd: Getting Colors.\n");
380
381    if( !multiVis)
382    {
383       ncolors = Get_XColors(&win_info, &colors);
384       vis = win_info.visual ;
385    }
386    else
387    {
388       ncolors = Get24bitDirectColors(&colors) ;
389       initFakeVisual(&vis_h) ;
390       vis = &vis_h ;
391    }
392    /*
393     * Inform the user that the image has been retrieved.
394     */
395    if (!silent) {
396#ifdef XKB
397	XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_Proceed);
398	XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_RepeatingLastBell);
399#else
400	XBell(dpy, FEEP_VOLUME);
401	XBell(dpy, FEEP_VOLUME);
402#endif
403	XFlush(dpy);
404    }
405
406    /*
407     * Calculate header size.
408     */
409    if (debug) outl("xwd: Calculating header size.\n");
410    header_size = SIZEOF(XWDheader) + (CARD32) win_name_size;
411
412    /*
413     * Write out header information.
414     */
415    if (debug) outl("xwd: Constructing and dumping file header.\n");
416    header.header_size = (CARD32) header_size;
417    header.file_version = (CARD32) XWD_FILE_VERSION;
418    header.pixmap_format = (CARD32) format;
419    header.pixmap_depth = (CARD32) image->depth;
420    header.pixmap_width = (CARD32) image->width;
421    header.pixmap_height = (CARD32) image->height;
422    header.xoffset = (CARD32) image->xoffset;
423    header.byte_order = (CARD32) image->byte_order;
424    header.bitmap_unit = (CARD32) image->bitmap_unit;
425    header.bitmap_bit_order = (CARD32) image->bitmap_bit_order;
426    header.bitmap_pad = (CARD32) image->bitmap_pad;
427    header.bits_per_pixel = (CARD32) image->bits_per_pixel;
428    header.bytes_per_line = (CARD32) image->bytes_per_line;
429    /****
430    header.visual_class = (CARD32) win_info.visual->class;
431    header.red_mask = (CARD32) win_info.visual->red_mask;
432    header.green_mask = (CARD32) win_info.visual->green_mask;
433    header.blue_mask = (CARD32) win_info.visual->blue_mask;
434    header.bits_per_rgb = (CARD32) win_info.visual->bits_per_rgb;
435    header.colormap_entries = (CARD32) win_info.visual->map_entries;
436    *****/
437    header.visual_class = (CARD32) vis->class;
438    header.red_mask = (CARD32) vis->red_mask;
439    header.green_mask = (CARD32) vis->green_mask;
440    header.blue_mask = (CARD32) vis->blue_mask;
441    header.bits_per_rgb = (CARD32) vis->bits_per_rgb;
442    header.colormap_entries = (CARD32) vis->map_entries;
443
444    header.ncolors = ncolors;
445    header.window_width = (CARD32) win_info.width;
446    header.window_height = (CARD32) win_info.height;
447    header.window_x = absx;
448    header.window_y = absy;
449    header.window_bdrwidth = (CARD32) win_info.border_width;
450
451    if (*(char *) &swaptest) {
452	_swaplong((char *) &header, sizeof(header));
453	for (i = 0; i < ncolors; i++) {
454	    _swaplong((char *) &colors[i].pixel, sizeof(CARD32));
455	    _swapshort((char *) &colors[i].red, 3 * sizeof(short));
456	}
457    }
458
459    if (fwrite((char *)&header, SIZEOF(XWDheader), 1, out) != 1 ||
460	fwrite(win_name, win_name_size, 1, out) != 1) {
461	perror("xwd");
462	exit(1);
463    }
464
465    /*
466     * Write out the color maps, if any
467     */
468
469    if (debug) outl("xwd: Dumping %d colors.\n", ncolors);
470    for (i = 0; i < ncolors; i++) {
471	xwdcolor.pixel = colors[i].pixel;
472	xwdcolor.red = colors[i].red;
473	xwdcolor.green = colors[i].green;
474	xwdcolor.blue = colors[i].blue;
475	xwdcolor.flags = colors[i].flags;
476	if (fwrite((char *) &xwdcolor, SIZEOF(XWDColor), 1, out) != 1) {
477	    perror("xwd");
478	    exit(1);
479	}
480    }
481
482    /*
483     * Write out the buffer.
484     */
485    if (debug) outl("xwd: Dumping pixmap.  bufsize=%d\n",buffer_size);
486
487    /*
488     *    This copying of the bit stream (data) to a file is to be replaced
489     *  by an Xlib call which hasn't been written yet.  It is not clear
490     *  what other functions of xwd will be taken over by this (as yet)
491     *  non-existant X function.
492     */
493    if (fwrite(image->data, (int) buffer_size, 1, out) != 1) {
494	perror("xwd");
495	exit(1);
496    }
497
498    /*
499     * free the color buffer.
500     */
501
502    if(debug && ncolors > 0) outl("xwd: Freeing colors.\n");
503    if(ncolors > 0) free(colors);
504
505    /*
506     * Free window name string.
507     */
508    if (debug) outl("xwd: Freeing window name string.\n");
509    if (got_win_name) XFree(win_name);
510
511    /*
512     * Free image
513     */
514    XDestroyImage(image);
515}
516
517/*
518 * Report the syntax for calling xwd.
519 */
520void
521usage(void)
522{
523    fprintf (stderr,
524"usage: %s [-display host:dpy] [-debug] [-help] %s [-nobdrs] [-out <file>]",
525	   program_name, "[{-root|-id <id>|-name <name>}]");
526    fprintf (stderr, " [-xy] [-add value] [-frame]\n");
527    exit(1);
528}
529
530
531/*
532 * Determine the pixmap size.
533 */
534
535int Image_Size(XImage *image)
536{
537    if (image->format != ZPixmap)
538      return(image->bytes_per_line * image->height * image->depth);
539
540    return(image->bytes_per_line * image->height);
541}
542
543#define lowbit(x) ((x) & (~(x) + 1))
544
545static int
546ReadColors(Visual *vis, Colormap cmap, XColor **colors)
547{
548    int i,ncolors ;
549
550    ncolors = vis->map_entries;
551
552    if (!(*colors = (XColor *) malloc (sizeof(XColor) * ncolors)))
553      Fatal_Error("Out of memory!");
554
555    if (vis->class == DirectColor ||
556	vis->class == TrueColor) {
557	Pixel red, green, blue, red1, green1, blue1;
558
559	red = green = blue = 0;
560	red1 = lowbit(vis->red_mask);
561	green1 = lowbit(vis->green_mask);
562	blue1 = lowbit(vis->blue_mask);
563	for (i=0; i<ncolors; i++) {
564	  (*colors)[i].pixel = red|green|blue;
565	  (*colors)[i].pad = 0;
566	  red += red1;
567	  if (red > vis->red_mask)
568	    red = 0;
569	  green += green1;
570	  if (green > vis->green_mask)
571	    green = 0;
572	  blue += blue1;
573	  if (blue > vis->blue_mask)
574	    blue = 0;
575	}
576    } else {
577	for (i=0; i<ncolors; i++) {
578	  (*colors)[i].pixel = i;
579	  (*colors)[i].pad = 0;
580	}
581    }
582
583    XQueryColors(dpy, cmap, *colors, ncolors);
584
585    return(ncolors);
586}
587
588/*
589 * Get the XColors of all pixels in image - returns # of colors
590 */
591int Get_XColors(XWindowAttributes *win_info, XColor **colors)
592{
593    int i, ncolors;
594    Colormap cmap = win_info->colormap;
595
596    if (use_installed)
597	/* assume the visual will be OK ... */
598	cmap = XListInstalledColormaps(dpy, win_info->root, &i)[0];
599    if (!cmap)
600	return(0);
601    ncolors = ReadColors(win_info->visual,cmap,colors) ;
602    return ncolors ;
603}
604
605void
606_swapshort (register char *bp, register unsigned n)
607{
608    register char c;
609    register char *ep = bp + n;
610
611    while (bp < ep) {
612	c = *bp;
613	*bp = *(bp + 1);
614	bp++;
615	*bp++ = c;
616    }
617}
618
619void
620_swaplong (register char *bp, register unsigned n)
621{
622    register char c;
623    register char *ep = bp + n;
624
625    while (bp < ep) {
626        c = bp[3];
627        bp[3] = bp[0];
628        bp[0] = c;
629        c = bp[2];
630        bp[2] = bp[1];
631        bp[1] = c;
632        bp += 4;
633    }
634}
635