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