Received: from expo.lcs.mit.edu by TGV.COM with INTERNET ; Sat, 8 Feb 92 03:04:20 PST Received: by expo.lcs.mit.edu; Fri, 7 Feb 92 12:01:01 EST Received: from relay2.UU.NET by expo.lcs.mit.edu; Fri, 7 Feb 92 11:51:38 EST Received: from uunet.uu.net (via LOCALHOST.UU.NET) by relay2.UU.NET with SMTP (5.61/UUNET-internet-primary) id AA14065; Fri, 7 Feb 92 11:51:00 -0500 Received: from craft.UUCP by uunet.uu.net with UUCP/RMAIL (queueing-rmail) id 114804.10499; Fri, 7 Feb 1992 11:48:04 EST Received: by craft (4.1/SMI-4.1) id AA01703; Fri, 7 Feb 92 11:39:08 EST Message-Id: <9202071639.AA01703@craft> From: david@craft.noname (David B. Lewis) Date: Fri, 7 Feb 1992 11:39:08 -0500 Organization: The Open Open Open Open Company X-Mailer: Z-Mail (2.0.0 7/1/91) To: xbugs@expo.lcs.mit.edu, xpert@expo.lcs.mit.edu Subject: xwd: additional methods to specify area to dump [long] VERSION: R5, public-patch-8 CLIENT MACHINE and OPERATING SYSTEM: Sparc/SunOS 4.1.1 DISPLAY TYPE: Visual XBASE12 8-bit color, beta software WINDOW MANAGER: typically XDSwm COMPILER: typically native cc AREA: clients/xwd/ SYNOPSIS: Code for additional methods of specifying the area to dump to the xwd image DESCRIPTION: In order to make xwd more useful as a standard client: 1) add the same -source [-geometry] option that xmag supports 2) add an on-root -rubber interactive selection 3) add a -sleep option to permit xwd to be used to grab images after some short amount of time has passed; permits dumping of menus, e.g. REPEAT BY: Helps permit dumping of collections of windows in active state. SAMPLE FIX: Here's the set of changes that I'm using: Bugs: - one of my goals was adding as little code as possible, so these changes have the same organization as the original code - there is still a lot of unused code in dsimple.[ch]. Not removed. - naive GC setup - xgrabsc and other tools are probably better to use anyway *** dsimple.c.orig Sat May 11 21:01:54 1991 --- dsimple.c Thu Feb 6 10:46:00 1992 *************** *** 499,501 **** --- 499,632 ---- fprintf(stderr, "\n"); exit(1); } + + #define ABS(a) (((a) >= 0) ? (a) : -(a)) + #define Min(x,y) (((x) < (y)) ? (x) : (y)) + + static int RubberBand (dpy, w, gc, x1, y1, x2, y2) + Display *dpy; + Window w; + GC gc; + int x1, y1, x2, y2; + { + int retval = (x2>x1)+2*(y2>y1); + /* + increasing x -> + | y + 0 | 1 | + ----------------- | + 2 | 3 \/ + | + */ + + /* assume a rectangle */ + XDrawRectangle(dpy, w, gc, + Min(x1, x2), Min(y1, y2), + ABS(x2-x1), ABS(y2-y1)); + + return retval; + } + + + + /* 0 is OK */ + int Get_Rubber_Values (dpy, ulx, uly, width, height, grabFlag) + Display *dpy; + int *ulx, *uly; /* RETURN */ + unsigned int *width, *height; /* RETURN */ + Bool grabFlag; + { + unsigned long valuemask; + GC Rubber_GC = NULL; + XGCValues gcVal; + Window root; + int screen; + XEvent event; + int i; + + /* globals for rubber-banding */ + /* note: order is significant; see below */ + #define UpperLeft 0 + #define UpperRight 1 + #define LowerLeft 2 + #define LowerRight 3 + Cursor corners[4]; + int corner, save_corner; + + int start_x, start_y, end_x, end_y; + + root = XDefaultRootWindow (dpy); + screen = XDefaultScreen (dpy); + + corners[LowerLeft] = XCreateFontCursor(dpy, XC_ll_angle); + corners[LowerRight] = XCreateFontCursor(dpy, XC_lr_angle); + corners[UpperLeft]= XCreateFontCursor(dpy, XC_ul_angle); + corners[UpperRight]= XCreateFontCursor(dpy, XC_ur_angle); + + if (grabFlag) XGrabServer(dpy); + if (XGrabPointer(dpy, root, False, + ButtonPressMask, GrabModeAsync, GrabModeAsync, root, + corners[corner=UpperLeft], CurrentTime) != GrabSuccess) { + return 1; + } + + valuemask = GCFunction | GCPlaneMask | GCForeground | + GCBackground | GCLineWidth; + gcVal.function = GXxor; + gcVal.plane_mask = BlackPixel(dpy, screen) ^ WhitePixel(dpy, screen); + gcVal.foreground = 0xffffffff; + gcVal.background = 0; + gcVal.line_width = 0; + Rubber_GC = XCreateGC(dpy, root, valuemask, &gcVal); + XSetSubwindowMode(dpy, Rubber_GC, IncludeInferiors); + + XMaskEvent(dpy, ButtonPressMask, &event); + start_x = end_x = event.xbutton.x_root; + start_y = end_y = event.xbutton.y_root; + + /* we have one corner. draw; set appropriate cursor. */ + corner=RubberBand(dpy, root, Rubber_GC, start_x, start_y, end_x, end_y); + XChangeActivePointerGrab (dpy, ButtonMotionMask | ButtonReleaseMask, + corners[corner], CurrentTime); + + while (1) { + XNextEvent(dpy, &event); + switch (event.type) { + case MotionNotify: + save_corner = corner; + corner = RubberBand (dpy, root, Rubber_GC, + start_x, start_y, end_x, end_y); + + if (save_corner != corner) + XChangeActivePointerGrab (dpy, + ButtonMotionMask | ButtonReleaseMask, + corners[corner], CurrentTime); + + while (XCheckTypedEvent(dpy, MotionNotify, &event)) + {} + + end_x = event.xbutton.x_root; + end_y = event.xbutton.y_root; + RubberBand(dpy,root, Rubber_GC, start_x, start_y, end_x, end_y); + + break; + + case ButtonRelease: + RubberBand(dpy,root,Rubber_GC, start_x, start_y, end_x, end_y); + *ulx= Min(start_x, end_x); + *uly= Min(start_y, end_y); + *width= ABS(start_x - end_x); + *height=ABS(start_y - end_y); + XFreeGC(dpy, Rubber_GC); + XUngrabPointer (dpy, CurrentTime); + if (grabFlag) XUngrabServer(dpy); + for (i=0 ; i < 4; i++) XFreeCursor(dpy, corners[i]); + XSync(dpy, 0); + return 0; + break; + + default: + break; + } + } + } *** dsimple.h.orig Sat Apr 28 12:07:15 1990 --- dsimple.h Thu Feb 6 10:09:51 1992 *************** *** 35,41 **** #define X_USAGE "[host:display]" /* X arguments handled by Get_Display_Name */ ! #define SELECT_USAGE "[-root|-id |-name ]" /* * Other_stuff.h: Definitions of routines in other_stuff. --- 35,41 ---- #define X_USAGE "[host:display]" /* X arguments handled by Get_Display_Name */ ! #define SELECT_USAGE "[-root | -id | -name | -geometry geomspec | -rubber]" /* * Other_stuff.h: Definitions of routines in other_stuff. *************** *** 51,53 **** --- 51,54 ---- void out(); void blip(); Window Window_With_Name(); + int Get_Rubber_Values(); *** xwd.c.orig Thu Jul 25 18:01:04 1991 --- xwd.c Thu Feb 6 10:32:40 1992 *************** *** 65,70 **** --- 65,71 ---- Bool debug = False; Bool use_installed = False; long add_pixel_value = 0; + int delay = 0; extern int (*_XErrorFunction)(); extern int _XDefaultError(); *************** *** 93,98 **** --- 94,101 ---- Window target_win; FILE *out_file = stdout; Bool frame_only = False; + int use_x=0, use_y=0; + unsigned int use_width=0, use_height=0; INIT_NAME; *************** *** 140,145 **** --- 143,180 ---- frame_only = True; continue; } + if (!strcmp(argv[i], "-geometry") || !strcmp(argv[i], "-source")) { + if (++i >= argc) usage(); + if (target_win) + outl("Use only one of -root -id -name -source -rubber; continuing."); + if ( (AllValues != XParseGeometry(argv[i], &use_x, &use_y, + &use_width, &use_height)) + || (use_x + (int)use_width < 0) + || (use_y + (int)use_height < 0) + || (use_x > XDisplayWidth(dpy, screen)) + || (use_y > XDisplayHeight(dpy, screen)) + ) + Fatal_Error("Please fully specify on-screen width x height + positive X, Y."); + target_win = RootWindow(dpy,screen); + on_root = True; + continue; + } + if (!strcmp(argv[i], "-rubber")) { + if (target_win) + outl("Use only one of -root -id -name -source -rubber; continuing."); + target_win = RootWindow(dpy,screen); + on_root = True; + if (Get_Rubber_Values(dpy, &use_x, &use_y, + &use_width, &use_height, True)) + Fatal_Error ("Error getting portion of root window."); + continue; + } + if (!strcmp(argv[i], "-sleep")) { + if (++i >= argc) usage(); + delay = atoi(argv[i]); + if (delay < 0) delay = 0; + continue; + } usage(); } *************** *** 164,172 **** /* * Dump it! */ ! Window_Dump(target_win, out_file); fclose(out_file); } --- 199,208 ---- /* * Dump it! */ ! Window_Dump(target_win, out_file, use_x, use_y, use_width, use_height); fclose(out_file); + exit(0); } *************** *** 173,178 **** --- 209,216 ---- /* * Window_Dump: dump a window to a file which must already be open for * writting. + * a width/height of 0 indicates that this function is being used for dumping + * a real non-root window, not a portion of the root window */ char *calloc(); *************** *** 179,187 **** #include "X11/XWDFile.h" ! Window_Dump(window, out) Window window; FILE *out; { unsigned long swaptest = 1; XColor *colors; --- 217,227 ---- #include "X11/XWDFile.h" ! Window_Dump(window, out, use_x, use_y, use_width, use_height) Window window; FILE *out; + int use_x, use_y; + unsigned int use_width, use_height; { unsigned long swaptest = 1; XColor *colors; *************** *** 200,206 **** Window dummywin; XWDFileHeader header; ! /* * Inform the user not to alter the screen. */ --- 240,246 ---- Window dummywin; XWDFileHeader header; ! if (delay) sleep(delay); /* * Inform the user not to alter the screen. */ *************** *** 207,218 **** Beep(); /* ! * Get the parameters of the window being dumped. */ if (debug) outl("xwd: Getting target window information.\n"); if(!XGetWindowAttributes(dpy, window, &win_info)) Fatal_Error("Can't get target window attributes."); /* handle any frame window */ if (!XTranslateCoordinates (dpy, window, RootWindow (dpy, screen), 0, 0, &absx, &absy, &dummywin)) { --- 247,262 ---- Beep(); /* ! * Get the parameters of the window being dumped; check dumpability. */ if (debug) outl("xwd: Getting target window information.\n"); if(!XGetWindowAttributes(dpy, window, &win_info)) Fatal_Error("Can't get target window attributes."); + if(!(IsViewable == win_info.map_state)) + Fatal_Error("Window doesn't appear to be viewable."); + if (0 == use_width) /* no size specified; prepare to fetch a window */ + { /* handle any frame window */ if (!XTranslateCoordinates (dpy, window, RootWindow (dpy, screen), 0, 0, &absx, &absy, &dummywin)) { *************** *** 225,230 **** --- 269,286 ---- win_info.y = absy; width = win_info.width; height = win_info.height; + } + else + { + /* use the values passed in; the rest of the calculations below + ** can be executed anyway, because window == Root in this case + */ + win_info.x = absx = use_x; + win_info.y = absy = use_y; + width = use_width; + height = use_height; + } + bw = 0; if (!nobdrs) { *************** *** 381,387 **** usage() { fprintf (stderr, ! "usage: %s [-display host:dpy] [-debug] [-help] %s [-nobdrs] [-out ]", program_name, SELECT_USAGE); fprintf (stderr, " [-xy] [-add value] [-frame]\n"); exit(1); --- 437,443 ---- usage() { fprintf (stderr, ! "usage: %s [-display host:dpy] [-debug] [-help] \n%s\n[-sleep seconds] [-nobdrs] [-out ]", program_name, SELECT_USAGE); fprintf (stderr, " [-xy] [-add value] [-frame]\n"); exit(1); *** xwd.man.orig Sat Jul 27 18:41:24 1991 --- xwd.man Thu Feb 6 10:09:58 1992 *************** *** 4,11 **** .SH SYNOPSIS .B "xwd" [-debug] [-help] [-nobdrs] [-out \fIfile\fP] [-xy] [-frame] [-add \fIvalue\fP] ! [-root | -id \fIid\fP | -name \fIname\fP ] [-icmap] [-screen] ! [-display \fIdisplay\fP] .SH DESCRIPTION .PP .I Xwd --- 4,11 ---- .SH SYNOPSIS .B "xwd" [-debug] [-help] [-nobdrs] [-out \fIfile\fP] [-xy] [-frame] [-add \fIvalue\fP] ! [-root | -id \fIid\fP | -name \fIname\fP | -geometry \fIgeom_spec\fP | -rubber] ! [-sleep \fIseconds\fP] [-icmap] [-screen] [-display \fIdisplay\fP] .SH DESCRIPTION .PP .I Xwd *************** *** 14,21 **** allows X users to store window images in a specially formatted dump file. This file can then be read by various other X utilities for redisplay, printing, editing, formatting, archiving, image processing, etc. ! The target window is selected by clicking the pointer in the desired window. ! The keyboard bell is rung once at the beginning of the dump and twice when the dump is completed. .SH OPTIONS .PP --- 14,24 ---- allows X users to store window images in a specially formatted dump file. This file can then be read by various other X utilities for redisplay, printing, editing, formatting, archiving, image processing, etc. ! The target window is selected by clicking the pointer in the desired window; ! with the -rubber option, a portion of the root window may be selected ! interactively. ! The keyboard bell is rung once at the beginning of the dump, after ! any delay, and twice when the dump is completed. .SH OPTIONS .PP *************** *** 69,74 **** --- 72,95 ---- This option indicates that the window with the specified WM_NAME property should be selected for the window dump, without requiring the user to select a window with the pointer. + .PP + .TP 8 + .B "-geometry \fIgeom_spec\fP" + This option indicates that the specified portion of the root window should be + selected for the window dump, without requiring the user to + select a window with the pointer. + .PP + .TP 8 + .B "-rubber" + This option indicates that a portion of the root window should + be selected for the window dump, with user interaction. + .PP + .TP 8 + .B "-sleep \fIseconds\fP" + This option indicates that xwd should delay for \fIseconds\fP after the + window area is specified but before dumping the window; this gives you + some time to pop up menus or do other set-up after specifying the portion + of the screen to dump. .PP .TP 8 .B "-icmap" -- David B. Lewis david%craft@uunet.uu.net (ignore bogus return address) "Sir, What was the best thing before sliced bread? Yours faithfully, Winty M. Thornton" -- The Times [London], 8 May 1991