[comp.sources.x] v03i002: cbs@cad.cs.cmu.edu, Part01/01

mikew@wyse.wyse.com (Mike Wexler) (01/18/89)

Submitted-by: interactive screen snapshot program
Posting-number: Volume 3, Issue 2
Archive-name: xsnap/part01

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  README AUTHOR Imakefile Makefile patchlevel.h xsnap.c
#   xsnap.man
# Wrapped by mikew@wyse on Tue Jan 17 16:40:30 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(981 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X
X   xsnap is a program that allows one to interactively take a 
X"snapshot" of a region of the screen.  This snapshot is then 
Xsaved to a window. I've found it useful for such things as 
Xcomparing a window's "before and after" pictures when debugging 
Xgraphics code, and quicker than using xwd and xwud when there's 
Xno other reason to save a window to a file.  However, it does eat
Xup server memory, since it creates a pixmap for each snapshot.
X
X   It also illustrates how one can have a user interactively 
Xspecify a region of the screen or of a window using rubberbanding.  
XThe code for doing so is pretty self-contained and, if one is interested, 
Xit should be pretty easy to rip it out and use it in something else.
X 
X   As with all free code: no warranty, any shape, any color.
X
X                           -- Clauss Strauch
X                   internet:  cbs@cad.cs.cmu.edu
X		       uucp:  ...!harvard!cs.cmu.edu!cbs
X                     BITnet:  cbs@cad.cs.cmu.edu%CMCCVMA
X
X
END_OF_FILE
if test 981 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'AUTHOR' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'AUTHOR'\"
else
echo shar: Extracting \"'AUTHOR'\" \(414 characters\)
sed "s/^X//" >'AUTHOR' <<'END_OF_FILE'
X
Xxsnap was written by: 
X   Clauss Strauch 
X   Engineering Design Research Center 
X   Carnegie Mellon University.
X   internet:  cbs@cad.cs.cmu.edu
X   uucp:  ...!harvard!cs.cmu.edu!cbs
X   BITnet:  cbs@cad.cs.cmu.edu%CMCCVMA
X
XPermission to use, copy, modify, and distribute xsnap and its
Xdocumentation for any purpose and without fee is hereby granted.
Xxsnap is provided "as is", without express or implied warranty.
END_OF_FILE
if test 414 -ne `wc -c <'AUTHOR'`; then
    echo shar: \"'AUTHOR'\" unpacked with wrong size!
fi
# end of 'AUTHOR'
fi
if test -f 'Imakefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Imakefile'\"
else
echo shar: Extracting \"'Imakefile'\" \(108 characters\)
sed "s/^X//" >'Imakefile' <<'END_OF_FILE'
X
XLOCAL_LIBRARIES = $(XLIB)
X           SRCS = xsnap.c
X           OBJS = xsnap.o
X
XComplexProgramTarget(xsnap)
END_OF_FILE
if test 108 -ne `wc -c <'Imakefile'`; then
    echo shar: \"'Imakefile'\" unpacked with wrong size!
fi
# end of 'Imakefile'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(6399 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile generated by imake - do not edit!
X# $XConsortium: imake.c,v 1.37 88/10/08 20:08:30 jim Exp $
X#
X# The cpp used on this machine replaces all newlines and multiple tabs and
X# spaces in a macro expansion with a single space.  Imake tries to compensate
X# for this, but is not always successful.
X#
X
X###########################################################################
X# X Window System Makefile generated from template file Imake.tmpl
X# $XConsortium: Imake.tmpl,v 1.91 88/10/23 22:37:10 jim Exp $
X#
X# Do not change the body of the imake template file.  Server-specific
X# parameters may be set in the appropriate .macros file; site-specific
X# parameters (but shared by all servers) may be set in site.def.  If you
X# make any changes, you'll need to rebuild the makefiles using
X# "make World" (at best) or "make Makefile; make Makefiles" (at least) in
X# the top level directory.
X#
X# If your C preprocessor doesn't define any unique symbols, you'll need
X# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
X# "make Makefile", "make Makefiles", or "make World").
X#
X# If you absolutely can't get imake to work, you'll need to set the
X# variables at the top of each Makefile as well as the dependencies at the
X# bottom (makedepend will do this automatically).
X#
X
X###########################################################################
X# platform-specific configuration parameters - edit Sun.macros to change
X
X# platform:  $XConsortium: Sun.macros,v 1.52 88/10/23 11:00:55 jim Exp $
X# operating system:   SunOS 3.4
X
XBOOTSTRAPCFLAGS =
X             AS = as
X             CC = cc
X            CPP = /lib/cpp
X             LD = ld
X           LINT = lint
X        INSTALL = install
X           TAGS = ctags
X             RM = rm -f
X             MV = mv
X             LN = ln -s
X         RANLIB = ranlib
XRANLIBINSTFLAGS = -t
X             AR = ar clq
X             LS = ls
X       LINTOPTS = -axz
X    LINTLIBFLAG = -C
X           MAKE = make
XSTD_CPP_DEFINES =
X    STD_DEFINES =
X
X###########################################################################
X# site-specific configuration parameters - edit site.def to change
X
X# site:  $XConsortium: site.def,v 1.16 88/10/12 10:30:24 jim Exp $
X
X###########################################################################
X# definitions common to all Makefiles - do not edit
X
X          SHELL =  /bin/sh
X
X        DESTDIR = /global
X      USRLIBDIR = $(DESTDIR)/lib
X         BINDIR = $(DESTDIR)/bin/X11
X         INCDIR = $(DESTDIR)/include
X         ADMDIR = $(DESTDIR)/usr/adm
X         LIBDIR = $(USRLIBDIR)/X11
X     LINTLIBDIR = $(USRLIBDIR)/lint
X        FONTDIR = $(LIBDIR)/fonts
X       XINITDIR = $(LIBDIR)/xinit
X         XDMDIR = $(LIBDIR)/xdm
X         UWMDIR = $(LIBDIR)/uwm
X         AWMDIR = $(LIBDIR)/awm
X         TWMDIR = $(LIBDIR)/twm
X          DTDIR = $(LIBDIR)/dt
X        MANPATH = /usr/man
X  MANSOURCEPATH = $(MANPATH)/man
X         MANDIR = $(MANSOURCEPATH)n
X      LIBMANDIR = $(MANSOURCEPATH)n3
X    XAPPLOADDIR = $(LIBDIR)/app-defaults
X
X   INSTBINFLAGS = -m 0755
X   INSTUIDFLAGS = -m 4755
X   INSTLIBFLAGS = -m 0664
X   INSTINCFLAGS = -m 0444
X   INSTMANFLAGS = -m 0444
X   INSTAPPFLAGS = -m 0444
X  INSTKMEMFLAGS = -m 4755
X        FCFLAGS = -t
X    CDEBUGFLAGS = -O
X
X        PATHSEP = /
X         DEPEND = $(BINDIR)/makedepend
X          IMAKE = $(BINDIR)/imake
X            RGB = $(LIBDIR)/rgb
X             FC = $(BINDIR)/bdftosnf
X      MKFONTDIR = $(BINDIR)/mkfontdir
X      MKDIRHIER = $(BINDIR)/mkdirhier.sh
X
X         CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(DEFINES)
X      LINTFLAGS = $(LINTOPTS) $(INCLUDES) $(STD_DEFINES) $(DEFINES) -DLINT
X        LDFLAGS = $(CDEBUGFLAGS) -L$(USRLIBDIR) $(SYS_LIBRARIES) $(SYSAUX_LIBRARIES)
X
X       IRULESRC = $(LIBDIR)/imake.includes
X
X   EXTENSIONLIB = $(USRLIBDIR)/libext.a
X           XLIB = $(USRLIBDIR)/libX11.a
X         XMULIB = $(USRLIBDIR)/libXmu.a
X        OLDXLIB = $(USRLIBDIR)/liboldX.a
X       XTOOLLIB = $(USRLIBDIR)/libXt.a
X         XAWLIB = $(USRLIBDIR)/libXaw.a
X       LINTXLIB = $(USRLIBDIR)/llib-lX11.ln
X        LINTXMU = $(USRLIBDIR)/llib-lXmu.ln
X      LINTXTOOL = $(USRLIBDIR)/llib-lXt.ln
X        LINTXAW = $(USRLIBDIR)/llib-lXaw.ln
X       INCLUDES = -I$(INCDIR)
X      MACROFILE = Sun.macros
X   ICONFIGFILES = $(IRULESRC)/Imake.tmpl \
X			$(IRULESRC)/$(MACROFILE) $(IRULESRC)/site.def
X  IMAKE_DEFINES =
X      IMAKE_CMD = $(NEWTOP)$(IMAKE) -TImake.tmpl -I$(NEWTOP)$(IRULESRC) \
X			-s Makefile $(IMAKE_DEFINES)
X         RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a \
X			.emacs_* tags TAGS make.log MakeOut
X
X###########################################################################
X# rules:  $XConsortium: Imake.rules,v 1.71 88/10/23 22:46:34 jim Exp $
X
X###########################################################################
X# start of Imakefile
X
XLOCAL_LIBRARIES = $(XLIB)
X           SRCS = xsnap.c
X           OBJS = xsnap.o
X
X PROGRAM = xsnap
X
Xall:: xsnap
X
Xxsnap: $(OBJS) $(LOCAL_LIBRARIES)
X	$(RM) $@
X	$(CC) -o $@ $(OBJS) $(LOCAL_LIBRARIES) $(LDFLAGS) $(SYSLAST_LIBRARIES)
X
Xrelink::
X	$(RM) $(PROGRAM)
X	$(MAKE) $(MFLAGS) $(PROGRAM)
X
Xinstall:: xsnap
X	$(INSTALL) -c $(INSTALLFLAGS) xsnap $(BINDIR)
X
Xinstall.man:: xsnap.man
X	$(INSTALL) -c $(INSTMANFLAGS) xsnap.man $(MANDIR)/xsnap.n
X
Xdepend:: $(DEPEND)
X
Xdepend::
X	$(DEPEND) -s "# DO NOT DELETE" -- $(CFLAGS) -- $(SRCS)
X
X$(DEPEND):
X	@echo "making $@"; \
X	cd $(DEPENDSRC); $(MAKE)
X
Xclean::
X	$(RM) $(PROGRAM)
X
X###########################################################################
X# Imake.tmpl common rules for all Makefiles - do not edit
X
Xemptyrule::
X
Xclean::
X	$(RM_CMD) \#*
X
XMakefile:: $(IMAKE)
X
XMakefile:: Imakefile \
X	$(IRULESRC)/Imake.tmpl \
X	$(IRULESRC)/Imake.rules \
X	$(IRULESRC)/site.def \
X	$(IRULESRC)/$(MACROFILE)
X	-@if [ -f Makefile ]; then \
X	echo "$(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
X	$(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
X	else exit 0; fi
X	$(IMAKE_CMD) -DTOPDIR=$(TOP)
X
X$(IMAKE):
X	@echo "making $@"; \
X	cd $(IMAKESRC); $(MAKE) BOOTSTRAPCFLAGS=$(BOOTSTRAPCFLAGS)
X
Xtags::
X	$(TAGS) -w *.[ch]
X	$(TAGS) -xw *.[ch] > TAGS
X
X###########################################################################
X# empty rules for directories that do not have SUBDIRS - do not edit
X
Xinstall::
X	@echo "install done"
X
Xinstall.man::
X	@echo "install.man done"
X
XMakefiles::
X
X###########################################################################
X# dependencies generated by makedepend
X
END_OF_FILE
if test 6399 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL 0
END_OF_FILE
if test 21 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'xsnap.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xsnap.c'\"
else
echo shar: Extracting \"'xsnap.c'\" \(18245 characters\)
sed "s/^X//" >'xsnap.c' <<'END_OF_FILE'
X/*
X *   xsnap -- take a snapshot of a portion of the screen.
X *
X *   Copyright 1989 Clauss Strauch
X *                  cbs@cad.cs.cmu.edu
X *
X *   Permission to use, copy, modify, and distribute this software and its
X *   documentation for any purpose and without fee is hereby granted.
X *   This software is provided "as is", without express or implied warranty.
X *   
X *
X */
X
X#include <stdio.h> 
X#include <X11/Xlib.h>
X#include <X11/Xos.h>
X#include <X11/Xutil.h>
X#include <X11/cursorfont.h>
X
X#ifndef TRUE
X#define TRUE 1
X#endif
X
X#ifndef FALSE
X#define FALSE 0
X#endif
X
X/*  Leave arguments as globals, since there are so many of them.
X *  They'll only be referenced in process_args and main.
X */
X
Xchar *display_string = NULL;         /* display we'll open */
Xint  border_width = 2;               /* border_width  of the snapshot window */
Xint  start_iconic = FALSE;           /* start snap window in iconic state?  */
Xchar *color_name = NULL;             /* user-supplied name of border color */
Xchar *window_geom_string = NULL;     /* geometry of snapshot window */
Xchar *icon_geom_string = NULL;       /* icon geometry */
Xchar *region_geom_string = NULL;     /* location of region to copy */
Xchar *app_name = "xsnap";            /* name of application for window manager */
Xint grab_server = TRUE;              /* grab the server? */
X
X
X/*
X *  create_event_window returns the ID of a InputOnly window that covers
X *  the given window.
X */
X
XWindow create_event_window(a_display,a_window, init_cursor)
XDisplay *a_display;
XWindow a_window;
X{
X	XSetWindowAttributes xswa;
X	unsigned long xswa_valuemask;
X	Window root_win;
X	Window event_window;
X	unsigned int win_width, win_height;
X	unsigned int  win_border_width, win_depth;
X	int win_x, win_y;
X
X	/* get the geometry of the window  */
X
X	XGetGeometry(a_display, a_window, &root_win, &win_x, &win_y,
X	    &win_width, &win_height, &win_border_width, &win_depth);
X
X	/* make an input only window to get events from  */
X
X	xswa.cursor = init_cursor;
X	xswa.override_redirect = True;
X	xswa.event_mask = ButtonPressMask | ButtonReleaseMask | Button1MotionMask;
X	xswa_valuemask = CWCursor | CWOverrideRedirect | CWEventMask;
X	event_window = XCreateWindow(a_display, a_window, win_x, win_y, win_width,
X	    win_height, 0, 0, InputOnly, CopyFromParent, 
X	    xswa_valuemask, &xswa);
X	return(event_window);
X}
X
X/*
X *   draw box draws a box on the given window, with the given GC 
X *
X */
X
Xvoid draw_box(a_display, a_window, a_gc, x1, y1, x2, y2)
XGC a_gc;
XWindow a_window;
XDisplay *a_display;
Xint x1, y1, x2, y2;
X{
X	XSegment segments[4];
X	segments[0].x1 = (short)x1;
X	segments[0].y1 = (short)y1;
X	segments[0].x2 = (short)x1;
X	segments[0].y2 = (short)y2;
X
X	segments[1].x1 = (short)x1;
X	segments[1].y1 = (short)y1;
X	segments[1].x2 = (short)x2;
X	segments[1].y2 = (short)y1;
X
X	segments[2].x1 = (short)x2;
X	segments[2].y1 = (short)y2;
X	segments[2].x2 = (short)x1;
X	segments[2].y2 = (short)y2;
X
X	segments[3].x1 = (short)x2;
X	segments[3].y1 = (short)y2;
X	segments[3].x2 = (short)x2;
X	segments[3].y2 = (short)y1;
X
X	XDrawSegments(a_display, a_window, a_gc, segments, 4);
X}
X
X/*
X *  get_region
X * takes as input:
X *    display
X *    window to get region from 
X *    pointers to x1, y1, width, height
X *  
X *   returns:  the position and width and height of a
X *             user selected region via the given pointers.
X *
X */
X
X
Xget_region(a_display, a_window,  x, y, width, height)
XDisplay *a_display;
XWindow a_window;
Xint *x, *y;
Xunsigned int *height, *width;
X
X{
X	Window event_window;
X	Cursor up_right_curs, up_left_curs;
X	Cursor low_right_curs, low_left_curs;
X	Cursor current_cursor;
X	int done;
X	int init_x, init_y;
X	int last_x, last_y;
X	XEvent event;
X	GC xor_gc;
X	XGCValues xor_gc_values;             /* for creating xor_gc */
X	unsigned long xor_gc_valuemask;       /* valuemask for creating xor_gc */
X
X	/* make the GC and cursors we'll need */
X
X	up_right_curs = XCreateFontCursor(a_display, XC_ur_angle);
X
X	up_left_curs = XCreateFontCursor(a_display, XC_ul_angle);
X
X	low_right_curs = XCreateFontCursor(a_display, XC_lr_angle);
X	
X	low_left_curs = XCreateFontCursor(a_display, XC_ll_angle);
X	
X
X
X	xor_gc_valuemask = GCFunction | GCSubwindowMode  | GCForeground;
X	xor_gc_values.function = GXxor;
X	xor_gc_values.foreground = 0xfd;
X	xor_gc_values.subwindow_mode = IncludeInferiors;
X	xor_gc = XCreateGC(a_display, a_window, xor_gc_valuemask, &xor_gc_values);
X
X	event_window = create_event_window(a_display, a_window,up_left_curs);
X	XMapRaised(a_display, event_window);
X
X
X	if (XGrabPointer(a_display, event_window, True, 
X	    ButtonPressMask,
X	    GrabModeAsync, GrabModeAsync, None, up_left_curs, 
X			 CurrentTime) != 0)
X	  {
X	    fprintf(stderr, "Cannot grab pointer.");
X	    exit(1);
X	  }
X
X
X	/* get the initial button  press */
X	done = FALSE;
X	while (! done)
X	{
X		XNextEvent(a_display, &event);
X		switch(event.type)
X		{
X		case MappingNotify:
X			XRefreshKeyboardMapping(&event);
X			break;
X		case ButtonPress:
X			if (event.xbutton.button == 1)
X			{
X				init_x = event.xbutton.x;
X				init_y = event.xbutton.y;
X
X
X				done = TRUE;
X				break;
X			}
X		}
X	}
X
X
X	/*  now we have the location of one corner of the box.   change the cursor,
X *  and have the user drag out the area.
X */
X	current_cursor = low_right_curs;
X	last_x = init_x;
X	last_y = init_y;
X	XChangeActivePointerGrab(a_display, ButtonReleaseMask | Button1MotionMask,
X	    current_cursor, CurrentTime);
X	done = FALSE;
X	draw_box(a_display, a_window, xor_gc, init_x, init_y, last_x, last_y);
X	while (! done)
X	{
X		XNextEvent(a_display, &event);
X		switch(event.type)
X		{
X		case MappingNotify:
X			XRefreshKeyboardMapping(&event);
X			break;
X		case MotionNotify:
X			draw_box(a_display, a_window, xor_gc, 
X			    init_x, init_y, last_x, last_y);  /* erase old */
X			last_x = event.xmotion.x;
X			last_y = event.xmotion.y;
X			draw_box(a_display, a_window, xor_gc, 
X			    init_x, init_y, last_x, last_y); /* draw new  */
X			/*  Change cursor to correspond to position of pointer */
X			if ((init_x < last_x) && (init_y < last_y)
X			    && (current_cursor != low_right_curs))
X			{
X				current_cursor = low_right_curs;
X				XChangeActivePointerGrab(a_display, 
X				    ButtonReleaseMask | Button1MotionMask,
X				    low_right_curs, CurrentTime);
X			}
X			else if ((last_x < init_x) && (last_y < init_y)
X			    &&  (current_cursor != up_left_curs))
X			{
X				current_cursor = up_left_curs;
X				XChangeActivePointerGrab(a_display, 
X				    ButtonReleaseMask | Button1MotionMask,
X				    up_left_curs, CurrentTime);
X			}
X
X			else if ((init_x < last_x) && (last_y < init_y)
X			    && (current_cursor != up_right_curs))
X			{
X				current_cursor = up_right_curs;
X				XChangeActivePointerGrab(a_display, 
X				    ButtonReleaseMask | Button1MotionMask,
X				    up_right_curs, CurrentTime);
X
X			}
X			else if ((last_x < init_x) && (init_y < last_y)
X			    && (current_cursor != low_left_curs))
X			{
X				current_cursor = low_left_curs;
X				XChangeActivePointerGrab(a_display, 
X				    ButtonReleaseMask | Button1MotionMask,
X				    low_left_curs, CurrentTime);
X			}
X
X			break;
X		case ButtonRelease:
X			if (event.xbutton.button == 1)
X			{
X				done = TRUE;
X				draw_box(a_display, a_window, xor_gc, 
X				    init_x, init_y, last_x, last_y);  /* erase last box drawn */
X			}
X			break;
X		}
X	}
X	XFlush(a_display);   /*  gets rid of last box on screen  */
X	if (init_x < last_x) *x = init_x;
X	else *x = last_x;
X	if (init_y < last_y) *y = init_y;
X	else *y = last_y;
X	*width = (unsigned int)abs(last_x - init_x);
X	*height = (unsigned int)abs(last_y - init_y);
X	/* clean up after ourself: */
X
X	XDestroyWindow(a_display, event_window);
X	XFreeGC(a_display, xor_gc);
X
X	/* we'll let the caller ungrab the pointer */
X
X}
X
X/* 
X *  get_pixmap_region 
X *
X *       input :
X *               a display, a window, x, y, width, height, interactive.
X *               if interactive, the user is prompted for a region,
X *               other wise the given region is copied to a pixmap.
X *       returns : a pixmap containing a copy of a user-specified area
X *                 of the given window;
X *
X */
X
XPixmap get_pixmap_region(a_display, a_screen, a_window, a_gc,  x, y, 
Xwidth, height,  interactive)
XDisplay *a_display;
XGC a_gc;
Xint a_screen;
XWindow a_window;
Xint *x, *y;
Xunsigned int *width, *height;
Xint interactive;
X
X{
X	int reg_x, reg_y;
X	unsigned int reg_width, reg_height;
X	Pixmap pixmap_returned;
X	int return_flag;
X
X	if (interactive){
X		get_region(a_display, a_window, &reg_x, &reg_y,
X		    &reg_width, &reg_height);
X		*x = reg_x;
X		*y = reg_y;
X		*width = reg_width;
X		*height = reg_height;
X	}
X
X	/* 
X   *  we should really use the depth of the given window for the
X   *  depth of the pixmap.
X   */
X
X	pixmap_returned = XCreatePixmap(a_display, 
X					DefaultRootWindow(a_display),
X					*width, *height, 
X					DefaultDepth(a_display, a_screen));
X
X	/*  now copy the area we specified  */
X
X	XCopyArea(a_display, a_window, pixmap_returned, a_gc, *x, *y, 
X		  *width, *height, 0, 0);
X	if (interactive)  XUngrabPointer(a_display, CurrentTime);
X	return(pixmap_returned);
X}
X
X
X/* 
X *  X error handler for,  mainly for future use
X */
X
Xint my_X_error_handler(display, myerr)
XDisplay *display;
XXErrorEvent *myerr;
X{
X  char msg[80];  
X
X/* if we get a BadAlloc error, it's probably 'cuz we couldn't allocate
X * the pixmap.  Tell the user this.
X */
X  fprintf(stderr,"xsnap:\n"); 
X  if ((myerr->error_code) == BadAlloc)   
X    {
X      fprintf(stderr, "Insufficient resources for operation.\n");
X      fprintf(stderr, "Probably not enough memory to allocate pixmap.\n");
X    }
X
X/* Now print out the error string that X generates */
X  
X  XGetErrorText(display, myerr->error_code, msg,80);
X  fprintf(stderr, "Error code %s\n", msg);
X/* no way to continue, so we'll just bag it  */
X  exit(1);
X}
X  
X
X/*
X *  print a usage message to the user
X */
X
Xusage()
X{
X	printf("%s\n", "Usage:  xsnap [-options...]");
X	printf("%s\n", "Where options are:");
X	printf("%s\n", "[-display host:display]  Display to connect to.");
X	printf("%s\n", "[-bd borderwidth]        Color of border");
X	printf("%s\n", "[-bw borderwidth]        Width of border");
X	printf("%s\n", "[-geometry geom]         Geometry of snapshot window");
X	printf("%s\n", "[-icongeometry geom]     Location of icon.");
X	printf("%s\n", "[-region geom]           Region of screen to be copied.");
X	printf("%s\n", "[-iconic]                Start up in iconic state");
X	printf("%s\n", "[-name name]             Passed to window manager for name of window.");
X	printf("%s\n", "[-nograb]                Don't grab server during specification of region.");
X	exit(1);
X}
X
X
X/*
X *        get the arguments.   arguments are matched to the first
X *        distinguishing substring.
X */
Xprocess_args(argc, argv)
Xint argc;
Xchar **argv;
X{
X	int i;
X
X	for (i = 1; i < argc; i++)
X	{
X		if (strncmp(argv[i], "-h", 2) == 0)
X		{
X			usage();
X			continue;
X		}
X		if (strncmp(argv[i], "-display", 2) == 0)
X		{
X			display_string = argv[++i];
X			continue;
X		}
X		if (strncmp(argv[i], "-bw", 3) == 0)
X		{
X			border_width = atoi(argv[++i]);
X			continue;
X		}
X		if (strncmp(argv[i], "-bd", 3) == 0)
X		{
X			color_name = argv[++i];
X			continue;
X		}
X		if (strncmp(argv[i], "-ge", 3) == 0)
X		{
X			window_geom_string = argv[++i];
X			continue;
X		}
X		if (strncmp(argv[i], "-icong", 6) == 0)
X		{
X			icon_geom_string = argv[++i];
X			continue;
X		}
X		if (strncmp(argv[i], "-r", 2) == 0)
X		{
X			region_geom_string = argv[++i];
X			continue;
X		}
X		if (strncmp(argv[i], "-iconi", 6) == 0)
X		{
X			start_iconic = TRUE;
X			continue;
X		}
X		if (strncmp(argv[i], "-na", 3) == 0)
X		{
X			app_name = argv[++i];
X			continue;
X		}
X		if (strncmp(argv[i], "-no", 3) == 0)
X		{
X			grab_server = FALSE;
X			continue;
X		}
X		usage();
X	}
X}
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	Display *the_display;
X	int the_screen;
X	XWMHints wmhints;
X	XEvent an_event;
X	GC copy_gc;
X	unsigned long copy_gc_valuemask;
X	XGCValues copy_gc_values;
X	long wmhints_mask;
X	XSizeHints wm_size_hints;
X	int x_return, y_return;           /* for XParseGeometry */
X	int width_return, height_return;  /* ditto              */
X	int geom_mask;                    /* bitmask for XParseGeometry fields */
X	unsigned long border_color_pixel; /* pixel for border color */
X	XColor color;
X	Colormap cmap;
X	Window window_to_snap;            /* always root window, now */
X	Window snapshot;
X	Cursor snap_cursor;
X	Pixmap  snap_pixmap;
X	int reg_x, reg_y;
X	int icon_x, icon_y;
X	int snap_x, snap_y;
X	unsigned int snap_width, snap_height;
X	unsigned int reg_width, reg_height;
X	int done;
X	char buffer [4];                     /* key press buffer for XLookupString  */
X	int string_length;                       /* length of returned string */
X
X	process_args(argc, argv);
X	XSetErrorHandler(my_X_error_handler);
X	if ((the_display = XOpenDisplay(display_string)) == NULL)
X	  {
X	    
X	    fprintf(stderr, "Cannot open display:    %s\n", 
X		    XDisplayName(display_string));
X	    exit(1);
X	  }
X	XSetErrorHandler(my_X_error_handler);
X	the_screen = DefaultScreen(the_display);
X	window_to_snap = XRootWindow(the_display, the_screen);
X
X	/* make copy GC */
X
X	copy_gc_valuemask = GCSubwindowMode;
X	copy_gc_values.subwindow_mode = IncludeInferiors;
X	copy_gc = XCreateGC(the_display, window_to_snap, copy_gc_valuemask, &copy_gc_values);
X
X	if (grab_server)
X	{
X		XGrabServer(the_display);
X		XSync(the_display, 0);
X	}
X
X	if (region_geom_string)
X	{
X		geom_mask = XParseGeometry(region_geom_string, &reg_x, &reg_y,
X		    &reg_width, &reg_height);
X		if ((geom_mask & XValue) && (geom_mask & YValue) &&
X		    (geom_mask & WidthValue) && (geom_mask & HeightValue))
X		/* must specify complete geometry for region */
X		{
X			if (geom_mask & XNegative)
X				reg_x += DisplayWidth(the_display, the_screen) - reg_width;
X			if (geom_mask & YNegative)
X				reg_y += DisplayHeight(the_display, the_screen) - reg_height;
X			snap_pixmap = get_pixmap_region(the_display, the_screen, 
X			    window_to_snap, copy_gc,
X			    &reg_x, &reg_y, &reg_width, 
X			    &reg_height, FALSE);
X		}
X		else usage();
X	}
X	else 
X		snap_pixmap = get_pixmap_region(the_display, the_screen,window_to_snap, copy_gc,
X		    &reg_x, &reg_y, &reg_width, &reg_height, TRUE);
X
X	/* ungrab the server */
X
X	XUngrabServer(the_display);
X
X	/* process border color */
X
X	cmap = DefaultColormap(the_display, the_screen);
X	if ((color_name) && (XParseColor(the_display, cmap, color_name, &color)) &&
X	    (XAllocColor(the_display, cmap, &color)))
X		border_color_pixel = color.pixel;
X	else
X		border_color_pixel = WhitePixel(the_display, the_screen);
X
X
X
X
X
X	/*
X * get location of our window(from the window_geom_string),
X * and set up the size hints structure.
X */     
X	wm_size_hints.flags = 0;
X	width_return = reg_width;
X	height_return = reg_height;
X	if (window_geom_string)
X	{
X		geom_mask = XParseGeometry(window_geom_string, &x_return, 
X					   &y_return, &width_return, 
X					   &height_return);
X		if (geom_mask & XValue)
X		{
X			if (geom_mask & XNegative)
X				wm_size_hints.x = DisplayWidth(the_display, 
X							       the_screen)
X				    - width_return + x_return - 
X				      (border_width * 2);
X			else
X				wm_size_hints.x = x_return;
X		}
X		if (geom_mask & YValue)
X		{
X			if (geom_mask & YNegative)
X				wm_size_hints.y =  
X				  DisplayHeight(the_display, the_screen)
X				    - height_return + y_return  - 
X				      (border_width * 2);
X
X			else
X				wm_size_hints.y = y_return;
X		}
X
X	}
X
X	if ((geom_mask & XValue) || (geom_mask & YValue))
X	  wm_size_hints.flags |= USPosition;
X
X	if ((geom_mask & WidthValue) || (geom_mask & HeightValue))
X	  wm_size_hints.flags |= USSize;
X	  wm_size_hints.width = width_return;
X	  wm_size_hints.height = height_return;
X	    
X
X	snapshot = XCreateSimpleWindow(the_display, 
X	    XRootWindow(the_display, the_screen), 
X	    wm_size_hints.x, wm_size_hints.y,
X            wm_size_hints.width, 
X            wm_size_hints.height, border_width,
X	    border_color_pixel,
X	    BlackPixel(the_display, the_screen));
X
X	if (window_geom_string)
X		XSetNormalHints(the_display, snapshot, &wm_size_hints);
X	XStoreName(the_display, snapshot, app_name);
X	wmhints_mask = 0;
X	if (start_iconic)
X	{
X		wmhints_mask |= StateHint;
X		wmhints.initial_state = IconicState;
X	}
X	x_return = y_return = 0;
X
X	/* Icon geometry is sorta broken, since we don't supply an icon, and 
X * there isn't any way I know of to get the geometry  of the icon that
X * the window manager will provide.   So, we'll pretend that our icon 
X * is 32x32 (ugh).
X */
X
X	if (icon_geom_string)
X	{
X		geom_mask = XParseGeometry(icon_geom_string, &x_return, 
X		    &y_return, &width_return, 
X		    &height_return);
X		if (geom_mask & XValue)
X		{
X			if (geom_mask & XNegative)
X				wmhints.icon_x = DisplayWidth(the_display, 
X				    the_screen)
X				    - 32 + x_return - (border_width * 2);
X			else
X				wmhints.icon_x = x_return;
X		}
X		if (geom_mask & YValue)
X		{
X			if (geom_mask & YNegative)
X				wmhints.icon_y =  DisplayHeight(the_display, 
X				    the_screen)
X				    - 32 + y_return  - (border_width * 2);
X
X			else
X				wmhints.icon_y = y_return;
X		}
X		wmhints_mask |= IconPositionHint;
X	}
X
X
X	if (wmhints_mask)
X	{
X		wmhints.flags = wmhints_mask;
X		XSetWMHints(the_display, snapshot, &wmhints);
X	}
X
X	/* solicit expose events */
X
X	XSelectInput(the_display, snapshot, ExposureMask | KeyPressMask);
X
X	/* give it a different cursor */
X
X	snap_cursor = XCreateFontCursor(the_display, XC_gumby);
X
X	XDefineCursor(the_display, snapshot, snap_cursor);
X
X	/* map it */
X
X	XMapRaised(the_display, snapshot);
X
X	/* process events */
X	done = FALSE;
X
X	while (! done)
X	{
X		XNextEvent(the_display, &an_event);
X		switch (an_event.type)
X		{
X		case MappingNotify:
X			XRefreshKeyboardMapping(&an_event);
X			break;
X		case Expose:
X			XCopyArea(the_display, snap_pixmap, snapshot, copy_gc, 
X			    an_event.xexpose.x, 
X			    an_event.xexpose.y, 
X			    an_event.xexpose.width, 
X			    an_event.xexpose.height, 
X			    an_event.xexpose.x, 
X			    an_event.xexpose.y);
X			break;
X		case KeyPress:
X			string_length = XLookupString(&an_event, buffer, 
X			    sizeof(buffer),
X			    NULL, NULL);
X			if ((string_length == 1) && ((buffer[0] == 'q') ||
X			    (buffer[0] == 'Q') ||
X			    (buffer[0] == '\003')))
X
X			/*  clean up  */
X			{
X				XDestroyWindow(the_display, snapshot);
X				XFreePixmap(the_display, snap_pixmap);
X				XFreeGC(the_display, copy_gc);
X				XCloseDisplay(the_display);
X				done = TRUE;
X				exit(0);
X				break;
X			}
X		}
X	}
X
X}
END_OF_FILE
if test 18245 -ne `wc -c <'xsnap.c'`; then
    echo shar: \"'xsnap.c'\" unpacked with wrong size!
fi
# end of 'xsnap.c'
fi
if test -f 'xsnap.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xsnap.man'\"
else
echo shar: Extracting \"'xsnap.man'\" \(1972 characters\)
sed "s/^X//" >'xsnap.man' <<'END_OF_FILE'
X.TH XSNAP 1
X.PD
X.ad b
X.SH NAME
Xxsnap \- Take a snapshot of a region of the screen
X.SH SYNOPSIS
X\fBxsnap\fR
X[\|\fB-display\fR displayname\|] 
X[\|\fB-bd\fR border\|] 
X[\|\fB-bw\fR borderwidth\|] 
X[\|\fB-geometry\fR geometry\|] 
X[\|\fB-icongeometry\fR icongeometry\|] 
X[\|\fB-region\fR geometry\|] 
X[\|\fB-iconic\fR\|] 
X[\|\fB-nograb\fR\|] 
X[\|\fB-name\fR name\|] 
X.SH DESCRIPTION
X.PP
XThe \fIxsnap\fP program allows one to take a snapshot of
Xa specified region of the screen.  If \fIxsnap\fP is run without a region being 
Xspecified,  the  user is prompted to interactively drag one out with the mouse.
XIn this case, pressing button 1 will select one corner of the region, and an opposite
Xcorner will be selected upon the release of button 1.   A window whose contents are a
Xcopy of this region is then created.
XPressing "Q", "q", or "^C" in this  window will exit the program.
X.SH OPTIONS
X.TP 8
X.B \-display \fIdisplay\fP
XSpecifies the display to use for both specifying and displaying the region.
X.TP 8
X.B \-bd \fIborder\fP
XBorder color of snapshot window.  Defaults to white.
X.TP 8
X.B \-bw \fIborder width\fP
XBorder width of snapshot window.  Defaults to 2.
X.TP 8
X.B \-geometry \fIgeom\fP
XGeometry of snapshot window.  
X.TP 8
X.B \-icongeometry \fIgeom\fp
XGeometry of icon.
X.TP 8
X.B \-iconic
XIf specified, snapshot window will start up in iconic state.
X.TP 8
X.B \-nograb
XDo not grab the server during specification of region.
X.TP 8
X.B \-name \fIname\fp
XName for icon to be passed to window manager.
X.TP 8
X.B \-region \fIgeom\fP
XThe size and  location on the screen of the region to be copied.
X.SH BUGS
X.br
XNo support for colormaps.
X.br
XIncorrect behavior may result on displays that support windows of different depths.
X.br
XSince it creates a pixmap for each snapshot,  it can chew up server memory very fast.
X.br
XThe icongeometry option  doesn't know about icon sizes.
X.SH AUTHOR
XClauss Strauch
X.br
XEngineering Design Research Center
X.br
XCarnegie Mellon University
X
X
X
X
X
X
X
END_OF_FILE
if test 1972 -ne `wc -c <'xsnap.man'`; then
    echo shar: \"'xsnap.man'\" unpacked with wrong size!
fi
# end of 'xsnap.man'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330
Moderator of comp.sources.x