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