Edit

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

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2026-02-15 10:09:14
    Hash : 81f70434
    Message : update to bitmap 1.1.2

  • app/bitmap/Graphics.c
  • /*
    
    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.
    
    */
    
    /*
     * Author:  Davor Matic, MIT X Consortium
     */
    
    #ifdef HAVE_CONFIG_H
    # include "config.h"
    #endif
    
    #include <X11/IntrinsicP.h>
    #include <X11/StringDefs.h>
    #include <X11/Xfuncs.h>
    #include "BitmapP.h"
    #include "Bitmap.h"
    #include "Requests.h"
    
    #include <stdio.h>
    #include <math.h>
    
    #ifndef abs
    #define abs(x)                        (((x) > 0) ? (x) : -(x))
    #endif
    #define min(x, y)                     (((int)(x) < (int)(y)) ? (x) : (y))
    #define max(x, y)                     (((int)(x) > (int)(y)) ? (x) : (y))
    #ifndef rint
    # if HAVE_LRINT
    #  define rint(x)                     lrint(x)
    # else
    #  define rint(x)                     floor(x + 0.5)
    # endif
    #endif
    
    #ifdef __clang__
    /* clang doesn't like (int)floor(d) */
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wbad-function-cast"
    #endif
    
    /*****************************************************************************\
     *                                   Graphics                                *
    \*****************************************************************************/
    
    #define GetBit(image, x, y)\
        ((bit)((*(image->data + (x) / 8 + (y) * image->bytes_per_line) &\
    	    (1 << ((x) & 7))) ? 1 : 0))
    
    #if 0
    bit
    BWGetBit(Widget w, Position x, Position y)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QueryInBitmap(BW, x, y))
    	return GetBit(BW->bitmap.image, x, y);
        else
    	return NotSet;
    }
    #endif
    
    #define InvertBit(image, x, y)\
        (*(image->data + (x) / 8 + (y) * image->bytes_per_line) ^=\
         (bit) (1 << ((x) % 8)))
    
    
    #define SetBit(image, x, y)\
        (*(image->data + (x) / 8 + (y) * image->bytes_per_line) |=\
         (bit) (1 << ((x) % 8)))
    
    #define ClearBit(image, x, y)\
        (*(image->data + (x) / 8 + (y) * image->bytes_per_line) &=\
         (bit)~(1 << ((x) % 8)))
    
    
    #define HighlightSquare(BW, x, y)\
        XFillRectangle(XtDisplay(BW), XtWindow(BW),\
                       BW->bitmap.highlighting_gc,\
    		   InWindowX(BW, x), InWindowY(BW, y),\
                       BW->bitmap.squareW, BW->bitmap.squareH)
    /*
    void
    HighlightSquare(BitmapWidget BW, Position x, Position y)
    {
        XFillRectangle(XtDisplay(BW), XtWindow(BW),
                       BW->bitmap.highlighting_gc,
    		   InWindowX(BW, x), InWindowY(BW, y),
                       BW->bitmap.squareW, BW->bitmap.squareH);
    }
    */
    
    #define DrawSquare(BW, x, y)\
        XFillRectangle(XtDisplay(BW), XtWindow(BW),\
                       BW->bitmap.drawing_gc,\
    		   InWindowX(BW, x), InWindowY(BW, y),\
                       BW->bitmap.squareW, BW->bitmap.squareH)
    
    /*
    void
    DrawSquare(BitmapWidget BW, Position x, Position y)
    {
        XFillRectangle(XtDisplay(BW), XtWindow(BW),
                       BW->bitmap.drawing_gc,
    		   InWindowX(BW, x), InWindowY(BW, y),
                       BW->bitmap.squareW, BW->bitmap.squareH);
    }
    */
    
    #define InvertPoint(BW, x, y)\
        {InvertBit(BW->bitmap.image, x, y); DrawSquare(BW, x, y);}
    
    #define DrawPoint(BW, x, y, value)\
        if (GetBit(BW->bitmap.image, x, y) != value)\
           InvertPoint(BW, x, y)
    
    void
    BWDrawPoint(Widget w, Position x, Position y, bit value)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QueryInBitmap(BW, x, y)) {
    	if (value == Highlight)
    	    HighlightSquare(BW, x, y);
    	else
    	    DrawPoint(BW, x, y, value);
        }
    }
    
    static XPoint *
    HotSpotShape(BitmapWidget BW, Position x, Position y)
    {
        static XPoint points[5];
    
        points[0].x = InWindowX(BW, x);
        points[0].y = InWindowY(BW, y + 1.0/2);
        points[1].x = InWindowX(BW, x + 1.0/2);
        points[1].y = InWindowY(BW, y + 1);
        points[2].x = InWindowX(BW, x + 1);
        points[2].y = InWindowY(BW, y + 1.0/2);
        points[3].x = InWindowX(BW, x + 1.0/2);
        points[3].y = InWindowY(BW, y);
        points[4].x = InWindowX(BW, x);
        points[4].y = InWindowY(BW, y + 1.0/2);
    
        return points;
    }
    
    #define DrawHotSpot(BW, x, y)\
      XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.drawing_gc,\
    	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
    
    #define HighlightHotSpot(BW, x, y)\
      XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,\
    	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
    
    /*
    XImage *CreateBitmapImage();
    void DestroyBitmapImage();
    */
    
    void
    BWRedrawHotSpot(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
    	DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
    }
    
    void
    BWClearHotSpot(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
          DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
          BW->bitmap.hot.x = BW->bitmap.hot.y = NotSet;
        }
    }
    
    void
    BWDrawHotSpot(Widget w, Position x, Position y, int value)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QueryInBitmap(BW, x, y)) {
    	if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y) &&
    	    ((BW->bitmap.hot.x == x) && (BW->bitmap.hot.y == y))) {
    	    if ((value == Clear) || (value == Invert)) {
    		BWClearHotSpot(w);
    	    }
    	}
    	else
    	    if ((value == Set) || (value == Invert)) {
    		BWClearHotSpot(w);
    		DrawHotSpot(BW, x, y);
    		BW->bitmap.hot.x = x;
    		BW->bitmap.hot.y = y;
    	    }
    
    	if (value == Highlight)
    	    HighlightHotSpot(BW, x, y);
        }
    }
    
    void
    BWSetHotSpot(Widget w, Position x, Position y)
    {
        if (QuerySet(x, y))
    	BWDrawHotSpot(w, x, y, Set);
        else
    	BWClearHotSpot(w);
    }
    
    /* high level procedures */
    
    void
    BWRedrawSquares(Widget w,
    		Position x, Position y,
    		Dimension width, Dimension height)
    {
        BitmapWidget BW = (BitmapWidget) w;
        Position from_x = InBitmapX(BW, x);
        Position from_y = InBitmapY(BW, y);
        Position to_x = InBitmapX(BW, x + width);
        Position 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.image->width - 1, to_x);
        to_y = min(BW->bitmap.image->height - 1, to_y);
    
        for (x = from_x; x <= to_x; x++)
    	for (y = from_y; y <= to_y; y++)
    	    if (GetBit(BW->bitmap.image, x, y)) DrawSquare(BW, x, y);
    }
    
    void
    BWDrawGrid(Widget w,
    	   Position from_x, Position from_y,
    	   Position to_x, Position to_y)
    {
        BitmapWidget BW = (BitmapWidget) w;
        int i;
    
        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.image->width - 1, to_x);
        to_y = min(BW->bitmap.image->height - 1, to_y);
    
        for(i = from_x + (from_x == 0); i <= to_x; i++)
    	XDrawLine(XtDisplay(BW), XtWindow(BW),
    		  BW->bitmap.frame_gc,
    		  InWindowX(BW, i), InWindowY(BW, from_y),
    		  InWindowX(BW, i), InWindowY(BW, to_y + 1));
    
        for(i = from_y + (from_y == 0); i <= to_y; i++)
    	XDrawLine(XtDisplay(BW), XtWindow(BW),
    		  BW->bitmap.frame_gc,
    		  InWindowX(BW, from_x), InWindowY(BW, i),
    		  InWindowX(BW, to_x + 1), InWindowY(BW, i));
    }
    
    
    void
    BWRedrawGrid(Widget w,
    	     Position x, Position y,
    	     Dimension width, Dimension height)
    {
        BitmapWidget BW = (BitmapWidget) w;
        Position from_x = InBitmapX(BW, x);
        Position from_y = InBitmapY(BW, y);
        Position to_x = InBitmapX(BW, x + width);
        Position to_y = InBitmapY(BW, y + height);
    
        if (BW->bitmap.grid)
    	BWDrawGrid(w, from_x, from_y, to_x, to_y);
    }
    
    void
    BWDrawLine(Widget w,
    	   Position from_x, Position from_y,
    	   Position to_x, Position to_y, int value)
    {
        Position i;
        register double x, y;
        double dx, dy, delta;
    
        dx = to_x - from_x;
        dy = to_y - from_y;
        x = from_x + 0.5;
        y = from_y + 0.5;
        delta = max(abs(dx), abs(dy));
        if (delta > 0) {
    	dx /= delta;
    	dy /= delta;
    	for(i = 0; i <= delta; i++) {
    	    BWDrawPoint(w, (Position) x, (Position) y, value);
    	    x += dx;
    	    y += dy;
    	}
        }
        else
    	BWDrawPoint(w, from_x, from_y, value);
    }
    
    void
    BWBlindLine(Widget w,
    	    Position from_x, Position from_y,
    	    Position to_x, Position to_y, int value)
    {
        Position i;
        register double x, y;
        double dx, dy, delta;
    
        dx = to_x - from_x;
        dy = to_y - from_y;
        x = from_x + 0.5;
        y = from_y + 0.5;
        delta = max(abs(dx), abs(dy));
        if (delta > 0) {
    	dx /= delta;
    	dy /= delta;
    	x += dx;
    	y += dy;
    	for(i = 1; i <= delta; i++) {
    	    BWDrawPoint(w, (Position) x, (Position) y, value);
    	    x += dx;
    	    y += dy;
    	}
        }
        else
    	BWDrawPoint(w, from_x, from_y, value);
    }
    
    void
    BWDrawRectangle(Widget w,
    		Position from_x, Position from_y,
    		Position to_x, Position to_y, int value)
    {
        register Position i;
        Dimension delta, width, height;
    
        QuerySwap(from_x, to_x);
        QuerySwap(from_y, to_y);
    
        width = to_x - from_x;
        height = to_y - from_y;
    
        delta = max(width, height);
    
        if (!QueryZero(width, height)) {
    	for (i = 0; (int)i < (int)delta; i++) {
    	    if ((int)i < (int)width) {
    		BWDrawPoint(w, from_x + i, from_y, value);
    		BWDrawPoint(w, to_x - i, to_y, value);
    	    }
    	    if ((int)i < (int)height) {
    		BWDrawPoint(w, from_x, to_y - i, value);
    		BWDrawPoint(w, to_x, from_y + i, value);
    	    }
    	}
        }
        else
    	BWDrawLine(w,
    		   from_x, from_y,
    		   to_x, to_y, value);
    }
    
    void
    BWDrawFilledRectangle(Widget w,
    		      Position from_x, Position from_y,
    		      Position to_x, Position to_y, int value)
    {
        register Position x, y;
    
        QuerySwap(from_x, to_x);
        QuerySwap(from_y, to_y);
    
        for (x = from_x; x <= to_x; x++)
    	for (y = from_y; y <= to_y; y++)
    	    BWDrawPoint(w, x, y, value);
    }
    
    void
    BWDrawCircle(Widget w,
    	     Position origin_x, Position origin_y,
    	     Position point_x, Position point_y, int value)
    {
        register Position i, delta;
        Dimension dx, dy, half;
        double radius;
    
        dx = abs(point_x - origin_x);
        dy = abs(point_y - origin_y);
        radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
        if (radius < 1.0) {
    	BWDrawPoint(w, origin_x, origin_y, value);
        }
        else {
            delta =floor(radius);
    	BWDrawPoint(w, origin_x - delta, origin_y, value);
    	BWDrawPoint(w, origin_x + delta, origin_y, value);
    	BWDrawPoint(w, origin_x, origin_y - delta, value);
    	BWDrawPoint(w, origin_x, origin_y + delta, value);
        }
        half = radius / sqrt(2.0);
        for(i = 1; (int)i <= (int)half; i++) {
    	delta = sqrt(radius * radius - i * i);
    	BWDrawPoint(w, origin_x - delta, origin_y - i, value);
    	BWDrawPoint(w, origin_x - delta, origin_y + i, value);
    	BWDrawPoint(w, origin_x + delta, origin_y - i, value);
    	BWDrawPoint(w, origin_x + delta, origin_y + i, value);
    	if (i != delta) {
    	    BWDrawPoint(w, origin_x - i, origin_y - delta, value);
    	    BWDrawPoint(w, origin_x - i, origin_y + delta, value);
    	    BWDrawPoint(w, origin_x + i, origin_y - delta, value);
    	    BWDrawPoint(w, origin_x + i, origin_y + delta, value);
    	}
        }
    }
    
    void
    BWDrawFilledCircle(Widget w,
    		   Position origin_x, Position origin_y,
    		   Position point_x, Position point_y, int value)
    {
        register Position i, j, delta, rad;
        Dimension dx, dy;
        double radius;
    
        dx = abs(point_x - origin_x);
        dy = abs(point_y - origin_y);
        radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
        rad=floor(radius);
        for(j = origin_x - rad ;
    	j <= origin_x + rad;
    	j++)
                    BWDrawPoint(w, j, origin_y, value);
    
        for(i = 1; i <= rad; i++) {
    	delta = sqrt(radius * radius - i * i);
    	for(j = origin_x - delta; j <= origin_x + delta; j++) {
    	    BWDrawPoint(w, j, origin_y - i, value);
    	    BWDrawPoint(w, j, origin_y + i, value);
    	}
        }
    }
    
    #define QueryFlood(BW, x, y, value)\
        ((GetBit(BW->bitmap.image, x, y) !=\
          (value & 1)) && QueryInBitmap(BW, x, y))
    
    #define Flood(BW, x, y, value)\
        {if (value == Highlight) HighlightSquare(BW, x, y);\
         else InvertPoint(BW, x, y);}
    
    /*
    static void
    FloodLoop(BitmapWidget BW, Position x, Position y, int value)
    {
        if (QueryFlood(BW, x, y, value)) {
    	Flood(BW, x, y, value);
    	FloodLoop(BW, x, y - 1, value);
    	FloodLoop(BW, x - 1, y, value);
    	FloodLoop(BW, x, y + 1, value);
    	FloodLoop(BW, x + 1, y, value);
        }
    }
    */
    
    static void
    FloodLoop(BitmapWidget BW, Position x, Position y, int value)
    {
        Position save_x, save_y, x_left, x_right;
    
        if (QueryFlood(BW, x, y, value))
    	Flood(BW, x, y, value)
    
    
        save_x = x;
        save_y = y;
    
        x++;
        while (QueryFlood(BW, x, y, value)) {
    	Flood(BW, x, y, value);
    	x++;
        }
        x_right = --x;
    
        x = save_x;
        x--;
        while (QueryFlood(BW, x, y, value)) {
    	Flood(BW, x, y, value);
    	x--;
        }
        x_left = ++x;
    
    
        x = x_left;
        y = save_y;
        y++;
    
        while (x <= x_right) {
    	Boolean flag = False;
    	Position x_enter;
    
    	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
    	    flag = True;
    	    x++;
    	}
    
    	if (flag) {
    	    if ((x == x_right) && QueryFlood(BW, x, y, value))
    		FloodLoop(BW, x, y, value);
    	    else
    		FloodLoop(BW, x - 1, y, value);
    	}
    
    	x_enter = x;
    
    	while (!QueryFlood(BW, x, y, value) && (x < x_right))
    	    x++;
    
    	if (x == x_enter) x++;
        }
    
        x = x_left;
        y = save_y;
        y--;
    
        while (x <= x_right) {
    	Boolean flag = False;
    	Position x_enter;
    
    	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
    	    flag = True;
    	    x++;
    	}
    
    	if (flag) {
    	    if ((x == x_right) && QueryFlood(BW, x, y, value))
    		FloodLoop(BW, x, y, value);
    	    else
    		FloodLoop(BW, x - 1, y, value);
    	}
    
    	x_enter = x;
    
    	while (!QueryFlood(BW, x, y, value) && (x < x_right))
    	    x++;
    
    	if (x == x_enter) x++;
        }
    }
    
    void
    BWFloodFill(Widget w, Position x, Position y, int value)
    {
        BitmapWidget BW = (BitmapWidget) w;
        int pixel;
    
        pixel = GetBit(BW->bitmap.image, x, y);
    
        if (value == Invert)
    	FloodLoop(BW, x, y, (pixel ? Clear : Set));
        else if (value != pixel)
    	FloodLoop(BW, x, y, value);
    }
    
    #define QueryHotInMark(BW)\
        ((BW->bitmap.hot.x == max(BW->bitmap.mark.from_x,\
    			      min(BW->bitmap.hot.x, BW->bitmap.mark.to_x)))\
         &&\
         (BW->bitmap.hot.y == max(BW->bitmap.mark.from_y,\
    			      min(BW->bitmap.hot.y, BW->bitmap.mark.to_y))))
    
    void
    BWUpAction(Widget w, _X_UNUSED XEvent *event,
               _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWUp(w);
    }
    
    void
    BWUp(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        bit first, up, down=0;
        Position from_x, from_y, to_x, to_y;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
    
        if ((to_y - from_y) == 0)
    	return;
    
        for(x = from_x; x <= to_x; x++) {
    	first = up = GetBit(BW->bitmap.image, x, to_y);
    	for(y = to_y - 1; y >= from_y; y--) {
    	    down = GetBit(BW->bitmap.image, x, y);
    	    if (up != down)
    		InvertPoint(BW, x, y);
    	    up =down;
    	}
    	if(first != down)
    	    InvertPoint(BW, x, to_y);
        }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w))
    	BWSetHotSpot(w,
    		     BW->bitmap.hot.x,
    		     (BW->bitmap.hot.y - 1 + BW->bitmap.image->height) %
    		     BW->bitmap.image->height);
    
    }
    
    void
    BWDownAction(Widget w, _X_UNUSED XEvent *event,
                 _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWDown(w);
    }
    
    void
    BWDown(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        bit first, down, up=0;
        Position from_x, from_y, to_x, to_y;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
    
        if ((to_y - from_y) == 0)
    	return;
    
        for(x = from_x; x <= to_x; x++) {
    	first = down = GetBit(BW->bitmap.image, x, from_y);
    	for(y = from_y + 1; y <= to_y; y++) {
    	    up = GetBit(BW->bitmap.image, x, y);
    	    if (down != up)
    		InvertPoint(BW, x, y);
    	    down = up;
    	}
    	if(first != up)
    	    InvertPoint(BW, x, from_y);
        }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w))
    	BWSetHotSpot(w,
    		     BW->bitmap.hot.x,
    		     (BW->bitmap.hot.y + 1) % BW->bitmap.image->height);
    }
    
    void
    BWLeftAction(Widget w, _X_UNUSED XEvent *event,
                 _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWLeft(w);
    }
    
    void
    BWLeft(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        bit first, left, right=0;
        Position from_x, from_y, to_x, to_y;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
    
        if ((to_x - from_x) == 0)
    	return;
    
        for(y = from_y; y <= to_y; y++) {
    	first = left = GetBit(BW->bitmap.image, to_x, y);
    	for(x = to_x - 1; x >= from_x; x--) {
    	    right = GetBit(BW->bitmap.image, x, y);
    	    if (left != right)
    		InvertPoint(BW, x, y);
    	    left = right;
    	}
    	if(first != right)
    	    InvertPoint(BW, to_x, y);
        }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w))
    	BWSetHotSpot(w,
    		     (BW->bitmap.hot.x - 1 + BW->bitmap.image->width) %
    		     BW->bitmap.image->width,
    		     BW->bitmap.hot.y);
    }
    
    void
    BWRightAction(Widget w, _X_UNUSED XEvent *event,
                  _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWRight(w);
    }
    
    void
    BWRight(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        bit first, right, left=0;
        Position from_x, from_y, to_x, to_y;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
    
        if ((to_x - from_x) == 0)
    	return;
    
        for(y = from_y; y <= to_y; y++) {
    	first = right = GetBit(BW->bitmap.image, from_x, y);
    	for(x = from_x + 1; x <= to_x; x++) {
    	    left = GetBit(BW->bitmap.image, x, y);
    	    if (right != left)
    		InvertPoint(BW, x, y);
    	    right = left;
    	}
    	if(first != left)
    	    InvertPoint(BW, from_x, y);
        }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w))
    	BWSetHotSpot(w,
    		     (BW->bitmap.hot.x + 1) % BW->bitmap.image->width,
    		     BW->bitmap.hot.y);
    }
    
    /* void TransferImageData(); */
    
    void
    BWFoldAction(Widget w, _X_UNUSED XEvent *event,
           _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWFold(w);
    }
    
    void
    BWFold(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        Position x, y, new_x, new_y;
        Dimension horiz, vert;
        char *storage_data;
        XImage *storage;
    
        storage_data = CreateCleanData(Length(BW->bitmap.image->width,
    					  BW->bitmap.image->height));
    
        storage = CreateBitmapImage(BW, storage_data,
    				(Dimension) BW->bitmap.image->width,
    				(Dimension) BW->bitmap.image->height);
    
        TransferImageData(BW->bitmap.image, storage);
    
        BW->bitmap.fold ^= True;
        horiz = (BW->bitmap.image->width + BW->bitmap.fold) / 2;
        vert = (BW->bitmap.image->height + BW->bitmap.fold) / 2;
    
        for (x = 0; x < BW->bitmap.image->width; x++)
    	for (y = 0; y < BW->bitmap.image->height; y++) {
    	    new_x = (int)(x + horiz) % (int)BW->bitmap.image->width;
    	    new_y = (int)(y + vert) % (int)BW->bitmap.image->height;
    	    if(GetBit(BW->bitmap.image, new_x, new_y) !=
    	       GetBit(storage, x, y))
    		InvertPoint(BW, new_x, new_y);
    	}
    
        DestroyBitmapImage(&storage);
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
          BWSetHotSpot(w,
    		   (Position)
    		   ((int)(BW->bitmap.hot.x+horiz)
    		    %(int)BW->bitmap.image->width),
    		   (Position)
    		   ((int)(BW->bitmap.hot.y+vert)
    		    %(int)BW->bitmap.image->height)
    		   );
    }
    
    
    void
    BWClearAction(Widget w, _X_UNUSED XEvent *event,
                  _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWClear(w);
    }
    
    void
    BWClear(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        int i, length;
    
        length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
    
        for (x = 0; x < BW->bitmap.image->width; x++)
    	for (y = 0; y < BW->bitmap.image->height; y++)
    	    if (GetBit(BW->bitmap.image, x, y))
    		DrawSquare(BW, x, y);
    
        for (i = 0; i < length; i++)
    	BW->bitmap.image->data[i] = 0;
    
    }
    
    void
    BWSetAction(Widget w, _X_UNUSED XEvent *event,
                _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWSet(w);
    }
    
    void
    BWSet(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        int i, length;
    
        length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
    
        for (x = 0; x < BW->bitmap.image->width; x++)
    	for (y = 0; y < BW->bitmap.image->height; y++)
    	    if (!GetBit(BW->bitmap.image, x, y))
    		DrawSquare(BW, x, y);
    
        for (i = 0; i < length; i++)
    	BW->bitmap.image->data[i] = (char)255;
    
    }
    
    void
    BWRedraw(Widget w, _X_UNUSED XEvent *event,
             _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        XClearArea(XtDisplay(BW), XtWindow(BW),
    	       0, 0, BW->core.width, BW->core.height,
    	       True);
    }
    
    void
    BWInvertAction(Widget w, _X_UNUSED XEvent *event,
                   _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWInvert(w);
    }
    
    void
    BWInvert(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        int i, length;
    
        length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
    
        XFillRectangle(XtDisplay(BW), XtWindow(BW),
    		   BW->bitmap.drawing_gc,
    		   InWindowX(BW, 0), InWindowY(BW, 0),
    		   InWindowX(BW, BW->bitmap.image->width) - InWindowX(BW, 0),
    		   InWindowY(BW, BW->bitmap.image->height) - InWindowY(BW, 0));
    
        for (i = 0; i < length; i++)
    	BW->bitmap.image->data[i] ^= 255;
    }
    
    void
    BWFlipHorizAction(Widget w, _X_UNUSED XEvent *event,
                      _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWFlipHoriz(w);
    }
    
    void
    BWFlipHoriz(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        Position from_x, from_y, to_x, to_y;
        float half;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
        half = (float) (to_y - from_y) / 2.0 + 0.5;
    
        if (half == 0.0)
    	return;
    
        for (x = from_x; x <= to_x; x++)
    	for (y = 0; y <  half; y++)
    	    if (GetBit(BW->bitmap.image, x, from_y + y) !=
    		GetBit(BW->bitmap.image, x, to_y - y)) {
    		InvertPoint(BW, x, from_y + y);
    		InvertPoint(BW, x, to_y - y);
    	    }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w))
    	BWSetHotSpot(w,
    		     BW->bitmap.hot.x,
    		     BW->bitmap.image->height - 1 - BW->bitmap.hot.y);
    }
    
    void
    BWFlipVertAction(Widget w, _X_UNUSED XEvent *event,
                     _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWFlipVert(w);
    }
    
    void
    BWFlipVert(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        register Position x, y;
        Position from_x, from_y, to_x, to_y;
        float half;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
        half = (float) (to_x - from_x) / 2.0 + 0.5;
    
        if (half == 0)
    	return;
    
        for (y = from_y; y <= to_y; y++)
    	for (x = 0; x < half; x++)
    	    if (GetBit(BW->bitmap.image, from_x + x, y) !=
    		GetBit(BW->bitmap.image, to_x - x, y)) {
    		InvertPoint(BW, from_x + x, y);
    		InvertPoint(BW, to_x - x, y);
    	    }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w))
    	BWSetHotSpot(w,
    		     BW->bitmap.image->width - 1 - BW->bitmap.hot.x,
    		     BW->bitmap.hot.y);
    }
    
    
    void
    BWRotateRightAction(Widget w, _X_UNUSED XEvent *event,
                        _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWRotateRight(w);
    }
    
    void
    BWRotateRight(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        Position x, y, delta, shift, tmp;
        Position half_width, half_height;
        XPoint hot;
        bit quad1, quad2, quad3, quad4;
        Position from_x, from_y, to_x, to_y;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
    
        half_width = floor((to_x - from_x) / 2.0 + 0.5);
        half_height = floor((to_y - from_y ) / 2.0 + 0.5);
        shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
        delta = min((Position) half_width, (Position) half_height) - shift;
    
        for (x = 0; x <= delta; x++) {
    	for (y = 1 - shift; y <= delta; y++) {
    	    quad1 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width + x,
    			   from_y + (Position)half_height + y);
    	    quad2 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width + y,
    			   from_y + (Position)half_height - shift - x);
    	    quad3 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width - shift - x,
    			   from_y + (Position)half_height - shift - y);
    	    quad4 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width - shift - y,
    			   from_y + (Position)half_height + x);
    
    	    if (quad1 != quad2)
    		InvertPoint(BW,
    			    from_x + (Position)half_width + x,
    			    from_y + (Position)half_height + y);
    	    if (quad2 != quad3)
    		InvertPoint(BW,
    			    from_x + (Position)half_width + y,
    			    from_y + (Position)half_height - shift - x);
    	    if (quad3 != quad4)
    		InvertPoint(BW,
    			    from_x + (Position)half_width - shift - x,
    			    from_y + (Position)half_height - shift - y);
    	    if (quad4 != quad1)
    		InvertPoint(BW,
    			    from_x + (Position)half_width - shift - y,
    			    from_y + (Position)half_height + x);
    	}
        }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w)) {
    	hot.x = BW->bitmap.hot.x - half_width;
    	hot.y = BW->bitmap.hot.y - half_height;
    	if (hot.x >= 0) hot.x += shift;
    	if (hot.y >= 0) hot.y += shift;
    	tmp = hot.x;
    	hot.x = - hot.y;
    	hot.y = tmp;
    	if (hot.x > 0) hot.x -= shift;
    	if (hot.y > 0) hot.y -= shift;
    	hot.x += half_width;
    	hot.y += half_height;
    	if (QueryInBitmap(BW, hot.x, hot.y))
    	    BWSetHotSpot(w, hot.x, hot.y);
        }
    
    }
    
    void
    BWRotateLeftAction(Widget w, _X_UNUSED XEvent *event,
                        _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWRotateLeft(w);
    }
    
    void
    BWRotateLeft(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        Position x, y,delta, shift, tmp;
        Position half_width, half_height;
        XPoint hot;
        bit quad1, quad2, quad3, quad4;
        Position from_x, from_y, to_x, to_y;
    
        if (BWQueryMarked(w)) {
    	from_x = BW->bitmap.mark.from_x;
    	from_y = BW->bitmap.mark.from_y;
    	to_x = BW->bitmap.mark.to_x;
    	to_y = BW->bitmap.mark.to_y;
        }
        else {
    	from_x = 0;
    	from_y = 0;
    	to_x = BW->bitmap.width - 1;
    	to_y = BW->bitmap.height - 1;
        }
    
        half_width = floor((to_x - from_x) / 2.0 + 0.5);
        half_height = floor((to_y - from_y ) / 2.0 + 0.5);
        shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
        delta = min((Position) half_width, (Position) half_height) - shift;
    
        for (x = 0; x <= delta; x++) {
    	for (y = 1 - shift; y <= delta; y++) {
    	    quad1 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width + x,
    			   from_y + (Position)half_height + y);
    	    quad2 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width + y,
    			   from_y + (Position)half_height - shift - x);
    	    quad3 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width - shift - x,
    			   from_y + (Position)half_height - shift - y);
    	    quad4 = GetBit(BW->bitmap.image,
    			   from_x + (Position)half_width - shift - y,
    			   from_y + (Position)half_height + x);
    
    	    if (quad1 != quad4)
    		InvertPoint(BW,
    			    from_x + (Position)half_width + x,
    			    from_y + (Position)half_height + y);
    	    if (quad2 != quad1)
    		InvertPoint(BW,
    			    from_x + (Position)half_width + y,
    			    from_y + (Position)half_height - shift - x);
    	    if (quad3 != quad2)
    		InvertPoint(BW,
    			    from_x + (Position)half_width - shift - x,
    			    from_y + (Position)half_height - shift - y);
    	    if (quad4 != quad3)
    		InvertPoint(BW,
    			    from_x + (Position)half_width - shift - y,
    			    from_y + (Position)half_height + x);
    	}
        }
    
        if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    	&&
    	!BWQueryMarked(w)) {
    	hot.x = BW->bitmap.hot.x - half_width;
    	hot.y = BW->bitmap.hot.y - half_height;
    	if (hot.x >= 0) hot.x += shift;
    	if (hot.y >= 0) hot.y += shift;
    	tmp = hot.x;
    	hot.x = hot.y;
    	hot.y = - tmp;
    	if (hot.x > 0) hot.x -= shift;
    	if (hot.y > 0) hot.y -= shift;
    	hot.x += half_width;
    	hot.y += half_height;
    	if (QueryInBitmap(BW, hot.x, hot.y))
    	    BWSetHotSpot(w, hot.x, hot.y);
        }
    }
    
    
    void
    CopyImageData(XImage *source, XImage *destination,
    	      Position from_x, Position from_y,
    	      Position to_x, Position to_y,
    	      Position at_x, Position at_y)
    {
        Position x, y, delta_x, delta_y;
    
        delta_x = to_x - from_x + 1;
        delta_y = to_y - from_y + 1;
    
        for (x = 0; x < delta_x; x++)
    	for (y = 0; y < delta_y; y++)
    	    if (GetBit(source, from_x + x, from_y + y))
    		SetBit(destination, at_x + x, at_y + y);
    	    else
    		ClearBit(destination, at_x + x, at_y + y);
    }
    
    XImage *
    ConvertToBitmapImage(BitmapWidget BW, XImage *image)
    {
        XImage *bitmap_image;
        char   *data;
        Position x, y;
    
        data = CreateCleanData(Length(image->width, image->height));
        bitmap_image = CreateBitmapImage(BW, data,
    				     (Dimension) image->width,
    				     (Dimension) image->height);
    
        for (x = 0; x < min(image->width, bitmap_image->width); x++)
    	for (y = 0; y < min(image->height, bitmap_image->height); y++)
    	    if ((XGetPixel(image, x, y) != 0) != GetBit(bitmap_image, x, y))
    		InvertBit(bitmap_image, x, y);
    
        return bitmap_image;
    }
    
    void
    TransferImageData(XImage *source, XImage *destination)
    {
        Position x, y;
    
        for (x = 0; x < min(source->width, destination->width); x++)
    	for (y = 0; y < min(source->height, destination->height); y++)
    	    if (GetBit(source, x, y) != GetBit(destination, x, y))
    		InvertBit(destination, x, y);
    }
    
    void
    BWStore(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        Dimension width, height;
        char *storage_data;
    
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
    
    	DestroyBitmapImage(&BW->bitmap.storage);
    
    	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
    	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
    
    	storage_data = CreateCleanData(Length(width, height));
    
    	BW->bitmap.storage = CreateBitmapImage(BW,
    					       storage_data,
    					       width, height);
    
    	CopyImageData(BW->bitmap.image, BW->bitmap.storage,
    		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
    		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
    		      0, 0);
        }
    }
    
    void
    BWClearMarked(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
    	BWDrawFilledRectangle(w,
    			      BW->bitmap.mark.from_x,
    			      BW->bitmap.mark.from_y,
    			      BW->bitmap.mark.to_x,
    			      BW->bitmap.mark.to_y,
    			      Clear);
    }
    
    
    void
    BWDragMarked(Widget w, Position at_x, Position at_y)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
    	BWDrawRectangle(w,
    			at_x, at_y,
    			at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
    			at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y,
    			Highlight);
    }
    
    void
    BWDragStored(Widget w, Position at_x, Position at_y)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (BW->bitmap.storage)
    	BWDrawRectangle(w,
    			at_x, at_y,
    			at_x + BW->bitmap.storage->width - 1,
    			at_y + BW->bitmap.storage->height - 1,
    			Highlight);
    }
    
    static void
    DrawImageData(BitmapWidget BW, XImage *image,
    	      Position at_x, Position at_y, int value)
    {
        Position x, y;
        Boolean  C, S, I, H;
        bit      A, B;
    
        C = value == Clear;
        S = value == Set;
        I = value == Invert;
        H = value == Highlight;
    
        for (x = 0; x < image->width; x++)
    	for (y = 0; y < image->height; y++) {
    	    A = GetBit(image, x, y);
    	    B = GetBit(BW->bitmap.image, at_x + x, at_y + y);
    	    if ((A & C) | ((A | B) & S) | ((A ^ B) & I) | ((A | B) & H))
    		value = (A & H) ? Highlight : Set;
    	    else
    		value = Clear;
    	    BWDrawPoint((Widget) BW,
    			 at_x + x, at_y + y,
    			 value);
    	}
    }
    
    void
    BWRestore(Widget w, Position at_x, Position at_y, int value)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (BW->bitmap.storage) {
          DrawImageData(BW, BW->bitmap.storage, at_x, at_y, value);
          /*DestroyBitmapImage(&BW->bitmap.storage);*/
        }
    }
    
    void
    BWCopy(Widget w, Position at_x, Position at_y, int value)
    {
        BitmapWidget BW = (BitmapWidget) w;
        XImage *storage;
        char *storage_data;
        Dimension width, height;
    
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
    
    	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
    	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
    
    	storage_data = CreateCleanData(Length(width, height));
    
    	storage = CreateBitmapImage(BW, storage_data, width, height);
    
    	CopyImageData(BW->bitmap.image, storage,
    		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
    		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
    		      0, 0);
    
    	DrawImageData(BW, storage, at_x, at_y, value);
    
    	DestroyBitmapImage(&storage);
        }
    }
    
    /* void BWMark(); */
    
    void
    BWMove(Widget w, Position at_x, Position at_y, int value)
    {
        BitmapWidget BW = (BitmapWidget) w;
        XImage *storage;
        char *storage_data;
        Dimension width, height;
    
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
    
    	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
    	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
    
    	storage_data = CreateCleanData(Length(width, height));
    
    	storage = CreateBitmapImage(BW, storage_data, width, height);
    
    	CopyImageData(BW->bitmap.image, storage,
    		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
    		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
    		      0, 0);
    
    	BWDrawFilledRectangle(w,
    			      BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
    			      BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
    			      Clear);
    
    	DrawImageData(BW, storage, at_x, at_y, value);
    
    	BWMark(w, at_x, at_y,
    	     at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
    	     at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y);
    
    	DestroyBitmapImage(&storage);
        }
    }
    
    void
    BWRedrawMark(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
    	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
    		       InWindowX(BW, BW->bitmap.mark.from_x),
    		       InWindowY(BW, BW->bitmap.mark.from_y),
    		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
    		       InWindowX(BW, BW->bitmap.mark.from_x),
    		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
    		       InWindowY(BW, BW->bitmap.mark.from_y));
    }
    
    void
    BWStoreToBufferAction(Widget w, _X_UNUSED XEvent *event,
                          _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWStoreToBuffer(w);
    }
    
    void
    BWStoreToBuffer(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        memmove( BW->bitmap.buffer->data, BW->bitmap.image->data,
    	  Length(BW->bitmap.image->width, BW->bitmap.image->height));
    
        BW->bitmap.buffer_hot = BW->bitmap.hot;
        BW->bitmap.buffer_mark = BW->bitmap.mark;
    }
    
    void
    BWUnmark(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BW->bitmap.buffer_mark = BW->bitmap.mark;
    
        if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
    	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
    		       InWindowX(BW, BW->bitmap.mark.from_x),
    		       InWindowY(BW, BW->bitmap.mark.from_y),
    		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
    		       InWindowX(BW, BW->bitmap.mark.from_x),
    		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
    		       InWindowY(BW, BW->bitmap.mark.from_y));
    
    	BW->bitmap.mark.from_x = BW->bitmap.mark.from_y = NotSet;
    	BW->bitmap.mark.to_x = BW->bitmap.mark.to_y = NotSet;
        }
    }
    
    void
    BWMark(Widget w, Position from_x, Position from_y,
           Position to_x, Position to_y)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        BWUnmark(w);
    
        if (QuerySet(from_x, from_y)) {
    	if ((from_x == to_x) && (from_y == to_y)) {
    	    /*
    	      BW->bitmap.mark.from_x = 0;
    	      BW->bitmap.mark.from_y = 0;
    	      BW->bitmap.mark.to_x = BW->bitmap.image->width - 1;
    	      BW->bitmap.mark.to_y = BW->bitmap.image->height - 1;
    	      */
    	    return;
    	}
    	else {
    	    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.image->width - 1, to_x);
    	    to_y = min(BW->bitmap.image->height - 1, to_y);
    
    	    BW->bitmap.mark.from_x = from_x;
    	    BW->bitmap.mark.from_y = from_y;
    	    BW->bitmap.mark.to_x = to_x;
    	    BW->bitmap.mark.to_y = to_y;
    	}
    
    	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
    		       InWindowX(BW, BW->bitmap.mark.from_x),
    		       InWindowY(BW, BW->bitmap.mark.from_y),
    		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
    		       InWindowX(BW, BW->bitmap.mark.from_x),
    		       InWindowY(BW, BW->bitmap.mark.to_y +1) -
    		       InWindowY(BW, BW->bitmap.mark.from_y));
        }
    }
    
    void
    BWMarkAll(Widget w)
    {
      BitmapWidget BW = (BitmapWidget) w;
    
      BWMark(w, 0, 0, BW->bitmap.image->width - 1, BW->bitmap.image->height - 1);
    }
    
    void
    BWUndoAction(Widget w, _X_UNUSED XEvent *event,
                 _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    {
        BWUndo(w);
    }
    
    void
    BWUndo(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
        Position x, y;
        char *tmp_data;
        XPoint tmp_hot;
        BWArea tmp_mark;
    
        tmp_data = BW->bitmap.image->data;
        BW->bitmap.image->data = BW->bitmap.buffer->data;
        BW->bitmap.buffer->data = tmp_data;
    
        tmp_hot = BW->bitmap.hot;
        tmp_mark = BW->bitmap.mark;
    
        for (x = 0; x < BW->bitmap.image->width; x++)
    	for (y = 0; y < BW->bitmap.image->height; y++)
    	 if (GetBit(BW->bitmap.image, x, y) != GetBit(BW->bitmap.buffer, x, y))
    	     DrawSquare(BW, x, y);
    
        BWSetHotSpot(w, BW->bitmap.buffer_hot.x, BW->bitmap.buffer_hot.y);
    /*
        BWMark(w, BW->bitmap.buffer_mark.from_x, BW->bitmap.buffer_mark.from_y,
    	   BW->bitmap.buffer_mark.to_x, BW->bitmap.buffer_mark.to_y);
    */
        BW->bitmap.buffer_hot = tmp_hot;
        BW->bitmap.buffer_mark= tmp_mark;
    
    }
    
    void
    BWHighlightAxes(Widget w)
    {
        BitmapWidget BW = (BitmapWidget) w;
    
        XDrawLine(XtDisplay(BW), XtWindow(BW),
    	      BW->bitmap.axes_gc,
    	      InWindowX(BW, 0),
    	      InWindowY(BW, 0),
    	      InWindowX(BW, BW->bitmap.width),
    	      InWindowY(BW, BW->bitmap.height));
        XDrawLine(XtDisplay(BW), XtWindow(BW),
    	      BW->bitmap.axes_gc,
    	      InWindowX(BW, BW->bitmap.width),
    	      InWindowY(BW, 0),
    	      InWindowX(BW, 0),
    	      InWindowY(BW, BW->bitmap.height));
        XDrawLine(XtDisplay(BW), XtWindow(BW),
    	      BW->bitmap.axes_gc,
    	      InWindowX(BW, 0),
    	      InWindowY(BW, (float)BW->bitmap.height / 2.0),
    	      InWindowX(BW, BW->bitmap.width),
    	      InWindowY(BW, (float)BW->bitmap.height / 2.0));
        XDrawLine(XtDisplay(BW), XtWindow(BW),
    	      BW->bitmap.axes_gc,
    	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
    	      InWindowY(BW, 0),
    	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
    	      InWindowY(BW, BW->bitmap.height));
    }
    
    typedef struct {
        Position *x, *y;
        Dimension *width, *height;
    } Table;
    
    XImage *
    ScaleBitmapImage(BitmapWidget BW, XImage *src,
    		 double scale_x, double scale_y)
    {
        char *data;
        XImage *dst;
        Table table;
        Position x, y, w, h;
        Dimension width, height;
        bit pixel;
    
        width = max(rint(scale_x * src->width), 1);
        height = max(rint(scale_y * src->height), 1);
    
        data = CreateCleanData(Length(width, height));
        dst = CreateBitmapImage(BW, data, width, height);
    
        /*
         * It would be nice to check if width or height < 1.0 and
         * average the skipped pixels. But, it is slow as it is now.
         */
        if (scale_x == 1.0 && scale_y == 1.0)
    	memmove( dst->data, src->data, Length(width, height));
        else {
    	table.x = (Position *) XtMalloc(sizeof(Position) * src->width);
    	table.y = (Position *) XtMalloc(sizeof(Position) * src->height);
    	table.width = (Dimension *) XtMalloc(sizeof(Dimension) * src->width);
    	table.height = (Dimension *) XtMalloc(sizeof(Dimension) * src->height);
    
    	for (x = 0; x < src->width; x++) {
    	    table.x[x] = rint(scale_x * x);
    	    table.width[x] = rint(scale_x * (x + 1)) - rint(scale_x * x);
    	}
    	for (y = 0; y < src->height; y++) {
    	    table.y[y] = rint(scale_y * y);
    	    table.height[y] = rint(scale_y * (y + 1)) - rint(scale_y * y);
    	}
    
    	for (x = 0; x < src->width; x++)
    	    for (y = 0; y < src->height; y++) {
    	        pixel = GetBit(src, x, y);
    		for (w = 0; (int)w < (int)table.width[x]; w++)
    		    for (h = 0; (int)h < (int)table.height[y]; h++)
    			if (pixel) SetBit(dst,
    					table.x[x] + w,
    					table.y[y] + h);
    	    }
    
    	XtFree((char *)table.x);
    	XtFree((char *)table.y);
    	XtFree((char *)table.width);
    	XtFree((char *)table.height);
        }
    
        return (dst);
    }
    
    /*****************************************************************************/