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