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