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