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