Edit

IABSD.fr/xenocara/app/bitmap/Bitmap.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-25 20:07:29
    Hash : 616b6f15
    Message : Importing from X.Org 7.2RC2

  • app/bitmap/Bitmap.c
  • /* $Xorg: Bitmap.c,v 1.4 2001/02/09 02:05:28 xorgcvs Exp $ */
    /*
    
    Copyright 1989, 1998  The Open Group
    
    Permission to use, copy, modify, distribute, and sell this software and its
    documentation for any purpose is hereby granted without fee, provided that
    the above copyright notice appear in all copies and that both that
    copyright notice and this permission notice appear in supporting
    documentation.
    
    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.
    
    Except as contained in this notice, the name of The Open Group shall
    not be used in advertising or otherwise to promote the sale, use or
    other dealings in this Software without prior written authorization
    from The Open Group.
    
    */
    /* $XFree86: Bitmap.c,v 1.5 2001/12/26 21:39:34 paulo Exp $ */
    
    /*
     * Author:  Davor Matic, MIT X Consortium
     */
    
    #include <X11/IntrinsicP.h>
    #include <X11/StringDefs.h>
    #include <X11/Xaw/XawInit.h>
    #include <X11/Xmu/CharSet.h>
    #include <X11/Xmu/Drawing.h>
    #include <X11/Xmu/SysUtil.h>
    #include <X11/Xatom.h>
    #include <X11/Xfuncs.h>
    #include <X11/Xos.h>
    #include "BitmapP.h"
    #include "Bitmap.h"
        
    #include <stdio.h>
    #include <math.h>
    
    #define min(x, y)                     ((((int)(x)) < (int)(y)) ? (x) : (y))
    #define max(x, y)                     ((((int)(x)) > (int)(y)) ? (x) : (y))
    
    Boolean DEBUG;
    
    #define DefaultGridTolerance 8
    #define DefaultBitmapSize    "16x16"
    #define FallbackBitmapWidth  16
    #define FallbackBitmapHeight 16
    #define DefaultGrid          TRUE
    #define DefaultDashed        TRUE
    #define DefaultStippled      TRUE
    #define DefaultProportional  TRUE
    #define DefaultAxes          FALSE
    #define DefaultMargin        16
    #define DefaultSquareWidth   16
    #define DefaultSquareHeight  16
    #define DefaultFilename      ""
    
    #define Offset(field) XtOffsetOf(BitmapRec, bitmap.field)
    
    static XtResource resources[] = {
    {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
         Offset(foreground_pixel), XtRString, XtDefaultForeground},
    {XtNhighlight, XtCHighlight, XtRPixel, sizeof(Pixel),
         Offset(highlight_pixel), XtRString, XtDefaultForeground},
    {XtNframe, XtCFrame, XtRPixel, sizeof(Pixel),
         Offset(frame_pixel), XtRString, XtDefaultForeground},
    {XtNgridTolerance, XtCGridTolerance, XtRDimension, sizeof(Dimension),
         Offset(grid_tolerance), XtRImmediate, (XtPointer) DefaultGridTolerance},
    {XtNsize, XtCSize, XtRString, sizeof(String),
         Offset(size), XtRImmediate, (XtPointer) DefaultBitmapSize},
    {XtNdashed, XtCDashed, XtRBoolean, sizeof(Boolean),
         Offset(dashed), XtRImmediate, (XtPointer) DefaultDashed},
    {XtNgrid, XtCGrid, XtRBoolean, sizeof(Boolean),
         Offset(grid), XtRImmediate, (XtPointer) DefaultGrid},
    {XtNstippled, XtCStippled, XtRBoolean, sizeof(Boolean),
         Offset(stippled), XtRImmediate, (XtPointer) DefaultStippled},
    {XtNproportional, XtCProportional, XtRBoolean, sizeof(Boolean),
         Offset(proportional), XtRImmediate, (XtPointer) DefaultProportional},
    {XtNaxes, XtCAxes, XtRBoolean, sizeof(Boolean),
         Offset(axes), XtRImmediate, (XtPointer) DefaultAxes},
    {XtNsquareWidth, XtCSquareWidth, XtRDimension, sizeof(Dimension),
         Offset(squareW), XtRImmediate, (XtPointer) DefaultSquareWidth},
    {XtNsquareHeight, XtCSquareHeight, XtRDimension, sizeof(Dimension),
         Offset(squareH), XtRImmediate, (XtPointer) DefaultSquareHeight},
    {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
         Offset(margin), XtRImmediate, (XtPointer) DefaultMargin},
    {XtNxHot, XtCXHot, XtRPosition, sizeof(Position),
         Offset(hot.x), XtRImmediate, (XtPointer) NotSet},
    {XtNyHot, XtCYHot, XtRPosition, sizeof(Position),
         Offset(hot.y), XtRImmediate, (XtPointer) NotSet},
    {XtNbutton1Function, XtCButton1Function, XtRButtonFunction, sizeof(int),
         Offset(button_function[0]), XtRImmediate, (XtPointer) Set},
    {XtNbutton2Function, XtCButton2Function, XtRButtonFunction, sizeof(int),
         Offset(button_function[1]), XtRImmediate, (XtPointer) Invert},
    {XtNbutton3Function, XtCButton3Function, XtRButtonFunction, sizeof(int),
         Offset(button_function[2]), XtRImmediate, (XtPointer) Clear},
    {XtNbutton4Function, XtCButton4Function, XtRButtonFunction, sizeof(int),
         Offset(button_function[3]), XtRImmediate, (XtPointer) Clear},
    {XtNbutton5Function, XtCButton5Function, XtRButtonFunction, sizeof(int),
         Offset(button_function[4]), XtRImmediate, (XtPointer) Clear},
    {XtNfilename, XtCFilename, XtRString, sizeof(String),
         Offset(filename), XtRImmediate, (XtPointer) DefaultFilename},
    {XtNbasename, XtCBasename, XtRString, sizeof(String),
         Offset(basename), XtRImmediate, (XtPointer) DefaultFilename},
    {XtNdashes, XtCDashes, XtRBitmap, sizeof(Pixmap),
         Offset(dashes), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
    {XtNstipple, XtCStipple, XtRBitmap, sizeof(Pixmap),
         Offset(stipple), XtRImmediate, (XtPointer) XtUnspecifiedPixmap},
    };
    #undef Offset
    
    
    static XtActionsRec actions[] =
    {
    {"mark",               (XtActionProc)BWTMark},
    {"mark-all",           (XtActionProc)BWTMarkAll},
    {"unmark",             (XtActionProc)BWTUnmark},
    {"paste",              (XtActionProc)BWTPaste},
    {"bw-debug",           (XtActionProc)BWDebug},
    {"abort",              (XtActionProc)BWAbort},
    {"store-to-buffer",    (XtActionProc)BWStoreToBuffer},
    {"change-notify",      (XtActionProc)BWChangeNotify},
    {"set-changed",        (XtActionProc)BWSetChanged},
    {"up",                 (XtActionProc)BWUp},
    {"down",               (XtActionProc)BWDown},
    {"left",               (XtActionProc)BWLeft},
    {"right",              (XtActionProc)BWRight},
    {"fold",               (XtActionProc)BWFold},
    {"flip-horiz",         (XtActionProc)BWFlipHoriz},
    {"flip-vert",          (XtActionProc)BWFlipVert},
    {"rotate-right",       (XtActionProc)BWRotateRight},
    {"rotate-left",        (XtActionProc)BWRotateLeft},
    {"set",                (XtActionProc)BWSet},
    {"clear",              (XtActionProc)BWClear},
    {"invert",             (XtActionProc)BWInvert},
    {"undo",               (XtActionProc)BWUndo},
    {"redraw",             (XtActionProc)BWRedraw},
    };
    
    static char translations1[] =
    "\
    Shift<Btn1Down>: mark()\n\
    Shift<Btn2Down>: mark-all()\n\
    Shift<Btn3Down>: unmark()\n\
    Ctrl<BtnDown>:   paste()\n\
    Ctrl<Key>l: redraw()\n\
    <Key>d:     bw-debug()\n\
    <Key>a:     abort()\n\
    <Key>Up:    store-to-buffer()\
                up()\
                change-notify()\
                set-changed()\n\
    <Key>KP_Up: store-to-buffer()\
                up()\
                change-notify()\
                set-changed()\n\
    <Key>Down:  store-to-buffer()\
                down()\
                change-notify()\
                set-changed()\n\
    <Key>KP_Down: store-to-buffer()\
                down()\
                change-notify()\
                set-changed()\n\
    <Key>Left:  store-to-buffer()\
                left()\
                change-notify()\
                set-changed()\n\
    <Key>KP_Left: store-to-buffer()\
                left()\
                change-notify()\
                set-changed()\n\
    <Key>Right: store-to-buffer()\
                right()\
                change-notify()\
                set-changed()\n\
    <Key>KP_Right: store-to-buffer()\
                right()\
                change-notify()\
                set-changed()\n\
    <Key>f:     store-to-buffer()\
                fold()\
                change-notify()\
                set-changed()\n\
    <Key>h:     store-to-buffer()\
                flip-horiz()\
                change-notify()\
                set-changed()\n\
    ";
    
    static char translations2[] =
    "<Key>v:     store-to-buffer()\
                flip-vert()\
                change-notify()\
                set-changed()\n\
    <Key>r:     store-to-buffer()\
                rotate-right()\
                change-notify()\
                set-changed()\n\
    <Key>l:     store-to-buffer()\
                rotate-left()\
                change-notify()\
                set-changed()\n\
    <Key>s:     store-to-buffer()\
                set()\
                change-notify()\
                set-changed()\n\
    <Key>c:     store-to-buffer()\
                clear()\
                change-notify()\
                set-changed()\n\
    <Key>i:     store-to-buffer()\
                invert()\
                change-notify()\
                set-changed()\n\
    <Key>u:     undo()\
                change-notify()\
                set-changed()\n\
    ";
    
    Atom targets[] = {
        XA_BITMAP,
        XA_PIXMAP
    };
    
    #include "Requests.h"
    
    
    static BWRequestRec requests[] = 
    {
    {MarkRequest, sizeof(BWStatus),
         TwoPointsEngage, (XtPointer) BWDrawRectangle,
         TwoPointsTerminateTimed, (XtPointer) BWSelect,
         NULL, (XtPointer) NULL},
    {RestoreRequest, sizeof(BWStatus),
         OnePointEngage, (XtPointer) BWDragStored,
         OnePointTerminate, (XtPointer) BWRestore,
         NULL, (XtPointer) NULL},
    {ImmediateCopyRequest, sizeof(BWStatus),
         OnePointEngage, (XtPointer) BWDragMarked,
         OnePointTerminate, (XtPointer) BWCopy,
         NULL, (XtPointer) NULL},
    {ImmediateMoveRequest, sizeof(BWStatus),
         OnePointEngage, (XtPointer) BWDragMarked,
         OnePointTerminate, (XtPointer) BWMove,
         NULL, (XtPointer) NULL},
    {CopyRequest, sizeof(BWStatus),
         DragOnePointEngage, (XtPointer) Paste,
         DragOnePointTerminate, (XtPointer) ImmediateCopyRequest,
         Interface, (XtPointer) BWUnmark},
    {MoveRequest, sizeof(BWStatus),
         DragOnePointEngage, (XtPointer) Paste,
         DragOnePointTerminate, (XtPointer) ImmediateMoveRequest,
         Interface, (XtPointer) BWUnmark},
    {PointRequest, sizeof(BWStatus),
         DragOnePointEngage, (XtPointer) BWDrawPoint,
         DragOnePointTerminate, (XtPointer) BWDrawPoint,
         NULL, (XtPointer) NULL},
    {CurveRequest, sizeof(BWStatus),
         DragTwoPointsEngage, (XtPointer) BWBlindLine,
         DragTwoPointsTerminate, (XtPointer) BWBlindLine,
         NULL, (XtPointer) NULL},
    {LineRequest, sizeof(BWStatus), 
         TwoPointsEngage, (XtPointer) BWDrawLine, 
         TwoPointsTerminate, (XtPointer) BWDrawLine,
         NULL, (XtPointer) NULL},
    {RectangleRequest, sizeof(BWStatus), 
         TwoPointsEngage, (XtPointer) BWDrawRectangle,
         TwoPointsTerminate, (XtPointer) BWDrawRectangle,
         NULL, (XtPointer) NULL},
    {FilledRectangleRequest, sizeof(BWStatus), 
         TwoPointsEngage, (XtPointer) BWDrawRectangle,
         TwoPointsTerminate, (XtPointer) BWDrawFilledRectangle,
         NULL, (XtPointer) NULL},
    {CircleRequest, sizeof(BWStatus), 
         TwoPointsEngage, (XtPointer) BWDrawCircle,
         TwoPointsTerminate, (XtPointer) BWDrawCircle,
         NULL, (XtPointer) NULL},
    {FilledCircleRequest, sizeof(BWStatus), 
         TwoPointsEngage, (XtPointer) BWDrawCircle, 
         TwoPointsTerminate, (XtPointer) BWDrawFilledCircle,
         NULL, (XtPointer) NULL},
    {FloodFillRequest, sizeof(BWStatus),
         OnePointEngage, (XtPointer) NULL,
         OnePointTerminate, (XtPointer) BWFloodFill,
         NULL, (XtPointer) NULL},
    {HotSpotRequest, sizeof(BWStatus),
         OnePointEngage, (XtPointer) BWDrawHotSpot,
         OnePointTerminate, (XtPointer) BWDrawHotSpot,
         NULL, (XtPointer) NULL},
    {ZoomInRequest, sizeof(BWStatus),
         TwoPointsEngage, (XtPointer) BWDrawRectangle,
         TwoPointsTerminate, (XtPointer) BWZoomIn,
         NULL, (XtPointer) NULL},
    };
    
    static void ClassInitialize(void);
    static void Initialize(Widget wrequest, Widget wnew, 
    		       ArgList argv, Cardinal *argc);
    static void Redisplay(Widget w, XEvent *event, Region region);
    static void Resize(Widget w);
    static void Destroy(Widget w);
    static void Refresh(BitmapWidget BW, Position x, Position y, 
    		    Dimension width, Dimension height);
    static Boolean SetValues(Widget old, Widget request, Widget new,
    			 ArgList args, Cardinal *num_args);
     
    BitmapClassRec bitmapClassRec = {
    {   /* core fields */
        /* superclass		*/	(WidgetClass) &simpleClassRec,
        /* class_name		*/	"Bitmap",
        /* widget_size		*/	sizeof(BitmapRec),
        /* class_initialize		*/	ClassInitialize,
        /* class_part_initialize	*/	NULL,
        /* class_inited		*/	FALSE,
        /* initialize		*/	Initialize,
        /* initialize_hook		*/	NULL,
        /* realize			*/	XtInheritRealize,
        /* actions			*/	actions,
        /* num_actions		*/	XtNumber(actions),
        /* resources		*/	resources,
        /* num_resources		*/	XtNumber(resources),
        /* xrm_class		*/	NULLQUARK,
        /* compress_motion		*/	TRUE,
        /* compress_exposure	*/	FALSE,
        /* compress_enterleave	*/	TRUE,
        /* visible_interest		*/	TRUE,
        /* destroy			*/	Destroy,
        /* resize			*/	Resize,
        /* expose			*/	Redisplay,
        /* set_values		*/	SetValues,
        /* set_values_hook		*/	NULL,
        /* set_values_almost	*/	XtInheritSetValuesAlmost,
        /* get_values_hook		*/	NULL,
        /* accept_focus		*/	NULL,
        /* version			*/	XtVersion,
        /* callback_private		*/	NULL,
        /* tm_table			*/	NULL , /* set in code */
        /* query_geometry		*/	XtInheritQueryGeometry,
        /* display_accelerator	*/	XtInheritDisplayAccelerator,
        /* extension		*/	NULL,
      },
      { 
        /* empty			*/	XtInheritChangeSensitive,
      },
      {
        /* targets                  */      targets,
        /* num_trets                */      XtNumber(targets),
        /* requests                 */      requests,
        /* num_requests             */      XtNumber(requests),
      }
    };
     
    WidgetClass bitmapWidgetClass = (WidgetClass) &bitmapClassRec;
        
    /* ARGSUSED */
    
    void 
    BWDebug(Widget w, XEvent *event, String *params, Cardinal *num_params)
    {
        DEBUG ^= True;
    }
    
    Pixmap 
    BWGetPixmap(Widget w) 
    {
        BitmapWidget BW = (BitmapWidget) w;
     
        return GetPixmap(BW, BW->bitmap.zoom.image);
    }
    
    Pixmap 
    BWGetUnzoomedPixmap(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        GC gc;
        Pixmap pix;
        
        if (BW->bitmap.zooming) {    
    	pix = XCreatePixmap(XtDisplay(w), XtWindow(w), 
    			    BW->bitmap.zoom.image->width, 
    			    BW->bitmap.zoom.image->height, 1);
    	if (!(gc = XCreateGC(XtDisplay(w), pix, 
    			     (unsigned long) 0, (XGCValues *) 0)))
    	    return (Pixmap) None;
    	
    	XPutImage(XtDisplay(w), pix, gc, 
    		  BW->bitmap.zoom.image, 
    		  0, 0, 0, 0, 
    		  BW->bitmap.zoom.image->width, 
    		  BW->bitmap.zoom.image->height);
    	XPutImage(XtDisplay(w), pix, gc, 
    		  BW->bitmap.image, 
    		  0, 0, 
    		  BW->bitmap.zoom.at_x,
    		  BW->bitmap.zoom.at_y,
    		  BW->bitmap.image->width, 
    		  BW->bitmap.image->height);
        }
        else {
    	pix = XCreatePixmap(XtDisplay(w), XtWindow(w), 
    			    BW->bitmap.image->width, 
    			    BW->bitmap.image->height, 1);
    	if (! (gc = XCreateGC(XtDisplay(w), pix, 
    			      (unsigned long) 0, (XGCValues *) 0)))
    	    return (Pixmap) None;
    	
    	XPutImage(XtDisplay(w), pix, gc, 
    		  BW->bitmap.image, 
    		  0, 0, 0, 0,
    		  BW->bitmap.image->width, 
    		  BW->bitmap.image->height);
        }
        XFreeGC(XtDisplay(w), gc);
        return(pix);
    }
    
    
    XImage *
    GetImage(BitmapWidget BW, Pixmap pixmap)
    {
        Window root;
        int x, y;
        unsigned int width, height, border_width, depth;
        XImage *source, *image;
    
        XGetGeometry(XtDisplay(BW), pixmap, &root, &x, &y,
    		 &width, &height, &border_width, &depth);
    
        source = XGetImage(XtDisplay(BW), pixmap, x, y, width, height,
    		     1, XYPixmap);
    
        image = ConvertToBitmapImage(BW, source);
    
        return image;
    }
    
    XImage *
    CreateBitmapImage(BitmapWidget BW, char *data, 
    		  Dimension width, Dimension height)
    {
        XImage *image = XCreateImage(XtDisplay(BW),
    				 DefaultVisual(XtDisplay(BW), 
    					       DefaultScreen(XtDisplay(BW))),
    				 1, XYBitmap, 0, 
    				 data, width, height,
    				 8, ((int)width + 7) / 8);
    
        image->height = height;
        image->width = width;
        image->depth = 1;
        image->xoffset = 0;
        image->format = XYBitmap;
        image->data = (char *)data;
        image->byte_order = LSBFirst;
        image->bitmap_unit = 8;
        image->bitmap_bit_order = LSBFirst;
        image->bitmap_pad = 8;
        image->bytes_per_line = ((int)width + 7) / 8;
    
        return image;
    }
    
    void 
    DestroyBitmapImage(XImage **image)
    {
        /*XDestroyImage(*image);*/
        if (image) {
    	if (*image) {
    	    if ((*image)->data)
    		XtFree((*image)->data);
    	    XtFree((char *)*image);
    	}
    	*image = NULL;
        }
    }
    
    #if 0
    XImage *
    BWGetImage(Widget w, XEvent *event, String *params, Cardinal *num_params)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return BW->bitmap.image;
    }
    #endif
    
    void 
    BWChangeNotify(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (BW->bitmap.notify)
    	(*BW->bitmap.notify)(w, NULL, NULL, NULL);
    }
    
    void 
    BWNotify(Widget w, XtActionProc proc)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BW->bitmap.notify = proc;
    }
    
    void 
    BWSetChanged(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    	
        BW->bitmap.changed = True;
    }
    
    Boolean 
    BWQueryChanged(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    	
        return BW->bitmap.changed;
    }
    
    void 
    BWClearChanged(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        BW->bitmap.changed = False;
    }
    
    Boolean 
    BWQueryStored(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        return (BW->bitmap.storage != NULL);
    }
    
    Boolean 
    BWQueryStippled(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return BW->bitmap.stippled;
    }
    
    static void 
    RedrawStippled(BitmapWidget BW)
    {
      XExposeEvent event;
      
      event.type = Expose;
      event.display = XtDisplay((Widget)BW);
      event.window = XtWindow((Widget)BW);
      event.x = 0;
      event.y = 0;
      event.width = BW->core.width;
      event.height = BW->core.height;
      event.count = 0;
      
      BWRedrawMark((Widget)BW);
      
      BW->bitmap.stipple_change_expose_event = True; 
      
      XtDispatchEvent((XEvent *)&event);
      
      BW->bitmap.stipple_change_expose_event = False;
    }
    
    void 
    BWSwitchStippled(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        RedrawStippled(BW);
    
        BW->bitmap.stippled ^= True;
        XSetFillStyle(XtDisplay(BW), BW->bitmap.highlighting_gc,
    		  (BW->bitmap.stippled ? FillStippled : FillSolid));
    
        RedrawStippled(BW);    
    }
    
    void 
    BWSelect(Widget w, Position from_x, Position from_y, 
    	 Position to_x, Position to_y, Time btime)
    {
        BWMark(w, from_x, from_y, to_x, to_y);
    
        BWGrabSelection(w, btime);
    }
    
    Boolean 
    BWQueryAxes(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return BW->bitmap.axes;
    }
    
    void 
    BWSwitchAxes(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BW->bitmap.axes ^= True;
        BWHighlightAxes(w);
    }
    
    void 
    BWAxes(Widget w, Boolean _switch)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        if (BW->bitmap.axes != _switch)
    	BWSwitchAxes(w);
    }
    
    void 
    BWRedrawAxes(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        if (BW->bitmap.axes)
    	BWHighlightAxes(w);
    }
    
    #if 0
    void 
    BWPutImage(BitmapWidget w, Display *display, Drawable drawable, GC gc, 
    	   Position x, Position y)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
      XPutImage(display, drawable, gc, BW->bitmap.image,
    	    0, 0, x, y, BW->bitmap.image->width, BW->bitmap.image->height);
    }
    #endif
    
    static String 
    StripFilename(String filename)
    {
        char *begin = strrchr(filename, '/');
        char *end, *result;
        int length;
        
        if (filename) {
    	begin = (begin ? begin + 1 : filename);
    	end = strchr(begin, '.'); /* change to strrchr to allow longer names */
    	length = (end ? (end - begin) : strlen (begin));
    	result = (char *) XtMalloc (length + 1);
    	strncpy (result, begin, length);
    	result [length] = '\0';
    	return (result);
        }
        else
    	return (NULL);
    }
    
    static int 
    XmuWriteBitmapDataToFile(String filename, String basename, 
    			 int width, int height, char *datap, 
    			 int x_hot, int y_hot)
    {
        FILE *file;
        int i, data_length;
        
        data_length = Length(width, height);
        
        if(!filename || !strcmp(filename, "") || !strcmp(filename, "-")) {   
    	file = stdout;
    	filename = "dummy";
    	}
        else
        	file = fopen(filename, "w+");
        
        if (!basename || !strcmp(basename, "") || !strcmp(basename, "-"))
    	basename = StripFilename(filename);
        
        if (file) {
    	fprintf(file, "#define %s_width %d\n", basename, width);
    	fprintf(file, "#define %s_height %d\n", basename, height);
    	if (QuerySet(x_hot, y_hot)) {
    	    fprintf(file, "#define %s_x_hot %d\n", basename, x_hot);
    	    fprintf(file, "#define %s_y_hot %d\n", basename, y_hot);
    	}
    	fprintf(file, "static unsigned char %s_bits[] = {\n   0x%02x",
    		basename, (unsigned char) datap[0]);
    	for(i = 1; i < data_length; i++) {
    	    fprintf(file, ",");
    	    fprintf(file, (i % 12) ? " " : "\n   ");
    	    fprintf(file, "0x%02x", (unsigned char) datap[i]);
    	}
    	fprintf(file, "};\n");
    	
    	if (file != stdout)
    	    fclose(file);
    
    	return BitmapSuccess;
        }
        
        return 1;
    }
    
    /*
     *
     */
    
    				/* ARGSUSED */
    static void 
    CvtStringToButtonFunction(XrmValuePtr args, /* not used */
    			  Cardinal *num_args, /* not used */
    			  XrmValuePtr from_val, 
    			  XrmValuePtr to_val)
    {
      static int button_function;
      char lower_name[80];
     
      XmuCopyISOLatin1Lowered (lower_name, (char*)from_val->addr);
      
      if (!strcmp(lower_name, XtClear)) {
        button_function = Clear;
        to_val->addr = (XPointer) &button_function;
        to_val->size = sizeof(button_function);
        return;
      }
      
      if (!strcmp(lower_name, XtSet)) {
        button_function = Set;
        to_val->addr = (XPointer) &button_function;
        to_val->size = sizeof(button_function);
        return;
      }
    
      if (!strcmp(lower_name, XtInvert)) {
        button_function = Invert;
        to_val->addr = (XPointer) &button_function;
        to_val->size = sizeof(button_function);
        return;
      }
      
      XtStringConversionWarning(from_val->addr, XtRButtonFunction);
      button_function = Clear;
      to_val->addr = (XPointer) &button_function;
      to_val->size = sizeof(button_function);
      
    }
    
    static void 
    ClassInitialize(void)
    {
      char *tm_table = XtMalloc(strlen(translations1) + strlen(translations2) + 1);
      strcpy(tm_table, translations1);
      strcat(tm_table, translations2);
      bitmapClassRec.core_class.tm_table = tm_table;
    
      XawInitializeWidgetSet();
      XtAddConverter(XtRString, XtRButtonFunction, CvtStringToButtonFunction,
    		 NULL, 0);
      DEBUG = False;
    }
    
    static void 
    SetSizeFromSizeResource(BitmapWidget bw)
    {
      if (BWParseSize(bw->bitmap.size, 
    		  &bw->bitmap.width,
    		  &bw->bitmap.height)
          ==
          False) {
        bw->bitmap.width = FallbackBitmapWidth;
        bw->bitmap.height = FallbackBitmapHeight;
        XtWarning("Cannot parse the size resource.  BitmapWidget");
      }
    }
    
    
    /* ARGSUSED */
    static void 
    Initialize(Widget wrequest, Widget wnew, ArgList argv, Cardinal *argc)
    {
        BitmapWidget new = (BitmapWidget) wnew;
    
        XGCValues  values;
        XtGCMask   mask;
        char *image_data, *buffer_data;
    
        new->bitmap.stipple_change_expose_event = False;
        new->bitmap.notify = NULL;
        new->bitmap.cardinal = 0;
        new->bitmap.current = 0;
        new->bitmap.fold = False;
        new->bitmap.changed = False;
        new->bitmap.zooming = False;
        new->bitmap.selection.own = False;
        new->bitmap.selection.limbo = False;
    
        new->bitmap.request_stack = (BWRequestStack *)
    	XtMalloc(sizeof(BWRequestStack));
    
        new->bitmap.request_stack[0].request = NULL;
        new->bitmap.request_stack[0].call_data = NULL;
        new->bitmap.request_stack[0].trap = False;
    
        SetSizeFromSizeResource(new);
    
        new->core.width = new->bitmap.width * new->bitmap.squareW + 
    	2 * new->bitmap.margin;
        new->core.height = new->bitmap.height * new->bitmap.squareH + 
    	2 * new->bitmap.margin;
      
        new->bitmap.hot.x = new->bitmap.hot.y = NotSet;
        new->bitmap.buffer_hot.x = new->bitmap.buffer_hot.y = NotSet;
      
        new->bitmap.mark.from_x = new->bitmap.mark.from_y = NotSet;
        new->bitmap.mark.to_x = new->bitmap.mark.to_y = NotSet;
        new->bitmap.buffer_mark.from_x = new->bitmap.buffer_mark.from_y = NotSet;
        new->bitmap.buffer_mark.to_x = new->bitmap.buffer_mark.to_y = NotSet;
    
        values.foreground = new->bitmap.foreground_pixel;
        values.background = new->core.background_pixel;
        values.foreground ^= values.background;
        values.function = GXxor;
        mask = GCForeground | GCBackground | GCFunction;
        new->bitmap.drawing_gc = XCreateGC(XtDisplay(new), 
    				       RootWindow(XtDisplay(new), 
    				       DefaultScreen(XtDisplay(new))),
    				       mask, &values);
    
        values.foreground = new->bitmap.highlight_pixel;
        values.background = new->core.background_pixel;
        values.foreground ^= values.background;
        values.function = GXxor;
        mask = GCForeground | GCBackground | GCFunction;
        if (new->bitmap.stipple != XtUnspecifiedPixmap)
        {
    	values.stipple = new->bitmap.stipple;
    	mask |= GCStipple | GCFillStyle;
        }
        values.fill_style = (new->bitmap.stippled ? FillStippled : FillSolid);
    
        new->bitmap.highlighting_gc = XCreateGC(XtDisplay(new), 
    					    RootWindow(XtDisplay(new), 
    					       DefaultScreen(XtDisplay(new))), 
    					    mask, &values);
    
    
        values.foreground = new->bitmap.frame_pixel;
        values.background = new->core.background_pixel;
        values.foreground ^= values.background;
        mask = GCForeground | GCBackground | GCFunction;
        if (new->bitmap.dashes != XtUnspecifiedPixmap)
        {
    	values.stipple = new->bitmap.dashes;
    	mask |= GCStipple | GCFillStyle;
        }
        values.fill_style = (new->bitmap.dashed ? FillStippled : FillSolid);
    
        new->bitmap.frame_gc = XCreateGC(XtDisplay(new), 
    				     RootWindow(XtDisplay(new), 
    						DefaultScreen(XtDisplay(new))),
    				     mask, &values);
    
        values.foreground = new->bitmap.highlight_pixel;
        values.background = new->core.background_pixel;
        values.foreground ^= values.background;
        mask = GCForeground | GCBackground | GCFunction;
        new->bitmap.axes_gc = XCreateGC(XtDisplay(new), 
    				     RootWindow(XtDisplay(new), 
    						DefaultScreen(XtDisplay(new))),
    				     mask, &values);
    
        image_data = CreateCleanData(Length(new->bitmap.width, 
    					new->bitmap.height));
        buffer_data = CreateCleanData(Length(new->bitmap.width, 
    					 new->bitmap.height));
    
        new->bitmap.storage = NULL;
        
        new->bitmap.image = CreateBitmapImage(new, 
    					  image_data,
    					  new->bitmap.width,
    					  new->bitmap.height);
        new->bitmap.buffer = CreateBitmapImage(new, 
    					   buffer_data,
    					   new->bitmap.width,
    					   new->bitmap.height);
    
        /* Read file */
        {
    	int status;
    	XImage *image, *buffer;
    	unsigned char *image_data;
    	char *buffer_data;
    	unsigned int width, height;
    	int x_hot, y_hot;
    	
    	status = XmuReadBitmapDataFromFile(new->bitmap.filename, 
    					   &width, &height, &image_data,
    					   &x_hot, &y_hot);
    	if (status == BitmapSuccess) {
    	    
    	    buffer_data = CreateCleanData(Length(width, height));
    	    
    	    image = CreateBitmapImage(new, (char *)image_data, width, height);
    	    buffer = CreateBitmapImage(new, buffer_data, width, height);
    	
    	    TransferImageData(new->bitmap.image, buffer);
    	
    	    DestroyBitmapImage(&new->bitmap.image);
    	    DestroyBitmapImage(&new->bitmap.buffer);
    	
    	    new->bitmap.image = image;
    	    new->bitmap.buffer = buffer;
    	    new->bitmap.width = width;
    	    new->bitmap.height = height;
    	    
    	    new->bitmap.hot.x = x_hot;
    	    new->bitmap.hot.y = y_hot;
    	    
    	    new->bitmap.changed = False;
    	    new->bitmap.zooming = False;
    	}
    
    	new->bitmap.filename = XtNewString(new->bitmap.filename);
    	
    	if (!strcmp(new->bitmap.basename, "")) {
    	    new->bitmap.basename = StripFilename(new->bitmap.filename);
    	}
    	else
    	  new->bitmap.basename = XtNewString(new->bitmap.basename);
        }
    
        Resize((Widget)new);
    }
    
    
    /* returns False if the format is wrong */
    Boolean 
    BWParseSize(String size, Dimension *width, Dimension *height)
    {
      int x, y;
      unsigned int w, h;
      int status;
    
      status = XParseGeometry(size, &x, &y, &w, &h);
    
      if (status & (WidthValue | HeightValue)) {
        *width = (Dimension) w;
        *height = (Dimension) h;
        return True;
      }
      else return False;
    
    }
    
    
    Boolean 
    BWQueryMarked(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y);
    }
    
    static void 
    FixMark(BitmapWidget BW)
    {
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
    	BW->bitmap.mark.from_x = min(BW->bitmap.mark.from_x, 
    				     BW->bitmap.image->width);
    	BW->bitmap.mark.from_y = min(BW->bitmap.mark.from_y, 
    				     BW->bitmap.image->height);
    	BW->bitmap.mark.to_x = min(BW->bitmap.mark.to_x, 
    				   BW->bitmap.image->width);
    	BW->bitmap.mark.to_y = min(BW->bitmap.mark.to_y, 
    				   BW->bitmap.image->height);
    	
    	if((BW->bitmap.mark.from_x == BW->bitmap.mark.from_y) &&
    	   (BW->bitmap.mark.to_x   == BW->bitmap.mark.to_y))
    	    BW->bitmap.mark.from_x = 
    		BW->bitmap.mark.from_y =
    		    BW->bitmap.mark.to_x = 
    			BW->bitmap.mark.to_y = NotSet;
        }
    }
    
    /* ARGSUSED */
    int 
    BWStoreFile(Widget w, String filename, String *basename)
    {
        BitmapWidget BW = (BitmapWidget) w;
        int status;
        unsigned char *storage_data;
        unsigned int width, height;
        int x_hot, y_hot;
        
        status = XmuReadBitmapDataFromFile(filename, &width, &height,
    				       &storage_data, &x_hot, &y_hot);
        if (status == BitmapSuccess) {
    
    	DestroyBitmapImage(&BW->bitmap.storage);
    	
    	BW->bitmap.storage = CreateBitmapImage(BW, (char *)storage_data, width, height);
    
    	return BitmapSuccess;
        }
        else
    	XtWarning(" read file failed.  BitmapWidget");
        
        return status;
    }
    
    String 
    BWUnparseStatus(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        XmuSnprintf(BW->bitmap.status, sizeof(BW->bitmap.status),
    	    "Filename: %s  Basename: %s  Size: %dx%d",
    	    (strcmp(BW->bitmap.filename, "") ? BW->bitmap.filename : "<none>"),
    	    (strcmp(BW->bitmap.basename, "") ? BW->bitmap.basename : "<none>"),
    	    BW->bitmap.width, BW->bitmap.height);
    
        return BW->bitmap.status;
    }
    
    void 
    BWChangeFilename(Widget w, String str)
    {
      BitmapWidget BW = (BitmapWidget) w;
      
      if (str) {
        XtFree(BW->bitmap.filename);
        BW->bitmap.filename = XtNewString( str);
      }
    }
    
    void 
    BWChangeBasename(Widget w, String str)
    {
      BitmapWidget BW = (BitmapWidget) w;
      
      if (str) {
        XtFree(BW->bitmap.basename);
        BW->bitmap.basename = XtNewString(str);
      }
    }
    
    
    int 
    BWReadFile(Widget w, String filename, String basename) /* ARGSUSED */
    {
        BitmapWidget BW = (BitmapWidget) w;
        int status;
        XImage *image, *buffer;
        unsigned char *image_data;
        char *buffer_data;
        unsigned int width, height;
        int x_hot, y_hot;
        
        if (!filename)
    	filename = BW->bitmap.filename;
    
        status = XmuReadBitmapDataFromFile(filename, &width, &height, &image_data,
    				       &x_hot, &y_hot);
        if (status == BitmapSuccess) {
    	
    	buffer_data = CreateCleanData(Length(width, height));
    	
    	image = CreateBitmapImage(BW, (char *)image_data, width, height);
    	buffer = CreateBitmapImage(BW, buffer_data, width, height);
    	
    	TransferImageData(BW->bitmap.image, buffer);
    	
    	DestroyBitmapImage(&BW->bitmap.image);
    	DestroyBitmapImage(&BW->bitmap.buffer);
    	
    	BW->bitmap.image = image;
    	BW->bitmap.buffer = buffer;
    	BW->bitmap.width = width;
    	BW->bitmap.height = height;
    	
    	BW->bitmap.hot.x = x_hot;
    	BW->bitmap.hot.y = y_hot;
    	
    	BW->bitmap.changed = False;
    	BW->bitmap.zooming = False;
    	
    	XtFree(BW->bitmap.filename);
    	BW->bitmap.filename = XtNewString(filename);
    	XtFree(BW->bitmap.basename);
    	BW->bitmap.basename= XtNewString(StripFilename(filename));
    
    	BWUnmark(w);
    	
    	Resize((Widget)BW);
    
    	if (BW->core.visible) {
    	    XClearArea(XtDisplay(BW), XtWindow(BW),
    		       0, 0, 
    		       BW->core.width, BW->core.height,
    		       True);
    	}
    	
    	return BitmapSuccess;
        }
        else
    	XtWarning(" read file failed.  BitmapWidget");
        
        return status;
    }
    
    #if 0
    void 
    BWSetImage(Widget w, XImage *image)
    {
        BitmapWidget BW = (BitmapWidget) w;
        XImage *buffer;
        char *buffer_data;
        
        buffer_data = CreateCleanData(Length(image->width, image->height));
        buffer = CreateBitmapImage(BW, buffer_data, 
    			       (Dimension) image->width, 
    			       (Dimension) image->height);
        
        TransferImageData(BW->bitmap.image, buffer);
        
        DestroyBitmapImage(&BW->bitmap.image);
        DestroyBitmapImage(&BW->bitmap.buffer);
        
        BW->bitmap.image = image;
        BW->bitmap.buffer = buffer;
        BW->bitmap.width = image->width;
        BW->bitmap.height = image->height;
        
        Resize((Widget)BW);
        
        if (BW->core.visible) {
    	XClearArea(XtDisplay(BW), XtWindow(BW),
    		   0, 0, 
    		   BW->core.width, BW->core.height,
    		   True);    
        }
    }
    #endif
    
    int 
    BWWriteFile(Widget w, String filename, String basename)
    {
        BitmapWidget BW = (BitmapWidget) w;
        char *data;
        XImage *image;
        XPoint hot;
        int status;
        
        if (BW->bitmap.zooming) {
            data = XtMalloc(Length(BW->bitmap.zoom.image->width, 
    			       BW->bitmap.zoom.image->height));
    	memmove( data, BW->bitmap.zoom.image->data, 
    	      Length(BW->bitmap.zoom.image->width, 
    		     BW->bitmap.zoom.image->height));
    	image = CreateBitmapImage(BW, data,
    				  (Dimension) BW->bitmap.zoom.image->width,
    				  (Dimension) BW->bitmap.zoom.image->height);
    	CopyImageData(BW->bitmap.image, image, 
    		      0, 0, 
    		      BW->bitmap.image->width - 1,
    		      BW->bitmap.image->height - 1,
    		      BW->bitmap.zoom.at_x, BW->bitmap.zoom.at_y);
    	
    	if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
    	    hot.x = BW->bitmap.hot.x + BW->bitmap.zoom.at_x;
    	    hot.y = BW->bitmap.hot.y + BW->bitmap.zoom.at_y;
    	}
    	else
    	    hot = BW->bitmap.zoom.hot;
        }
        else {
    	image = BW->bitmap.image;
    	hot = BW->bitmap.hot;
        }
        
        if (!filename) filename = BW->bitmap.filename;
        else {
    	XtFree(BW->bitmap.filename);
    	BW->bitmap.filename = XtNewString(filename);
    	XtFree(BW->bitmap.basename);
    	BW->bitmap.basename= XtNewString(StripFilename(filename));
        }
        if (!basename) basename = BW->bitmap.basename;
        else {
    	XtFree(BW->bitmap.basename);
    	BW->bitmap.basename = XtNewString(basename);
        }
    
        if (DEBUG)
    	fprintf(stderr, "Saving filename: %s %s\n", filename, basename);
    
        status = XmuWriteBitmapDataToFile(filename, basename,
    				      image->width, image->height, image->data,
    				      hot.x, hot.y);
        if (BW->bitmap.zooming)
    	DestroyBitmapImage(&image);
        
        if (status == BitmapSuccess)
    	BW->bitmap.changed = False;
        
        return status;
    }
    
    String 
    BWGetFilename(Widget w, String *str)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        *str = XtNewString(BW->bitmap.filename);
    
        return *str;
    }
    
    String 
    BWGetFilepath(Widget w, String *str)
    {
        BitmapWidget BW = (BitmapWidget) w;
        String end;
    
        *str = XtNewString(BW->bitmap.filename);
        end = strrchr(*str, '/');
    
        if (end)
    	*(end + 1) = '\0';
        else 
    	**str = '\0';
    
        return *str;
    }
    
    
    String 
    BWGetBasename(Widget w, String *str)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        *str = XtNewString(BW->bitmap.basename);
    
        return *str;
    }
    
    static void 
    FixHotSpot(BitmapWidget BW)
    {
        if (!QueryInBitmap(BW, BW->bitmap.hot.x, BW->bitmap.hot.y))
    	BW->bitmap.hot.x = BW->bitmap.hot.y = NotSet;
    }
    
    static void 
    ZoomOut(BitmapWidget BW)
    {
        CopyImageData(BW->bitmap.image, BW->bitmap.zoom.image, 
    		  0, 0, 
    		  BW->bitmap.image->width - 1,
    		  BW->bitmap.image->height - 1,
    		  BW->bitmap.zoom.at_x, BW->bitmap.zoom.at_y);
        
        DestroyBitmapImage(&BW->bitmap.image);
        DestroyBitmapImage(&BW->bitmap.buffer);
        
        BW->bitmap.image = BW->bitmap.zoom.image;
        BW->bitmap.buffer = BW->bitmap.zoom.buffer;
        BW->bitmap.width = BW->bitmap.image->width;
        BW->bitmap.height = BW->bitmap.image->height;
        BW->bitmap.fold = BW->bitmap.zoom.fold;
        BW->bitmap.changed |= BW->bitmap.zoom.changed;
        BW->bitmap.grid = BW->bitmap.zoom.grid;
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
    	BW->bitmap.hot.x += BW->bitmap.zoom.at_x;
    	BW->bitmap.hot.y += BW->bitmap.zoom.at_y;
        }
        else
    	BW->bitmap.hot = BW->bitmap.zoom.hot;
        
        BW->bitmap.mark.from_x = NotSet;
        BW->bitmap.mark.from_y = NotSet;
        BW->bitmap.mark.to_x = NotSet;
        BW->bitmap.mark.to_y = NotSet;
        BW->bitmap.zooming = False;
    }    
    
    void 
    BWZoomOut(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        if (BW->bitmap.zooming) {
    	ZoomOut(BW);
    	
    	Resize((Widget)BW);
    	if (BW->core.visible)
    	    XClearArea(XtDisplay(BW), XtWindow(BW),
    		       0, 0, 
    		       BW->core.width, BW->core.height,
    		       True);
        }
    }
    
    
    void 
    BWZoomMarked(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BWZoomIn(w, 
    	     BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
    	     BW->bitmap.mark.to_x,   BW->bitmap.mark.to_y);
    }
    
    void 
    BWZoomIn(Widget w, 
    	 Position from_x, Position from_y, 
    	 Position to_x, Position to_y)
    {
        BitmapWidget BW = (BitmapWidget) w;
        XImage *image, *buffer;    
        Dimension width, height;
        char *image_data, *buffer_data;
      
        if (BW->bitmap.zooming)
    	ZoomOut(BW);
        
        QuerySwap(from_x, to_x);
        QuerySwap(from_y, to_y);
        from_x = max(0, from_x);
        from_y = max(0, from_y);
        to_x = min(BW->bitmap.width - 1, to_x);
        to_y = min(BW->bitmap.height - 1, to_y);
        
        width = to_x - from_x + 1;
        height = to_y - from_y + 1;
    
        image_data = CreateCleanData(Length(width, height));
        buffer_data = CreateCleanData(Length(width, height));
    
        image = CreateBitmapImage(BW, image_data, width, height);
        buffer = CreateBitmapImage(BW, buffer_data, width, height);
    
        CopyImageData(BW->bitmap.image, image, from_x, from_y, to_x, to_y, 0, 0);
        CopyImageData(BW->bitmap.buffer, buffer, from_x, from_y, to_x, to_y, 0, 0);
        
        BW->bitmap.zoom.image = BW->bitmap.image;
        BW->bitmap.zoom.buffer = BW->bitmap.buffer;
        BW->bitmap.zoom.at_x = from_x;
        BW->bitmap.zoom.at_y = from_y;
        BW->bitmap.zoom.fold = BW->bitmap.fold;
        BW->bitmap.zoom.changed = BW->bitmap.changed;
        BW->bitmap.zoom.hot = BW->bitmap.hot;
        BW->bitmap.zoom.grid = BW->bitmap.grid;
    
        BW->bitmap.image = image;
        BW->bitmap.buffer = buffer;
        BW->bitmap.width = width;
        BW->bitmap.height = height;
        BW->bitmap.changed = False;
        BW->bitmap.hot.x -= from_x;
        BW->bitmap.hot.y -= from_y;
        BW->bitmap.mark.from_x = NotSet;
        BW->bitmap.mark.from_y = NotSet;
        BW->bitmap.mark.to_x = NotSet;
        BW->bitmap.mark.to_y = NotSet;
        BW->bitmap.zooming = True;
        BW->bitmap.grid = True; /* potencially true, could use a resource here */
    
        FixHotSpot(BW);
    
        Resize((Widget)BW);
        if (BW->core.visible)
    	XClearArea(XtDisplay(BW), XtWindow(BW),
    		   0, 0, 
    		   BW->core.width, BW->core.height,
    		   True);
    }
    
    
    void 
    BWRescale(Widget w, Dimension width, Dimension height)
    {
        BitmapWidget BW = (BitmapWidget) w;
        XImage *image, *buffer;
        char *buffer_data;
    
        if (BW->bitmap.zooming)
    	ZoomOut(BW);
            
        image = ScaleBitmapImage(BW, BW->bitmap.image, 
    		       (double) width / (double) BW->bitmap.image->width,
    		       (double) height / (double) BW->bitmap.image->height);
    
        buffer_data = CreateCleanData(Length(image->width, image->height));
        buffer = CreateBitmapImage(BW, buffer_data, 
    			       (Dimension) image->width, 
    			       (Dimension) image->height);
        
        TransferImageData(BW->bitmap.buffer, buffer);
    
        DestroyBitmapImage(&BW->bitmap.image);
        DestroyBitmapImage(&BW->bitmap.buffer);
        
        BW->bitmap.image = image;
        BW->bitmap.buffer = buffer;
        BW->bitmap.width = image->width;
        BW->bitmap.height = image->height;
        
        FixHotSpot(BW);
        FixMark(BW);
    
        Resize((Widget)BW);
        if (BW->core.visible)
    	XClearArea(XtDisplay(BW), XtWindow(BW),
    		   0, 0, 
    		   BW->core.width, BW->core.height,
    		   True);
    }
    
    Boolean 
    BWQueryZooming(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return BW->bitmap.zooming;
    }
    
    
    static void 
    ResizeGrid(BitmapWidget BW, Dimension width, Dimension height)
    {
      XImage *image, *buffer;
      char *image_data, *buffer_data;
      
      if (BW->bitmap.zooming)
        ZoomOut(BW);
      
      image_data = CreateCleanData(Length(width, height));
      buffer_data = CreateCleanData(Length(width, height));
      
      image = CreateBitmapImage(BW, image_data, width, height);
      buffer = CreateBitmapImage(BW, buffer_data, width, height);
      
      TransferImageData(BW->bitmap.image, image);
      TransferImageData(BW->bitmap.buffer, buffer);
      
      DestroyBitmapImage(&BW->bitmap.image);
      DestroyBitmapImage(&BW->bitmap.buffer);
      
      BW->bitmap.image = image;
      BW->bitmap.buffer = buffer;
      BW->bitmap.width = width;
      BW->bitmap.height = height;
      
      FixHotSpot(BW);
      FixMark(BW);
    }
    
    void 
    BWResize(Widget w, Dimension width, Dimension height)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        ResizeGrid(BW, width, height);
    
        Resize((Widget)BW);
        if (BW->core.visible)
    	XClearArea(XtDisplay(BW), XtWindow(BW),
    		   0, 0, 
    		   BW->core.width, BW->core.height,
    		   True);
    }
    
    static void 
    Destroy(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        XFreeGC(XtDisplay(w), BW->bitmap.drawing_gc);
        XFreeGC(XtDisplay(w), BW->bitmap.highlighting_gc);
        XFreeGC(XtDisplay(w), BW->bitmap.frame_gc);
        XFreeGC(XtDisplay(w), BW->bitmap.axes_gc);
        BWRemoveAllRequests(w);
    
        XtFree(BW->bitmap.filename);
        XtFree(BW->bitmap.basename);
    }
    
    
    static void 
    Resize(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        Dimension squareW, squareH;
    
        squareW = max(1, ((int)BW->core.width - 2 * (int)BW->bitmap.margin) / 
    		  (int)BW->bitmap.width);
        squareH = max(1, ((int)BW->core.height - 2 * (int)BW->bitmap.margin) / 
    		  (int)BW->bitmap.height);
    
        if (BW->bitmap.proportional)
    	BW->bitmap.squareW = BW->bitmap.squareH = min(squareW, squareH);
        else {
    	BW->bitmap.squareW = squareW;
    	BW->bitmap.squareH = squareH;
        }
        
        BW->bitmap.horizOffset = max((Position)BW->bitmap.margin, 
    				 (Position)(BW->core.width - 
    					    BW->bitmap.width * 
    					    BW->bitmap.squareW) / 2);
        BW->bitmap.vertOffset = max((Position)BW->bitmap.margin, 
    				(Position)(BW->core.height - 
    					   BW->bitmap.height * 
    					   BW->bitmap.squareH) / 2);
    
        BW->bitmap.grid &= ((BW->bitmap.squareW > BW->bitmap.grid_tolerance) && 
    			(BW->bitmap.squareH > BW->bitmap.grid_tolerance));
    }
    
    /* ARGSUSED */
    static void 
    Redisplay(Widget w, XEvent *event, Region region)
    {
         BitmapWidget BW = (BitmapWidget) w;
    
      if(event->type == Expose
         &&
         BW->core.visible)
        if (BW->bitmap.stipple_change_expose_event == False)
          Refresh(BW, 
    	      event->xexpose.x, event->xexpose.y,
    	      event->xexpose.width, event->xexpose.height);
    }
    
    void 
    BWClip(Widget w, Position x, Position y, Dimension width, Dimension height)
    {
        Position      from_x, from_y,
                      to_x, to_y;
        BitmapWidget BW = (BitmapWidget) w;
        XRectangle rectangle;
      
        from_x = InBitmapX(BW, x);
        from_y = InBitmapY(BW, y);
        to_x = InBitmapX(BW, x + width);
        to_y = InBitmapY(BW, y + height);
        QuerySwap(from_x, to_x);
        QuerySwap(from_y, to_y);
        from_x = max(0, from_x);
        from_y = max(0, from_y);
        to_x = min(BW->bitmap.width - 1, to_x);
        to_y = min(BW->bitmap.height - 1, to_y);
    
        rectangle.x = InWindowX(BW, from_x);
        rectangle.y = InWindowY(BW, from_y);
        rectangle.width = InWindowX(BW, to_x  + 1) - InWindowX(BW, from_x);
        rectangle.height = InWindowY(BW, to_y + 1) - InWindowY(BW, from_y);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.highlighting_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.drawing_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.frame_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.axes_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
    }
    
    void 
    BWUnclip(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        XRectangle rectangle;
      
        rectangle.x = InWindowX(BW, 0);
        rectangle.y = InWindowY(BW, 0);
        rectangle.width = InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0);
        rectangle.height = InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.highlighting_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.drawing_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.frame_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.axes_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
    }
    
    static void 
    Refresh(BitmapWidget BW, Position x, Position y, 
    	Dimension width, Dimension height)
    {
        XRectangle rectangle;
    
        rectangle.x = min(x, InWindowX(BW, InBitmapX(BW, x)));
        rectangle.y = min(y, InWindowY(BW, InBitmapY(BW, y)));
        rectangle.width = max(x + width,
    		     InWindowX(BW, InBitmapX(BW, x + width)+1)) - rectangle.x;
        rectangle.height = max(y + height,
    		     InWindowY(BW, InBitmapY(BW, y + height)+1)) - rectangle.y;
        
        XClearArea(XtDisplay(BW), XtWindow(BW),
    	       rectangle.x, rectangle.y,
    	       rectangle.width, rectangle.height,
    	       False);
    
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.frame_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
    
        XDrawRectangle(XtDisplay(BW), XtWindow(BW),
    		   BW->bitmap.frame_gc,
    		   InWindowX(BW, 0) - 1, InWindowY(BW, 0) - 1,
    		   InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0) + 1, 
    		   InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0) + 1);
    
        BWClip((Widget) BW, x, y, width, height);
    
        BWRedrawGrid((Widget) BW, x, y, width, height);
    
        BWRedrawSquares((Widget) BW, x, y, width, height);
    
        BWRedrawMark((Widget) BW);
        BWRedrawHotSpot((Widget) BW);
        BWRedrawAxes((Widget) BW);
        BWUnclip((Widget) BW);
    }
    
    Boolean 
    BWQueryGrid(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return BW->bitmap.grid;
    }
    
    void 
    BWSwitchGrid(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        BW->bitmap.grid ^= TRUE;
        BWDrawGrid(w,
    	       0, 0,
    	       BW->bitmap.image->width - 1, BW->bitmap.image->height - 1);
    }
    
    void 
    BWGrid(Widget w, Boolean _switch)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        if (BW->bitmap.grid != _switch)
    	BWSwitchGrid(w);
    }
    
    Boolean 
    BWQueryDashed(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return (BW->bitmap.dashed);
    }
    
    void 
    BWSwitchDashed(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        XRectangle rectangle;
    
        BWRedrawGrid(w, 0, 0, BW->bitmap.width - 1, BW->bitmap.height - 1);
    
        rectangle.x = 0;
        rectangle.y = 0;
        rectangle.width = BW->core.width;
        rectangle.height = BW->core.height;
    
        XSetClipRectangles(XtDisplay(BW),
    		       BW->bitmap.frame_gc,
    		       0, 0,
    		       &rectangle, 1,
    		       Unsorted);
    
        XDrawRectangle(XtDisplay(BW), XtWindow(BW),
    		   BW->bitmap.frame_gc,
    		   InWindowX(BW, 0) - 1, InWindowY(BW, 0) - 1,
    		   InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0) + 1, 
    		   InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0) + 1);
        
        BW->bitmap.dashed ^= True;
        XSetFillStyle(XtDisplay(BW), BW->bitmap.frame_gc,
    		  (BW->bitmap.dashed ? FillStippled : FillSolid));
     
        XDrawRectangle(XtDisplay(BW), XtWindow(BW),
    		   BW->bitmap.frame_gc,
    		   InWindowX(BW, 0) - 1, InWindowY(BW, 0) - 1,
    		   InWindowX(BW, BW->bitmap.width) - InWindowX(BW, 0) + 1, 
    		   InWindowY(BW, BW->bitmap.height) - InWindowY(BW, 0) + 1);
    
        BWUnclip(w);
       
        BWRedrawGrid(w, 0, 0, BW->bitmap.width - 1, BW->bitmap.height - 1);
    }
    
    void 
    BWDashed(Widget w, Boolean _switch)
    {
        BitmapWidget BW = (BitmapWidget) w;
        
        if (BW->bitmap.dashed != _switch)
    	BWSwitchDashed(w);
    }
    
    static Boolean 
    SetValues(Widget old, Widget request, Widget new, 
    	  ArgList args, Cardinal *num_args) /* ARGSUSED */
    {
      BitmapWidget oldbw = (BitmapWidget) old;
      BitmapWidget newbw = (BitmapWidget) new;
      Boolean resize = False;
      Boolean redisplay = False;
    
    #define NE(field) (oldbw->field != newbw->field)
    
      if (NE(bitmap.grid))
        BWSwitchGrid(old);
    
      if (NE(bitmap.dashed))
        BWSwitchDashed(old);
    
      if (NE(bitmap.axes))
        BWSwitchAxes(old);
    
      if (NE(bitmap.stippled))
        BWSwitchStippled(old);
    
      if (NE(bitmap.proportional))
        resize = True;
    
      if (NE(bitmap.filename) || NE(bitmap.basename)  || NE(bitmap.size))
        BWChangeNotify(old);
    
      if (NE(bitmap.filename)) {
        if (newbw->bitmap.filename) {
          XtFree(oldbw->bitmap.filename);
          newbw->bitmap.filename = XtNewString(newbw->bitmap.filename);
        }
        else 
          newbw->bitmap.filename = oldbw->bitmap.filename;
      }
    
      if (NE(bitmap.basename)) {
        if (newbw->bitmap.basename) {
          XtFree(oldbw->bitmap.basename);
          newbw->bitmap.basename = XtNewString(newbw->bitmap.basename);
        }
        else 
          newbw->bitmap.basename = oldbw->bitmap.basename;
      }
      
      if (NE(bitmap.size)) {
        Dimension width, height;
        
        if (BWParseSize(newbw->bitmap.size, &width, &height)) { 
          ResizeGrid(newbw, width, height);
          resize = True;
        }
      }
      
      if (NE(bitmap.margin) || 
          NE(bitmap.grid_tolerance) ||
          NE(bitmap.squareW) ||
          NE(bitmap.squareH) ||
          NE(core.height) ||
          NE(core.width))
        resize = True;
    
      if (NE(bitmap.hot.x) || NE(bitmap.hot.y))
        BWSetHotSpot(old, newbw->bitmap.hot.x, newbw->bitmap.hot.y);
        
      if (NE(bitmap.foreground_pixel) || NE(core.background_pixel)) {
        XSetForeground(XtDisplay(new), 
    		   newbw->bitmap.drawing_gc,
    		   newbw->bitmap.foreground_pixel 
    		   ^ 
    		   newbw->core.background_pixel);
        redisplay = True;
      }
    
      if (NE(bitmap.frame_pixel) || NE(core.background_pixel)) {
        XSetForeground(XtDisplay(new), 
    		   newbw->bitmap.frame_gc,
    		   newbw->bitmap.frame_pixel
    		   ^ 
    		   newbw->core.background_pixel);
        redisplay = True;
      }
    
      if (NE(bitmap.dashes)) {
        XSetStipple(XtDisplay(new),
    		newbw->bitmap.frame_gc,
    		newbw->bitmap.dashes);
        redisplay = True;
      }
    
      if (NE(bitmap.highlight_pixel) || NE(core.background_pixel)) {
        RedrawStippled(newbw);
        XSetForeground(XtDisplay(new), 
    		   newbw->bitmap.highlighting_gc,
    		   newbw->bitmap.highlight_pixel
    		   ^ 
    		   newbw->core.background_pixel);
        RedrawStippled(newbw);
      }
     
      if (NE(bitmap.stipple)) {
        RedrawStippled(newbw);
        XSetStipple(XtDisplay(new),
    		newbw->bitmap.highlighting_gc,
    		newbw->bitmap.stipple);
        RedrawStippled(newbw);
      }
      
      if (resize) Resize((Widget)newbw);
    
        return (redisplay || resize);
    
    #undef NE
    }
    
    Boolean 
    BWQueryProportional(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        return (BW->bitmap.proportional);
    }
    
    void 
    BWSwitchProportional(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BW->bitmap.proportional ^= True;
    
        Resize((Widget)BW);
        if (BW->core.visible)
    	XClearArea(XtDisplay(BW), XtWindow(BW),
    		   0, 0, 
    		   BW->core.width, BW->core.height,
    		   True);
    }
    
    #if 0
    void 
    BWProportional(Widget w, Boolean _switch)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (BW->bitmap.proportional != _switch)
    	BWSwitchProportional(w);
    }
    #endif
    
    void 
    BWTPaste(Widget w, XEvent *event, String *params, Cardinal *num_params)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BWRequestSelection(w, event->xbutton.time, TRUE);
    
        if (!BWQueryStored(w))
    	return;
        
        BWEngageRequest(w, RestoreRequest, False, 
    		    (char *)&(event->xbutton.state), sizeof(int));
        
        OnePointHandler(w,
    	       (BWStatus*) BW->bitmap.request_stack[BW->bitmap.current].status,
    	       event, NULL);
    }
    
    void 
    BWTMark(Widget w, XEvent *event, String *params, Cardinal *num_params)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BWEngageRequest(w, MarkRequest, False,
    		    (char *)&(event->xbutton.state), sizeof(int));
        TwoPointsHandler(w,
                (BWStatus*) BW->bitmap.request_stack[BW->bitmap.current].status,
    	     event, NULL);
    
    }
    
    void 
    BWTMarkAll(Widget w, XEvent *event, String *params, Cardinal *num_params)
    {
        BWMarkAll(w);
    
        BWGrabSelection(w, event->xkey.time);
    }
    
    void 
    BWTUnmark(Widget w, XEvent *event, String *params, Cardinal *num_params)
    {
        BWUnmark(w);
    }
    
    /*****************************************************************************/