xwd.c revision 06ef0fec
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(NULL);
167	if (!strcmp(argv[i], "-out")) {
168	    if (++i >= argc) usage("-out requires an argument");
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("-add requires an argument");
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	if (!strcmp(argv[i], "-version")) {
200	    puts(PACKAGE_STRING);
201	    exit(0);
202	}
203	fprintf (stderr, "%s: unrecognized argument '%s'\n",
204		 program_name, argv[i]);
205	usage(NULL);
206    }
207#ifdef WIN32
208    if (standard_out)
209	_setmode(fileno(out_file), _O_BINARY);
210#endif
211
212    /*
213     * Let the user select the target window.
214     */
215    if (target_win == None)
216	target_win = Select_Window(dpy, !frame_only);
217
218    /*
219     * Dump it!
220     */
221    Window_Dump(target_win, out_file);
222
223    XCloseDisplay(dpy);
224    if (fclose(out_file)) {
225	perror("xwd");
226	exit(1);
227    }
228    exit(0);
229}
230
231static int
232Get24bitDirectColors(XColor **colors)
233{
234    int i , ncolors = 256 ;
235    XColor *tcol ;
236
237    *colors = tcol = (XColor *)malloc(sizeof(XColor) * ncolors) ;
238
239    for(i=0 ; i < ncolors ; i++)
240    {
241	tcol[i].pixel = i << 16 | i << 8 | i ;
242	tcol[i].red = tcol[i].green = tcol[i].blue = i << 8   | i ;
243    }
244
245    return ncolors ;
246}
247
248
249/*
250 * Window_Dump: dump a window to a file which must already be open for
251 *              writting.
252 */
253
254void
255Window_Dump(Window window, FILE *out)
256{
257    unsigned long swaptest = 1;
258    XColor *colors;
259    unsigned buffer_size;
260    size_t win_name_size;
261    CARD32 header_size;
262    int ncolors, i;
263    char *win_name;
264    char default_win_name[] = "xwdump";
265    Bool got_win_name;
266    XWindowAttributes win_info;
267    XImage *image;
268    int absx, absy, x, y;
269    unsigned width, height;
270    int dwidth, dheight;
271    Window dummywin;
272    XWDFileHeader header;
273    XWDColor xwdcolor;
274
275    int                 transparentOverlays , multiVis;
276    int                 numVisuals;
277    XVisualInfo         *pVisuals;
278    int                 numOverlayVisuals;
279    OverlayInfo         *pOverlayVisuals;
280    int                 numImageVisuals;
281    XVisualInfo         **pImageVisuals;
282    list_ptr            vis_regions;    /* list of regions to read from */
283    list_ptr            vis_image_regions ;
284    Visual		vis_h,*vis ;
285    int			allImage = 0 ;
286
287    /*
288     * Inform the user not to alter the screen.
289     */
290    if (!silent) {
291#ifdef XKB
292	XkbStdBell(dpy,None,50,XkbBI_Wait);
293#else
294	XBell(dpy,FEEP_VOLUME);
295#endif
296	XFlush(dpy);
297    }
298
299    /*
300     * Get the parameters of the window being dumped.
301     */
302    if (debug) outl("xwd: Getting target window information.\n");
303    if(!XGetWindowAttributes(dpy, window, &win_info))
304      Fatal_Error("Can't get target window attributes.");
305
306    /* handle any frame window */
307    if (!XTranslateCoordinates (dpy, window, RootWindow (dpy, screen), 0, 0,
308				&absx, &absy, &dummywin)) {
309	fprintf (stderr,
310		 "%s:  unable to translate window coordinates (%d,%d)\n",
311		 program_name, absx, absy);
312	exit (1);
313    }
314    win_info.x = absx;
315    win_info.y = absy;
316    width = win_info.width;
317    height = win_info.height;
318
319    if (!nobdrs) {
320	absx -= win_info.border_width;
321	absy -= win_info.border_width;
322	width += (2 * win_info.border_width);
323	height += (2 * win_info.border_width);
324    }
325    dwidth = DisplayWidth (dpy, screen);
326    dheight = DisplayHeight (dpy, screen);
327
328
329    /* clip to window */
330    if (absx < 0) width += absx, absx = 0;
331    if (absy < 0) height += absy, absy = 0;
332    if (absx + width > dwidth) width = dwidth - absx;
333    if (absy + height > dheight) height = dheight - absy;
334
335    XFetchName(dpy, window, &win_name);
336    if (!win_name || !win_name[0]) {
337	win_name = default_win_name;
338	got_win_name = False;
339    } else {
340	got_win_name = True;
341    }
342
343    /* sizeof(char) is included for the null string terminator. */
344    win_name_size = strlen(win_name) + sizeof(char);
345
346    /*
347     * Snarf the pixmap with XGetImage.
348     */
349
350    x = absx - win_info.x;
351    y = absy - win_info.y;
352
353    multiVis = GetMultiVisualRegions(dpy,RootWindow(dpy, screen),
354               absx, absy,
355	       width, height,&transparentOverlays,&numVisuals, &pVisuals,
356               &numOverlayVisuals,&pOverlayVisuals,&numImageVisuals,
357               &pImageVisuals,&vis_regions,&vis_image_regions,&allImage) ;
358    if (on_root || multiVis)
359    {
360	if(!multiVis)
361	    image = XGetImage (dpy, RootWindow(dpy, screen), absx, absy,
362                    width, height, AllPlanes, format);
363	else
364	    image = ReadAreaToImage(dpy, RootWindow(dpy, screen), absx, absy,
365                width, height,
366    		numVisuals,pVisuals,numOverlayVisuals,pOverlayVisuals,
367                numImageVisuals, pImageVisuals,vis_regions,
368                vis_image_regions,format,allImage);
369    }
370    else
371	image = XGetImage (dpy, window, x, y, width, height, AllPlanes, format);
372    if (!image) {
373	fprintf (stderr, "%s:  unable to get image at %dx%d+%d+%d\n",
374		 program_name, width, height, x, y);
375	exit (1);
376    }
377
378    if (add_pixel_value != 0) XAddPixel (image, add_pixel_value);
379
380    /*
381     * Determine the pixmap size.
382     */
383    buffer_size = Image_Size(image);
384
385    if (debug) outl("xwd: Getting Colors.\n");
386
387    if( !multiVis)
388    {
389       ncolors = Get_XColors(&win_info, &colors);
390       vis = win_info.visual ;
391    }
392    else
393    {
394       ncolors = Get24bitDirectColors(&colors) ;
395       initFakeVisual(&vis_h) ;
396       vis = &vis_h ;
397    }
398    /*
399     * Inform the user that the image has been retrieved.
400     */
401    if (!silent) {
402#ifdef XKB
403	XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_Proceed);
404	XkbStdBell(dpy,window,FEEP_VOLUME,XkbBI_RepeatingLastBell);
405#else
406	XBell(dpy, FEEP_VOLUME);
407	XBell(dpy, FEEP_VOLUME);
408#endif
409	XFlush(dpy);
410    }
411
412    /*
413     * Calculate header size.
414     */
415    if (debug) outl("xwd: Calculating header size.\n");
416    header_size = SIZEOF(XWDheader) + (CARD32) win_name_size;
417
418    /*
419     * Write out header information.
420     */
421    if (debug) outl("xwd: Constructing and dumping file header.\n");
422    header.header_size = (CARD32) header_size;
423    header.file_version = (CARD32) XWD_FILE_VERSION;
424    header.pixmap_format = (CARD32) format;
425    header.pixmap_depth = (CARD32) image->depth;
426    header.pixmap_width = (CARD32) image->width;
427    header.pixmap_height = (CARD32) image->height;
428    header.xoffset = (CARD32) image->xoffset;
429    header.byte_order = (CARD32) image->byte_order;
430    header.bitmap_unit = (CARD32) image->bitmap_unit;
431    header.bitmap_bit_order = (CARD32) image->bitmap_bit_order;
432    header.bitmap_pad = (CARD32) image->bitmap_pad;
433    header.bits_per_pixel = (CARD32) image->bits_per_pixel;
434    header.bytes_per_line = (CARD32) image->bytes_per_line;
435    /****
436    header.visual_class = (CARD32) win_info.visual->class;
437    header.red_mask = (CARD32) win_info.visual->red_mask;
438    header.green_mask = (CARD32) win_info.visual->green_mask;
439    header.blue_mask = (CARD32) win_info.visual->blue_mask;
440    header.bits_per_rgb = (CARD32) win_info.visual->bits_per_rgb;
441    header.colormap_entries = (CARD32) win_info.visual->map_entries;
442    *****/
443    header.visual_class = (CARD32) vis->class;
444    header.red_mask = (CARD32) vis->red_mask;
445    header.green_mask = (CARD32) vis->green_mask;
446    header.blue_mask = (CARD32) vis->blue_mask;
447    header.bits_per_rgb = (CARD32) vis->bits_per_rgb;
448    header.colormap_entries = (CARD32) vis->map_entries;
449
450    header.ncolors = ncolors;
451    header.window_width = (CARD32) win_info.width;
452    header.window_height = (CARD32) win_info.height;
453    header.window_x = absx;
454    header.window_y = absy;
455    header.window_bdrwidth = (CARD32) win_info.border_width;
456
457    if (*(char *) &swaptest) {
458	_swaplong((char *) &header, sizeof(header));
459	for (i = 0; i < ncolors; i++) {
460	    _swaplong((char *) &colors[i].pixel, sizeof(CARD32));
461	    _swapshort((char *) &colors[i].red, 3 * sizeof(short));
462	}
463    }
464
465    if (fwrite((char *)&header, SIZEOF(XWDheader), 1, out) != 1 ||
466	fwrite(win_name, win_name_size, 1, out) != 1) {
467	perror("xwd");
468	exit(1);
469    }
470
471    /*
472     * Write out the color maps, if any
473     */
474
475    if (debug) outl("xwd: Dumping %d colors.\n", ncolors);
476    for (i = 0; i < ncolors; i++) {
477	xwdcolor.pixel = colors[i].pixel;
478	xwdcolor.red = colors[i].red;
479	xwdcolor.green = colors[i].green;
480	xwdcolor.blue = colors[i].blue;
481	xwdcolor.flags = colors[i].flags;
482	if (fwrite((char *) &xwdcolor, SIZEOF(XWDColor), 1, out) != 1) {
483	    perror("xwd");
484	    exit(1);
485	}
486    }
487
488    /*
489     * Write out the buffer.
490     */
491    if (debug) outl("xwd: Dumping pixmap.  bufsize=%d\n",buffer_size);
492
493    /*
494     *    This copying of the bit stream (data) to a file is to be replaced
495     *  by an Xlib call which hasn't been written yet.  It is not clear
496     *  what other functions of xwd will be taken over by this (as yet)
497     *  non-existant X function.
498     */
499    if (fwrite(image->data, (int) buffer_size, 1, out) != 1) {
500	perror("xwd");
501	exit(1);
502    }
503
504    /*
505     * free the color buffer.
506     */
507
508    if(debug && ncolors > 0) outl("xwd: Freeing colors.\n");
509    if(ncolors > 0) free(colors);
510
511    /*
512     * Free window name string.
513     */
514    if (debug) outl("xwd: Freeing window name string.\n");
515    if (got_win_name) XFree(win_name);
516
517    /*
518     * Free image
519     */
520    XDestroyImage(image);
521}
522
523/*
524 * Report the syntax for calling xwd.
525 */
526void
527usage(const char *errmsg)
528{
529    if (errmsg != NULL)
530        fprintf (stderr, "%s: %s\n", program_name, errmsg);
531
532    fprintf (stderr,
533"usage: %s [-display host:dpy] [-debug] [-help] %s [-nobdrs] [-out <file>]",
534	   program_name, "[{-root|-id <id>|-name <name>}]");
535    fprintf (stderr, " [-xy] [-add value] [-frame] [-version]\n");
536    exit(1);
537}
538
539
540/*
541 * Determine the pixmap size.
542 */
543
544int Image_Size(XImage *image)
545{
546    if (image->format != ZPixmap)
547      return(image->bytes_per_line * image->height * image->depth);
548
549    return(image->bytes_per_line * image->height);
550}
551
552#define lowbit(x) ((x) & (~(x) + 1))
553
554static int
555ReadColors(Visual *vis, Colormap cmap, XColor **colors)
556{
557    int i,ncolors ;
558
559    ncolors = vis->map_entries;
560
561    if (!(*colors = (XColor *) malloc (sizeof(XColor) * ncolors)))
562      Fatal_Error("Out of memory!");
563
564    if (vis->class == DirectColor ||
565	vis->class == TrueColor) {
566	Pixel red, green, blue, red1, green1, blue1;
567
568	red = green = blue = 0;
569	red1 = lowbit(vis->red_mask);
570	green1 = lowbit(vis->green_mask);
571	blue1 = lowbit(vis->blue_mask);
572	for (i=0; i<ncolors; i++) {
573	  (*colors)[i].pixel = red|green|blue;
574	  (*colors)[i].pad = 0;
575	  red += red1;
576	  if (red > vis->red_mask)
577	    red = 0;
578	  green += green1;
579	  if (green > vis->green_mask)
580	    green = 0;
581	  blue += blue1;
582	  if (blue > vis->blue_mask)
583	    blue = 0;
584	}
585    } else {
586	for (i=0; i<ncolors; i++) {
587	  (*colors)[i].pixel = i;
588	  (*colors)[i].pad = 0;
589	}
590    }
591
592    XQueryColors(dpy, cmap, *colors, ncolors);
593
594    return(ncolors);
595}
596
597/*
598 * Get the XColors of all pixels in image - returns # of colors
599 */
600int Get_XColors(XWindowAttributes *win_info, XColor **colors)
601{
602    int i, ncolors;
603    Colormap cmap = win_info->colormap;
604
605    if (use_installed)
606	/* assume the visual will be OK ... */
607	cmap = XListInstalledColormaps(dpy, win_info->root, &i)[0];
608    if (!cmap)
609	return(0);
610    ncolors = ReadColors(win_info->visual,cmap,colors) ;
611    return ncolors ;
612}
613
614void
615_swapshort (register char *bp, register unsigned n)
616{
617    register char c;
618    register char *ep = bp + n;
619
620    while (bp < ep) {
621	c = *bp;
622	*bp = *(bp + 1);
623	bp++;
624	*bp++ = c;
625    }
626}
627
628void
629_swaplong (register char *bp, register unsigned n)
630{
631    register char c;
632    register char *ep = bp + n;
633
634    while (bp < ep) {
635        c = bp[3];
636        bp[3] = bp[0];
637        bp[0] = c;
638        c = bp[2];
639        bp[2] = bp[1];
640        bp[1] = c;
641        bp += 4;
642    }
643}
644