Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2 
      3 Copyright 1989, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27 */
     28 
     29 /*
     30  * Author:  Davor Matic, MIT X Consortium
     31  */
     32 
     33 #ifdef HAVE_CONFIG_H
     34 # include "config.h"
     35 #endif
     36 
     37 #include <X11/IntrinsicP.h>
     38 #include <X11/StringDefs.h>
     39 #include <X11/Xfuncs.h>
     40 #include "BitmapP.h"
     41 #include "Bitmap.h"
     42 #include "Requests.h"
     43 
     44 #include <stdio.h>
     45 #include <math.h>
     46 
     47 #ifndef abs
     48 #define abs(x)                        (((x) > 0) ? (x) : -(x))
     49 #endif
     50 #define min(x, y)                     (((int)(x) < (int)(y)) ? (x) : (y))
     51 #define max(x, y)                     (((int)(x) > (int)(y)) ? (x) : (y))
     52 #ifndef rint
     53 # if HAVE_LRINT
     54 #  define rint(x)                     lrint(x)
     55 # else
     56 #  define rint(x)                     floor(x + 0.5)
     57 # endif
     58 #endif
     59 
     60 #ifdef __clang__
     61 /* clang doesn't like (int)floor(d) */
     62 #pragma clang diagnostic push
     63 #pragma clang diagnostic ignored "-Wbad-function-cast"
     64 #endif
     65 
     66 /*****************************************************************************\
     67  *                                   Graphics                                *
     68 \*****************************************************************************/
     69 
     70 #define GetBit(image, x, y)\
     71     ((bit)((*(image->data + (x) / 8 + (y) * image->bytes_per_line) &\
     72 	    (1 << ((x) & 7))) ? 1 : 0))
     73 
     74 #if 0
     75 bit
     76 BWGetBit(Widget w, Position x, Position y)
     77 {
     78     BitmapWidget BW = (BitmapWidget) w;
     79 
     80     if (QueryInBitmap(BW, x, y))
     81 	return GetBit(BW->bitmap.image, x, y);
     82     else
     83 	return NotSet;
     84 }
     85 #endif
     86 
     87 #define InvertBit(image, x, y)\
     88     (*(image->data + (x) / 8 + (y) * image->bytes_per_line) ^=\
     89      (bit) (1 << ((x) % 8)))
     90 
     91 
     92 #define SetBit(image, x, y)\
     93     (*(image->data + (x) / 8 + (y) * image->bytes_per_line) |=\
     94      (bit) (1 << ((x) % 8)))
     95 
     96 #define ClearBit(image, x, y)\
     97     (*(image->data + (x) / 8 + (y) * image->bytes_per_line) &=\
     98      (bit)~(1 << ((x) % 8)))
     99 
    100 
    101 #define HighlightSquare(BW, x, y)\
    102     XFillRectangle(XtDisplay(BW), XtWindow(BW),\
    103                    BW->bitmap.highlighting_gc,\
    104 		   InWindowX(BW, x), InWindowY(BW, y),\
    105                    BW->bitmap.squareW, BW->bitmap.squareH)
    106 /*
    107 void
    108 HighlightSquare(BitmapWidget BW, Position x, Position y)
    109 {
    110     XFillRectangle(XtDisplay(BW), XtWindow(BW),
    111                    BW->bitmap.highlighting_gc,
    112 		   InWindowX(BW, x), InWindowY(BW, y),
    113                    BW->bitmap.squareW, BW->bitmap.squareH);
    114 }
    115 */
    116 
    117 #define DrawSquare(BW, x, y)\
    118     XFillRectangle(XtDisplay(BW), XtWindow(BW),\
    119                    BW->bitmap.drawing_gc,\
    120 		   InWindowX(BW, x), InWindowY(BW, y),\
    121                    BW->bitmap.squareW, BW->bitmap.squareH)
    122 
    123 /*
    124 void
    125 DrawSquare(BitmapWidget BW, Position x, Position y)
    126 {
    127     XFillRectangle(XtDisplay(BW), XtWindow(BW),
    128                    BW->bitmap.drawing_gc,
    129 		   InWindowX(BW, x), InWindowY(BW, y),
    130                    BW->bitmap.squareW, BW->bitmap.squareH);
    131 }
    132 */
    133 
    134 #define InvertPoint(BW, x, y)\
    135     {InvertBit(BW->bitmap.image, x, y); DrawSquare(BW, x, y);}
    136 
    137 #define DrawPoint(BW, x, y, value)\
    138     if (GetBit(BW->bitmap.image, x, y) != value)\
    139        InvertPoint(BW, x, y)
    140 
    141 void
    142 BWDrawPoint(Widget w, Position x, Position y, bit value)
    143 {
    144     BitmapWidget BW = (BitmapWidget) w;
    145 
    146     if (QueryInBitmap(BW, x, y)) {
    147 	if (value == Highlight)
    148 	    HighlightSquare(BW, x, y);
    149 	else
    150 	    DrawPoint(BW, x, y, value);
    151     }
    152 }
    153 
    154 static XPoint *
    155 HotSpotShape(BitmapWidget BW, Position x, Position y)
    156 {
    157     static XPoint points[5];
    158 
    159     points[0].x = InWindowX(BW, x);
    160     points[0].y = InWindowY(BW, y + 1.0/2);
    161     points[1].x = InWindowX(BW, x + 1.0/2);
    162     points[1].y = InWindowY(BW, y + 1);
    163     points[2].x = InWindowX(BW, x + 1);
    164     points[2].y = InWindowY(BW, y + 1.0/2);
    165     points[3].x = InWindowX(BW, x + 1.0/2);
    166     points[3].y = InWindowY(BW, y);
    167     points[4].x = InWindowX(BW, x);
    168     points[4].y = InWindowY(BW, y + 1.0/2);
    169 
    170     return points;
    171 }
    172 
    173 #define DrawHotSpot(BW, x, y)\
    174   XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.drawing_gc,\
    175 	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
    176 
    177 #define HighlightHotSpot(BW, x, y)\
    178   XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,\
    179 	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
    180 
    181 /*
    182 XImage *CreateBitmapImage();
    183 void DestroyBitmapImage();
    184 */
    185 
    186 void
    187 BWRedrawHotSpot(Widget w)
    188 {
    189     BitmapWidget BW = (BitmapWidget) w;
    190 
    191     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
    192 	DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
    193 }
    194 
    195 void
    196 BWClearHotSpot(Widget w)
    197 {
    198     BitmapWidget BW = (BitmapWidget) w;
    199 
    200     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
    201       DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
    202       BW->bitmap.hot.x = BW->bitmap.hot.y = NotSet;
    203     }
    204 }
    205 
    206 void
    207 BWDrawHotSpot(Widget w, Position x, Position y, int value)
    208 {
    209     BitmapWidget BW = (BitmapWidget) w;
    210 
    211     if (QueryInBitmap(BW, x, y)) {
    212 	if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y) &&
    213 	    ((BW->bitmap.hot.x == x) && (BW->bitmap.hot.y == y))) {
    214 	    if ((value == Clear) || (value == Invert)) {
    215 		BWClearHotSpot(w);
    216 	    }
    217 	}
    218 	else
    219 	    if ((value == Set) || (value == Invert)) {
    220 		BWClearHotSpot(w);
    221 		DrawHotSpot(BW, x, y);
    222 		BW->bitmap.hot.x = x;
    223 		BW->bitmap.hot.y = y;
    224 	    }
    225 
    226 	if (value == Highlight)
    227 	    HighlightHotSpot(BW, x, y);
    228     }
    229 }
    230 
    231 void
    232 BWSetHotSpot(Widget w, Position x, Position y)
    233 {
    234     if (QuerySet(x, y))
    235 	BWDrawHotSpot(w, x, y, Set);
    236     else
    237 	BWClearHotSpot(w);
    238 }
    239 
    240 /* high level procedures */
    241 
    242 void
    243 BWRedrawSquares(Widget w,
    244 		Position x, Position y,
    245 		Dimension width, Dimension height)
    246 {
    247     BitmapWidget BW = (BitmapWidget) w;
    248     Position from_x = InBitmapX(BW, x);
    249     Position from_y = InBitmapY(BW, y);
    250     Position to_x = InBitmapX(BW, x + width);
    251     Position to_y = InBitmapY(BW, y + height);
    252 
    253     QuerySwap(from_x, to_x);
    254     QuerySwap(from_y, to_y);
    255     from_x = max(0, from_x);
    256     from_y = max(0, from_y);
    257     to_x = min(BW->bitmap.image->width - 1, to_x);
    258     to_y = min(BW->bitmap.image->height - 1, to_y);
    259 
    260     for (x = from_x; x <= to_x; x++)
    261 	for (y = from_y; y <= to_y; y++)
    262 	    if (GetBit(BW->bitmap.image, x, y)) DrawSquare(BW, x, y);
    263 }
    264 
    265 void
    266 BWDrawGrid(Widget w,
    267 	   Position from_x, Position from_y,
    268 	   Position to_x, Position to_y)
    269 {
    270     BitmapWidget BW = (BitmapWidget) w;
    271     int i;
    272 
    273     QuerySwap(from_x, to_x);
    274     QuerySwap(from_y, to_y);
    275     from_x = max(0, from_x);
    276     from_y = max(0, from_y);
    277     to_x = min(BW->bitmap.image->width - 1, to_x);
    278     to_y = min(BW->bitmap.image->height - 1, to_y);
    279 
    280     for(i = from_x + (from_x == 0); i <= to_x; i++)
    281 	XDrawLine(XtDisplay(BW), XtWindow(BW),
    282 		  BW->bitmap.frame_gc,
    283 		  InWindowX(BW, i), InWindowY(BW, from_y),
    284 		  InWindowX(BW, i), InWindowY(BW, to_y + 1));
    285 
    286     for(i = from_y + (from_y == 0); i <= to_y; i++)
    287 	XDrawLine(XtDisplay(BW), XtWindow(BW),
    288 		  BW->bitmap.frame_gc,
    289 		  InWindowX(BW, from_x), InWindowY(BW, i),
    290 		  InWindowX(BW, to_x + 1), InWindowY(BW, i));
    291 }
    292 
    293 
    294 void
    295 BWRedrawGrid(Widget w,
    296 	     Position x, Position y,
    297 	     Dimension width, Dimension height)
    298 {
    299     BitmapWidget BW = (BitmapWidget) w;
    300     Position from_x = InBitmapX(BW, x);
    301     Position from_y = InBitmapY(BW, y);
    302     Position to_x = InBitmapX(BW, x + width);
    303     Position to_y = InBitmapY(BW, y + height);
    304 
    305     if (BW->bitmap.grid)
    306 	BWDrawGrid(w, from_x, from_y, to_x, to_y);
    307 }
    308 
    309 void
    310 BWDrawLine(Widget w,
    311 	   Position from_x, Position from_y,
    312 	   Position to_x, Position to_y, int value)
    313 {
    314     Position i;
    315     register double x, y;
    316     double dx, dy, delta;
    317 
    318     dx = to_x - from_x;
    319     dy = to_y - from_y;
    320     x = from_x + 0.5;
    321     y = from_y + 0.5;
    322     delta = max(abs(dx), abs(dy));
    323     if (delta > 0) {
    324 	dx /= delta;
    325 	dy /= delta;
    326 	for(i = 0; i <= delta; i++) {
    327 	    BWDrawPoint(w, (Position) x, (Position) y, value);
    328 	    x += dx;
    329 	    y += dy;
    330 	}
    331     }
    332     else
    333 	BWDrawPoint(w, from_x, from_y, value);
    334 }
    335 
    336 void
    337 BWBlindLine(Widget w,
    338 	    Position from_x, Position from_y,
    339 	    Position to_x, Position to_y, int value)
    340 {
    341     Position i;
    342     register double x, y;
    343     double dx, dy, delta;
    344 
    345     dx = to_x - from_x;
    346     dy = to_y - from_y;
    347     x = from_x + 0.5;
    348     y = from_y + 0.5;
    349     delta = max(abs(dx), abs(dy));
    350     if (delta > 0) {
    351 	dx /= delta;
    352 	dy /= delta;
    353 	x += dx;
    354 	y += dy;
    355 	for(i = 1; i <= delta; i++) {
    356 	    BWDrawPoint(w, (Position) x, (Position) y, value);
    357 	    x += dx;
    358 	    y += dy;
    359 	}
    360     }
    361     else
    362 	BWDrawPoint(w, from_x, from_y, value);
    363 }
    364 
    365 void
    366 BWDrawRectangle(Widget w,
    367 		Position from_x, Position from_y,
    368 		Position to_x, Position to_y, int value)
    369 {
    370     register Position i;
    371     Dimension delta, width, height;
    372 
    373     QuerySwap(from_x, to_x);
    374     QuerySwap(from_y, to_y);
    375 
    376     width = to_x - from_x;
    377     height = to_y - from_y;
    378 
    379     delta = max(width, height);
    380 
    381     if (!QueryZero(width, height)) {
    382 	for (i = 0; (int)i < (int)delta; i++) {
    383 	    if ((int)i < (int)width) {
    384 		BWDrawPoint(w, from_x + i, from_y, value);
    385 		BWDrawPoint(w, to_x - i, to_y, value);
    386 	    }
    387 	    if ((int)i < (int)height) {
    388 		BWDrawPoint(w, from_x, to_y - i, value);
    389 		BWDrawPoint(w, to_x, from_y + i, value);
    390 	    }
    391 	}
    392     }
    393     else
    394 	BWDrawLine(w,
    395 		   from_x, from_y,
    396 		   to_x, to_y, value);
    397 }
    398 
    399 void
    400 BWDrawFilledRectangle(Widget w,
    401 		      Position from_x, Position from_y,
    402 		      Position to_x, Position to_y, int value)
    403 {
    404     register Position x, y;
    405 
    406     QuerySwap(from_x, to_x);
    407     QuerySwap(from_y, to_y);
    408 
    409     for (x = from_x; x <= to_x; x++)
    410 	for (y = from_y; y <= to_y; y++)
    411 	    BWDrawPoint(w, x, y, value);
    412 }
    413 
    414 void
    415 BWDrawCircle(Widget w,
    416 	     Position origin_x, Position origin_y,
    417 	     Position point_x, Position point_y, int value)
    418 {
    419     register Position i, delta;
    420     Dimension dx, dy, half;
    421     double radius;
    422 
    423     dx = abs(point_x - origin_x);
    424     dy = abs(point_y - origin_y);
    425     radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
    426     if (radius < 1.0) {
    427 	BWDrawPoint(w, origin_x, origin_y, value);
    428     }
    429     else {
    430         delta =floor(radius);
    431 	BWDrawPoint(w, origin_x - delta, origin_y, value);
    432 	BWDrawPoint(w, origin_x + delta, origin_y, value);
    433 	BWDrawPoint(w, origin_x, origin_y - delta, value);
    434 	BWDrawPoint(w, origin_x, origin_y + delta, value);
    435     }
    436     half = radius / sqrt(2.0);
    437     for(i = 1; (int)i <= (int)half; i++) {
    438 	delta = sqrt(radius * radius - i * i);
    439 	BWDrawPoint(w, origin_x - delta, origin_y - i, value);
    440 	BWDrawPoint(w, origin_x - delta, origin_y + i, value);
    441 	BWDrawPoint(w, origin_x + delta, origin_y - i, value);
    442 	BWDrawPoint(w, origin_x + delta, origin_y + i, value);
    443 	if (i != delta) {
    444 	    BWDrawPoint(w, origin_x - i, origin_y - delta, value);
    445 	    BWDrawPoint(w, origin_x - i, origin_y + delta, value);
    446 	    BWDrawPoint(w, origin_x + i, origin_y - delta, value);
    447 	    BWDrawPoint(w, origin_x + i, origin_y + delta, value);
    448 	}
    449     }
    450 }
    451 
    452 void
    453 BWDrawFilledCircle(Widget w,
    454 		   Position origin_x, Position origin_y,
    455 		   Position point_x, Position point_y, int value)
    456 {
    457     register Position i, j, delta, rad;
    458     Dimension dx, dy;
    459     double radius;
    460 
    461     dx = abs(point_x - origin_x);
    462     dy = abs(point_y - origin_y);
    463     radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
    464     rad=floor(radius);
    465     for(j = origin_x - rad ;
    466 	j <= origin_x + rad;
    467 	j++)
    468                 BWDrawPoint(w, j, origin_y, value);
    469 
    470     for(i = 1; i <= rad; i++) {
    471 	delta = sqrt(radius * radius - i * i);
    472 	for(j = origin_x - delta; j <= origin_x + delta; j++) {
    473 	    BWDrawPoint(w, j, origin_y - i, value);
    474 	    BWDrawPoint(w, j, origin_y + i, value);
    475 	}
    476     }
    477 }
    478 
    479 #define QueryFlood(BW, x, y, value)\
    480     ((GetBit(BW->bitmap.image, x, y) !=\
    481       (value & 1)) && QueryInBitmap(BW, x, y))
    482 
    483 #define Flood(BW, x, y, value)\
    484     {if (value == Highlight) HighlightSquare(BW, x, y);\
    485      else InvertPoint(BW, x, y);}
    486 
    487 /*
    488 static void
    489 FloodLoop(BitmapWidget BW, Position x, Position y, int value)
    490 {
    491     if (QueryFlood(BW, x, y, value)) {
    492 	Flood(BW, x, y, value);
    493 	FloodLoop(BW, x, y - 1, value);
    494 	FloodLoop(BW, x - 1, y, value);
    495 	FloodLoop(BW, x, y + 1, value);
    496 	FloodLoop(BW, x + 1, y, value);
    497     }
    498 }
    499 */
    500 
    501 static void
    502 FloodLoop(BitmapWidget BW, Position x, Position y, int value)
    503 {
    504     Position save_x, save_y, x_left, x_right;
    505 
    506     if (QueryFlood(BW, x, y, value))
    507 	Flood(BW, x, y, value)
    508 
    509 
    510     save_x = x;
    511     save_y = y;
    512 
    513     x++;
    514     while (QueryFlood(BW, x, y, value)) {
    515 	Flood(BW, x, y, value);
    516 	x++;
    517     }
    518     x_right = --x;
    519 
    520     x = save_x;
    521     x--;
    522     while (QueryFlood(BW, x, y, value)) {
    523 	Flood(BW, x, y, value);
    524 	x--;
    525     }
    526     x_left = ++x;
    527 
    528 
    529     x = x_left;
    530     y = save_y;
    531     y++;
    532 
    533     while (x <= x_right) {
    534 	Boolean flag = False;
    535 	Position x_enter;
    536 
    537 	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
    538 	    flag = True;
    539 	    x++;
    540 	}
    541 
    542 	if (flag) {
    543 	    if ((x == x_right) && QueryFlood(BW, x, y, value))
    544 		FloodLoop(BW, x, y, value);
    545 	    else
    546 		FloodLoop(BW, x - 1, y, value);
    547 	}
    548 
    549 	x_enter = x;
    550 
    551 	while (!QueryFlood(BW, x, y, value) && (x < x_right))
    552 	    x++;
    553 
    554 	if (x == x_enter) x++;
    555     }
    556 
    557     x = x_left;
    558     y = save_y;
    559     y--;
    560 
    561     while (x <= x_right) {
    562 	Boolean flag = False;
    563 	Position x_enter;
    564 
    565 	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
    566 	    flag = True;
    567 	    x++;
    568 	}
    569 
    570 	if (flag) {
    571 	    if ((x == x_right) && QueryFlood(BW, x, y, value))
    572 		FloodLoop(BW, x, y, value);
    573 	    else
    574 		FloodLoop(BW, x - 1, y, value);
    575 	}
    576 
    577 	x_enter = x;
    578 
    579 	while (!QueryFlood(BW, x, y, value) && (x < x_right))
    580 	    x++;
    581 
    582 	if (x == x_enter) x++;
    583     }
    584 }
    585 
    586 void
    587 BWFloodFill(Widget w, Position x, Position y, int value)
    588 {
    589     BitmapWidget BW = (BitmapWidget) w;
    590     int pixel;
    591 
    592     pixel = GetBit(BW->bitmap.image, x, y);
    593 
    594     if (value == Invert)
    595 	FloodLoop(BW, x, y, (pixel ? Clear : Set));
    596     else if (value != pixel)
    597 	FloodLoop(BW, x, y, value);
    598 }
    599 
    600 #define QueryHotInMark(BW)\
    601     ((BW->bitmap.hot.x == max(BW->bitmap.mark.from_x,\
    602 			      min(BW->bitmap.hot.x, BW->bitmap.mark.to_x)))\
    603      &&\
    604      (BW->bitmap.hot.y == max(BW->bitmap.mark.from_y,\
    605 			      min(BW->bitmap.hot.y, BW->bitmap.mark.to_y))))
    606 
    607 void
    608 BWUpAction(Widget w, _X_UNUSED XEvent *event,
    609            _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    610 {
    611     BWUp(w);
    612 }
    613 
    614 void
    615 BWUp(Widget w)
    616 {
    617     BitmapWidget BW = (BitmapWidget) w;
    618     register Position x, y;
    619     bit first, up, down=0;
    620     Position from_x, from_y, to_x, to_y;
    621 
    622     if (BWQueryMarked(w)) {
    623 	from_x = BW->bitmap.mark.from_x;
    624 	from_y = BW->bitmap.mark.from_y;
    625 	to_x = BW->bitmap.mark.to_x;
    626 	to_y = BW->bitmap.mark.to_y;
    627     }
    628     else {
    629 	from_x = 0;
    630 	from_y = 0;
    631 	to_x = BW->bitmap.width - 1;
    632 	to_y = BW->bitmap.height - 1;
    633     }
    634 
    635     if ((to_y - from_y) == 0)
    636 	return;
    637 
    638     for(x = from_x; x <= to_x; x++) {
    639 	first = up = GetBit(BW->bitmap.image, x, to_y);
    640 	for(y = to_y - 1; y >= from_y; y--) {
    641 	    down = GetBit(BW->bitmap.image, x, y);
    642 	    if (up != down)
    643 		InvertPoint(BW, x, y);
    644 	    up =down;
    645 	}
    646 	if(first != down)
    647 	    InvertPoint(BW, x, to_y);
    648     }
    649 
    650     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    651 	&&
    652 	!BWQueryMarked(w))
    653 	BWSetHotSpot(w,
    654 		     BW->bitmap.hot.x,
    655 		     (BW->bitmap.hot.y - 1 + BW->bitmap.image->height) %
    656 		     BW->bitmap.image->height);
    657 
    658 }
    659 
    660 void
    661 BWDownAction(Widget w, _X_UNUSED XEvent *event,
    662              _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    663 {
    664     BWDown(w);
    665 }
    666 
    667 void
    668 BWDown(Widget w)
    669 {
    670     BitmapWidget BW = (BitmapWidget) w;
    671     register Position x, y;
    672     bit first, down, up=0;
    673     Position from_x, from_y, to_x, to_y;
    674 
    675     if (BWQueryMarked(w)) {
    676 	from_x = BW->bitmap.mark.from_x;
    677 	from_y = BW->bitmap.mark.from_y;
    678 	to_x = BW->bitmap.mark.to_x;
    679 	to_y = BW->bitmap.mark.to_y;
    680     }
    681     else {
    682 	from_x = 0;
    683 	from_y = 0;
    684 	to_x = BW->bitmap.width - 1;
    685 	to_y = BW->bitmap.height - 1;
    686     }
    687 
    688     if ((to_y - from_y) == 0)
    689 	return;
    690 
    691     for(x = from_x; x <= to_x; x++) {
    692 	first = down = GetBit(BW->bitmap.image, x, from_y);
    693 	for(y = from_y + 1; y <= to_y; y++) {
    694 	    up = GetBit(BW->bitmap.image, x, y);
    695 	    if (down != up)
    696 		InvertPoint(BW, x, y);
    697 	    down = up;
    698 	}
    699 	if(first != up)
    700 	    InvertPoint(BW, x, from_y);
    701     }
    702 
    703     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    704 	&&
    705 	!BWQueryMarked(w))
    706 	BWSetHotSpot(w,
    707 		     BW->bitmap.hot.x,
    708 		     (BW->bitmap.hot.y + 1) % BW->bitmap.image->height);
    709 }
    710 
    711 void
    712 BWLeftAction(Widget w, _X_UNUSED XEvent *event,
    713              _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    714 {
    715     BWLeft(w);
    716 }
    717 
    718 void
    719 BWLeft(Widget w)
    720 {
    721     BitmapWidget BW = (BitmapWidget) w;
    722     register Position x, y;
    723     bit first, left, right=0;
    724     Position from_x, from_y, to_x, to_y;
    725 
    726     if (BWQueryMarked(w)) {
    727 	from_x = BW->bitmap.mark.from_x;
    728 	from_y = BW->bitmap.mark.from_y;
    729 	to_x = BW->bitmap.mark.to_x;
    730 	to_y = BW->bitmap.mark.to_y;
    731     }
    732     else {
    733 	from_x = 0;
    734 	from_y = 0;
    735 	to_x = BW->bitmap.width - 1;
    736 	to_y = BW->bitmap.height - 1;
    737     }
    738 
    739     if ((to_x - from_x) == 0)
    740 	return;
    741 
    742     for(y = from_y; y <= to_y; y++) {
    743 	first = left = GetBit(BW->bitmap.image, to_x, y);
    744 	for(x = to_x - 1; x >= from_x; x--) {
    745 	    right = GetBit(BW->bitmap.image, x, y);
    746 	    if (left != right)
    747 		InvertPoint(BW, x, y);
    748 	    left = right;
    749 	}
    750 	if(first != right)
    751 	    InvertPoint(BW, to_x, y);
    752     }
    753 
    754     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    755 	&&
    756 	!BWQueryMarked(w))
    757 	BWSetHotSpot(w,
    758 		     (BW->bitmap.hot.x - 1 + BW->bitmap.image->width) %
    759 		     BW->bitmap.image->width,
    760 		     BW->bitmap.hot.y);
    761 }
    762 
    763 void
    764 BWRightAction(Widget w, _X_UNUSED XEvent *event,
    765               _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    766 {
    767     BWRight(w);
    768 }
    769 
    770 void
    771 BWRight(Widget w)
    772 {
    773     BitmapWidget BW = (BitmapWidget) w;
    774     register Position x, y;
    775     bit first, right, left=0;
    776     Position from_x, from_y, to_x, to_y;
    777 
    778     if (BWQueryMarked(w)) {
    779 	from_x = BW->bitmap.mark.from_x;
    780 	from_y = BW->bitmap.mark.from_y;
    781 	to_x = BW->bitmap.mark.to_x;
    782 	to_y = BW->bitmap.mark.to_y;
    783     }
    784     else {
    785 	from_x = 0;
    786 	from_y = 0;
    787 	to_x = BW->bitmap.width - 1;
    788 	to_y = BW->bitmap.height - 1;
    789     }
    790 
    791     if ((to_x - from_x) == 0)
    792 	return;
    793 
    794     for(y = from_y; y <= to_y; y++) {
    795 	first = right = GetBit(BW->bitmap.image, from_x, y);
    796 	for(x = from_x + 1; x <= to_x; x++) {
    797 	    left = GetBit(BW->bitmap.image, x, y);
    798 	    if (right != left)
    799 		InvertPoint(BW, x, y);
    800 	    right = left;
    801 	}
    802 	if(first != left)
    803 	    InvertPoint(BW, from_x, y);
    804     }
    805 
    806     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    807 	&&
    808 	!BWQueryMarked(w))
    809 	BWSetHotSpot(w,
    810 		     (BW->bitmap.hot.x + 1) % BW->bitmap.image->width,
    811 		     BW->bitmap.hot.y);
    812 }
    813 
    814 /* void TransferImageData(); */
    815 
    816 void
    817 BWFoldAction(Widget w, _X_UNUSED XEvent *event,
    818        _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    819 {
    820     BWFold(w);
    821 }
    822 
    823 void
    824 BWFold(Widget w)
    825 {
    826     BitmapWidget BW = (BitmapWidget) w;
    827     Position x, y, new_x, new_y;
    828     Dimension horiz, vert;
    829     char *storage_data;
    830     XImage *storage;
    831 
    832     storage_data = CreateCleanData(Length(BW->bitmap.image->width,
    833 					  BW->bitmap.image->height));
    834 
    835     storage = CreateBitmapImage(BW, storage_data,
    836 				(Dimension) BW->bitmap.image->width,
    837 				(Dimension) BW->bitmap.image->height);
    838 
    839     TransferImageData(BW->bitmap.image, storage);
    840 
    841     BW->bitmap.fold ^= True;
    842     horiz = (BW->bitmap.image->width + BW->bitmap.fold) / 2;
    843     vert = (BW->bitmap.image->height + BW->bitmap.fold) / 2;
    844 
    845     for (x = 0; x < BW->bitmap.image->width; x++)
    846 	for (y = 0; y < BW->bitmap.image->height; y++) {
    847 	    new_x = (int)(x + horiz) % (int)BW->bitmap.image->width;
    848 	    new_y = (int)(y + vert) % (int)BW->bitmap.image->height;
    849 	    if(GetBit(BW->bitmap.image, new_x, new_y) !=
    850 	       GetBit(storage, x, y))
    851 		InvertPoint(BW, new_x, new_y);
    852 	}
    853 
    854     DestroyBitmapImage(&storage);
    855 
    856     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
    857       BWSetHotSpot(w,
    858 		   (Position)
    859 		   ((int)(BW->bitmap.hot.x+horiz)
    860 		    %(int)BW->bitmap.image->width),
    861 		   (Position)
    862 		   ((int)(BW->bitmap.hot.y+vert)
    863 		    %(int)BW->bitmap.image->height)
    864 		   );
    865 }
    866 
    867 
    868 void
    869 BWClearAction(Widget w, _X_UNUSED XEvent *event,
    870               _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    871 {
    872     BWClear(w);
    873 }
    874 
    875 void
    876 BWClear(Widget w)
    877 {
    878     BitmapWidget BW = (BitmapWidget) w;
    879     register Position x, y;
    880     int i, length;
    881 
    882     length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
    883 
    884     for (x = 0; x < BW->bitmap.image->width; x++)
    885 	for (y = 0; y < BW->bitmap.image->height; y++)
    886 	    if (GetBit(BW->bitmap.image, x, y))
    887 		DrawSquare(BW, x, y);
    888 
    889     for (i = 0; i < length; i++)
    890 	BW->bitmap.image->data[i] = 0;
    891 
    892 }
    893 
    894 void
    895 BWSetAction(Widget w, _X_UNUSED XEvent *event,
    896             _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    897 {
    898     BWSet(w);
    899 }
    900 
    901 void
    902 BWSet(Widget w)
    903 {
    904     BitmapWidget BW = (BitmapWidget) w;
    905     register Position x, y;
    906     int i, length;
    907 
    908     length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
    909 
    910     for (x = 0; x < BW->bitmap.image->width; x++)
    911 	for (y = 0; y < BW->bitmap.image->height; y++)
    912 	    if (!GetBit(BW->bitmap.image, x, y))
    913 		DrawSquare(BW, x, y);
    914 
    915     for (i = 0; i < length; i++)
    916 	BW->bitmap.image->data[i] = (char)255;
    917 
    918 }
    919 
    920 void
    921 BWRedraw(Widget w, _X_UNUSED XEvent *event,
    922          _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    923 {
    924     BitmapWidget BW = (BitmapWidget) w;
    925 
    926     XClearArea(XtDisplay(BW), XtWindow(BW),
    927 	       0, 0, BW->core.width, BW->core.height,
    928 	       True);
    929 }
    930 
    931 void
    932 BWInvertAction(Widget w, _X_UNUSED XEvent *event,
    933                _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    934 {
    935     BWInvert(w);
    936 }
    937 
    938 void
    939 BWInvert(Widget w)
    940 {
    941     BitmapWidget BW = (BitmapWidget) w;
    942     int i, length;
    943 
    944     length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
    945 
    946     XFillRectangle(XtDisplay(BW), XtWindow(BW),
    947 		   BW->bitmap.drawing_gc,
    948 		   InWindowX(BW, 0), InWindowY(BW, 0),
    949 		   InWindowX(BW, BW->bitmap.image->width) - InWindowX(BW, 0),
    950 		   InWindowY(BW, BW->bitmap.image->height) - InWindowY(BW, 0));
    951 
    952     for (i = 0; i < length; i++)
    953 	BW->bitmap.image->data[i] ^= 255;
    954 }
    955 
    956 void
    957 BWFlipHorizAction(Widget w, _X_UNUSED XEvent *event,
    958                   _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
    959 {
    960     BWFlipHoriz(w);
    961 }
    962 
    963 void
    964 BWFlipHoriz(Widget w)
    965 {
    966     BitmapWidget BW = (BitmapWidget) w;
    967     register Position x, y;
    968     Position from_x, from_y, to_x, to_y;
    969     float half;
    970 
    971     if (BWQueryMarked(w)) {
    972 	from_x = BW->bitmap.mark.from_x;
    973 	from_y = BW->bitmap.mark.from_y;
    974 	to_x = BW->bitmap.mark.to_x;
    975 	to_y = BW->bitmap.mark.to_y;
    976     }
    977     else {
    978 	from_x = 0;
    979 	from_y = 0;
    980 	to_x = BW->bitmap.width - 1;
    981 	to_y = BW->bitmap.height - 1;
    982     }
    983     half = (float) (to_y - from_y) / 2.0 + 0.5;
    984 
    985     if (half == 0.0)
    986 	return;
    987 
    988     for (x = from_x; x <= to_x; x++)
    989 	for (y = 0; y <  half; y++)
    990 	    if (GetBit(BW->bitmap.image, x, from_y + y) !=
    991 		GetBit(BW->bitmap.image, x, to_y - y)) {
    992 		InvertPoint(BW, x, from_y + y);
    993 		InvertPoint(BW, x, to_y - y);
    994 	    }
    995 
    996     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
    997 	&&
    998 	!BWQueryMarked(w))
    999 	BWSetHotSpot(w,
   1000 		     BW->bitmap.hot.x,
   1001 		     BW->bitmap.image->height - 1 - BW->bitmap.hot.y);
   1002 }
   1003 
   1004 void
   1005 BWFlipVertAction(Widget w, _X_UNUSED XEvent *event,
   1006                  _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
   1007 {
   1008     BWFlipVert(w);
   1009 }
   1010 
   1011 void
   1012 BWFlipVert(Widget w)
   1013 {
   1014     BitmapWidget BW = (BitmapWidget) w;
   1015     register Position x, y;
   1016     Position from_x, from_y, to_x, to_y;
   1017     float half;
   1018 
   1019     if (BWQueryMarked(w)) {
   1020 	from_x = BW->bitmap.mark.from_x;
   1021 	from_y = BW->bitmap.mark.from_y;
   1022 	to_x = BW->bitmap.mark.to_x;
   1023 	to_y = BW->bitmap.mark.to_y;
   1024     }
   1025     else {
   1026 	from_x = 0;
   1027 	from_y = 0;
   1028 	to_x = BW->bitmap.width - 1;
   1029 	to_y = BW->bitmap.height - 1;
   1030     }
   1031     half = (float) (to_x - from_x) / 2.0 + 0.5;
   1032 
   1033     if (half == 0)
   1034 	return;
   1035 
   1036     for (y = from_y; y <= to_y; y++)
   1037 	for (x = 0; x < half; x++)
   1038 	    if (GetBit(BW->bitmap.image, from_x + x, y) !=
   1039 		GetBit(BW->bitmap.image, to_x - x, y)) {
   1040 		InvertPoint(BW, from_x + x, y);
   1041 		InvertPoint(BW, to_x - x, y);
   1042 	    }
   1043 
   1044     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
   1045 	&&
   1046 	!BWQueryMarked(w))
   1047 	BWSetHotSpot(w,
   1048 		     BW->bitmap.image->width - 1 - BW->bitmap.hot.x,
   1049 		     BW->bitmap.hot.y);
   1050 }
   1051 
   1052 
   1053 void
   1054 BWRotateRightAction(Widget w, _X_UNUSED XEvent *event,
   1055                     _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
   1056 {
   1057     BWRotateRight(w);
   1058 }
   1059 
   1060 void
   1061 BWRotateRight(Widget w)
   1062 {
   1063     BitmapWidget BW = (BitmapWidget) w;
   1064     Position x, y, delta, shift, tmp;
   1065     Position half_width, half_height;
   1066     XPoint hot;
   1067     bit quad1, quad2, quad3, quad4;
   1068     Position from_x, from_y, to_x, to_y;
   1069 
   1070     if (BWQueryMarked(w)) {
   1071 	from_x = BW->bitmap.mark.from_x;
   1072 	from_y = BW->bitmap.mark.from_y;
   1073 	to_x = BW->bitmap.mark.to_x;
   1074 	to_y = BW->bitmap.mark.to_y;
   1075     }
   1076     else {
   1077 	from_x = 0;
   1078 	from_y = 0;
   1079 	to_x = BW->bitmap.width - 1;
   1080 	to_y = BW->bitmap.height - 1;
   1081     }
   1082 
   1083     half_width = floor((to_x - from_x) / 2.0 + 0.5);
   1084     half_height = floor((to_y - from_y ) / 2.0 + 0.5);
   1085     shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
   1086     delta = min((Position) half_width, (Position) half_height) - shift;
   1087 
   1088     for (x = 0; x <= delta; x++) {
   1089 	for (y = 1 - shift; y <= delta; y++) {
   1090 	    quad1 = GetBit(BW->bitmap.image,
   1091 			   from_x + (Position)half_width + x,
   1092 			   from_y + (Position)half_height + y);
   1093 	    quad2 = GetBit(BW->bitmap.image,
   1094 			   from_x + (Position)half_width + y,
   1095 			   from_y + (Position)half_height - shift - x);
   1096 	    quad3 = GetBit(BW->bitmap.image,
   1097 			   from_x + (Position)half_width - shift - x,
   1098 			   from_y + (Position)half_height - shift - y);
   1099 	    quad4 = GetBit(BW->bitmap.image,
   1100 			   from_x + (Position)half_width - shift - y,
   1101 			   from_y + (Position)half_height + x);
   1102 
   1103 	    if (quad1 != quad2)
   1104 		InvertPoint(BW,
   1105 			    from_x + (Position)half_width + x,
   1106 			    from_y + (Position)half_height + y);
   1107 	    if (quad2 != quad3)
   1108 		InvertPoint(BW,
   1109 			    from_x + (Position)half_width + y,
   1110 			    from_y + (Position)half_height - shift - x);
   1111 	    if (quad3 != quad4)
   1112 		InvertPoint(BW,
   1113 			    from_x + (Position)half_width - shift - x,
   1114 			    from_y + (Position)half_height - shift - y);
   1115 	    if (quad4 != quad1)
   1116 		InvertPoint(BW,
   1117 			    from_x + (Position)half_width - shift - y,
   1118 			    from_y + (Position)half_height + x);
   1119 	}
   1120     }
   1121 
   1122     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
   1123 	&&
   1124 	!BWQueryMarked(w)) {
   1125 	hot.x = BW->bitmap.hot.x - half_width;
   1126 	hot.y = BW->bitmap.hot.y - half_height;
   1127 	if (hot.x >= 0) hot.x += shift;
   1128 	if (hot.y >= 0) hot.y += shift;
   1129 	tmp = hot.x;
   1130 	hot.x = - hot.y;
   1131 	hot.y = tmp;
   1132 	if (hot.x > 0) hot.x -= shift;
   1133 	if (hot.y > 0) hot.y -= shift;
   1134 	hot.x += half_width;
   1135 	hot.y += half_height;
   1136 	if (QueryInBitmap(BW, hot.x, hot.y))
   1137 	    BWSetHotSpot(w, hot.x, hot.y);
   1138     }
   1139 
   1140 }
   1141 
   1142 void
   1143 BWRotateLeftAction(Widget w, _X_UNUSED XEvent *event,
   1144                     _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
   1145 {
   1146     BWRotateLeft(w);
   1147 }
   1148 
   1149 void
   1150 BWRotateLeft(Widget w)
   1151 {
   1152     BitmapWidget BW = (BitmapWidget) w;
   1153     Position x, y,delta, shift, tmp;
   1154     Position half_width, half_height;
   1155     XPoint hot;
   1156     bit quad1, quad2, quad3, quad4;
   1157     Position from_x, from_y, to_x, to_y;
   1158 
   1159     if (BWQueryMarked(w)) {
   1160 	from_x = BW->bitmap.mark.from_x;
   1161 	from_y = BW->bitmap.mark.from_y;
   1162 	to_x = BW->bitmap.mark.to_x;
   1163 	to_y = BW->bitmap.mark.to_y;
   1164     }
   1165     else {
   1166 	from_x = 0;
   1167 	from_y = 0;
   1168 	to_x = BW->bitmap.width - 1;
   1169 	to_y = BW->bitmap.height - 1;
   1170     }
   1171 
   1172     half_width = floor((to_x - from_x) / 2.0 + 0.5);
   1173     half_height = floor((to_y - from_y ) / 2.0 + 0.5);
   1174     shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
   1175     delta = min((Position) half_width, (Position) half_height) - shift;
   1176 
   1177     for (x = 0; x <= delta; x++) {
   1178 	for (y = 1 - shift; y <= delta; y++) {
   1179 	    quad1 = GetBit(BW->bitmap.image,
   1180 			   from_x + (Position)half_width + x,
   1181 			   from_y + (Position)half_height + y);
   1182 	    quad2 = GetBit(BW->bitmap.image,
   1183 			   from_x + (Position)half_width + y,
   1184 			   from_y + (Position)half_height - shift - x);
   1185 	    quad3 = GetBit(BW->bitmap.image,
   1186 			   from_x + (Position)half_width - shift - x,
   1187 			   from_y + (Position)half_height - shift - y);
   1188 	    quad4 = GetBit(BW->bitmap.image,
   1189 			   from_x + (Position)half_width - shift - y,
   1190 			   from_y + (Position)half_height + x);
   1191 
   1192 	    if (quad1 != quad4)
   1193 		InvertPoint(BW,
   1194 			    from_x + (Position)half_width + x,
   1195 			    from_y + (Position)half_height + y);
   1196 	    if (quad2 != quad1)
   1197 		InvertPoint(BW,
   1198 			    from_x + (Position)half_width + y,
   1199 			    from_y + (Position)half_height - shift - x);
   1200 	    if (quad3 != quad2)
   1201 		InvertPoint(BW,
   1202 			    from_x + (Position)half_width - shift - x,
   1203 			    from_y + (Position)half_height - shift - y);
   1204 	    if (quad4 != quad3)
   1205 		InvertPoint(BW,
   1206 			    from_x + (Position)half_width - shift - y,
   1207 			    from_y + (Position)half_height + x);
   1208 	}
   1209     }
   1210 
   1211     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
   1212 	&&
   1213 	!BWQueryMarked(w)) {
   1214 	hot.x = BW->bitmap.hot.x - half_width;
   1215 	hot.y = BW->bitmap.hot.y - half_height;
   1216 	if (hot.x >= 0) hot.x += shift;
   1217 	if (hot.y >= 0) hot.y += shift;
   1218 	tmp = hot.x;
   1219 	hot.x = hot.y;
   1220 	hot.y = - tmp;
   1221 	if (hot.x > 0) hot.x -= shift;
   1222 	if (hot.y > 0) hot.y -= shift;
   1223 	hot.x += half_width;
   1224 	hot.y += half_height;
   1225 	if (QueryInBitmap(BW, hot.x, hot.y))
   1226 	    BWSetHotSpot(w, hot.x, hot.y);
   1227     }
   1228 }
   1229 
   1230 
   1231 void
   1232 CopyImageData(XImage *source, XImage *destination,
   1233 	      Position from_x, Position from_y,
   1234 	      Position to_x, Position to_y,
   1235 	      Position at_x, Position at_y)
   1236 {
   1237     Position x, y, delta_x, delta_y;
   1238 
   1239     delta_x = to_x - from_x + 1;
   1240     delta_y = to_y - from_y + 1;
   1241 
   1242     for (x = 0; x < delta_x; x++)
   1243 	for (y = 0; y < delta_y; y++)
   1244 	    if (GetBit(source, from_x + x, from_y + y))
   1245 		SetBit(destination, at_x + x, at_y + y);
   1246 	    else
   1247 		ClearBit(destination, at_x + x, at_y + y);
   1248 }
   1249 
   1250 XImage *
   1251 ConvertToBitmapImage(BitmapWidget BW, XImage *image)
   1252 {
   1253     XImage *bitmap_image;
   1254     char   *data;
   1255     Position x, y;
   1256 
   1257     data = CreateCleanData(Length(image->width, image->height));
   1258     bitmap_image = CreateBitmapImage(BW, data,
   1259 				     (Dimension) image->width,
   1260 				     (Dimension) image->height);
   1261 
   1262     for (x = 0; x < min(image->width, bitmap_image->width); x++)
   1263 	for (y = 0; y < min(image->height, bitmap_image->height); y++)
   1264 	    if ((XGetPixel(image, x, y) != 0) != GetBit(bitmap_image, x, y))
   1265 		InvertBit(bitmap_image, x, y);
   1266 
   1267     return bitmap_image;
   1268 }
   1269 
   1270 void
   1271 TransferImageData(XImage *source, XImage *destination)
   1272 {
   1273     Position x, y;
   1274 
   1275     for (x = 0; x < min(source->width, destination->width); x++)
   1276 	for (y = 0; y < min(source->height, destination->height); y++)
   1277 	    if (GetBit(source, x, y) != GetBit(destination, x, y))
   1278 		InvertBit(destination, x, y);
   1279 }
   1280 
   1281 void
   1282 BWStore(Widget w)
   1283 {
   1284     BitmapWidget BW = (BitmapWidget) w;
   1285     Dimension width, height;
   1286     char *storage_data;
   1287 
   1288     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
   1289 
   1290 	DestroyBitmapImage(&BW->bitmap.storage);
   1291 
   1292 	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
   1293 	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
   1294 
   1295 	storage_data = CreateCleanData(Length(width, height));
   1296 
   1297 	BW->bitmap.storage = CreateBitmapImage(BW,
   1298 					       storage_data,
   1299 					       width, height);
   1300 
   1301 	CopyImageData(BW->bitmap.image, BW->bitmap.storage,
   1302 		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
   1303 		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
   1304 		      0, 0);
   1305     }
   1306 }
   1307 
   1308 void
   1309 BWClearMarked(Widget w)
   1310 {
   1311     BitmapWidget BW = (BitmapWidget) w;
   1312 
   1313     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
   1314 	BWDrawFilledRectangle(w,
   1315 			      BW->bitmap.mark.from_x,
   1316 			      BW->bitmap.mark.from_y,
   1317 			      BW->bitmap.mark.to_x,
   1318 			      BW->bitmap.mark.to_y,
   1319 			      Clear);
   1320 }
   1321 
   1322 
   1323 void
   1324 BWDragMarked(Widget w, Position at_x, Position at_y)
   1325 {
   1326     BitmapWidget BW = (BitmapWidget) w;
   1327 
   1328     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
   1329 	BWDrawRectangle(w,
   1330 			at_x, at_y,
   1331 			at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
   1332 			at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y,
   1333 			Highlight);
   1334 }
   1335 
   1336 void
   1337 BWDragStored(Widget w, Position at_x, Position at_y)
   1338 {
   1339     BitmapWidget BW = (BitmapWidget) w;
   1340 
   1341     if (BW->bitmap.storage)
   1342 	BWDrawRectangle(w,
   1343 			at_x, at_y,
   1344 			at_x + BW->bitmap.storage->width - 1,
   1345 			at_y + BW->bitmap.storage->height - 1,
   1346 			Highlight);
   1347 }
   1348 
   1349 static void
   1350 DrawImageData(BitmapWidget BW, XImage *image,
   1351 	      Position at_x, Position at_y, int value)
   1352 {
   1353     Position x, y;
   1354     Boolean  C, S, I, H;
   1355     bit      A, B;
   1356 
   1357     C = value == Clear;
   1358     S = value == Set;
   1359     I = value == Invert;
   1360     H = value == Highlight;
   1361 
   1362     for (x = 0; x < image->width; x++)
   1363 	for (y = 0; y < image->height; y++) {
   1364 	    A = GetBit(image, x, y);
   1365 	    B = GetBit(BW->bitmap.image, at_x + x, at_y + y);
   1366 	    if ((A & C) | ((A | B) & S) | ((A ^ B) & I) | ((A | B) & H))
   1367 		value = (A & H) ? Highlight : Set;
   1368 	    else
   1369 		value = Clear;
   1370 	    BWDrawPoint((Widget) BW,
   1371 			 at_x + x, at_y + y,
   1372 			 value);
   1373 	}
   1374 }
   1375 
   1376 void
   1377 BWRestore(Widget w, Position at_x, Position at_y, int value)
   1378 {
   1379     BitmapWidget BW = (BitmapWidget) w;
   1380 
   1381     if (BW->bitmap.storage) {
   1382       DrawImageData(BW, BW->bitmap.storage, at_x, at_y, value);
   1383       /*DestroyBitmapImage(&BW->bitmap.storage);*/
   1384     }
   1385 }
   1386 
   1387 void
   1388 BWCopy(Widget w, Position at_x, Position at_y, int value)
   1389 {
   1390     BitmapWidget BW = (BitmapWidget) w;
   1391     XImage *storage;
   1392     char *storage_data;
   1393     Dimension width, height;
   1394 
   1395     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
   1396 
   1397 	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
   1398 	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
   1399 
   1400 	storage_data = CreateCleanData(Length(width, height));
   1401 
   1402 	storage = CreateBitmapImage(BW, storage_data, width, height);
   1403 
   1404 	CopyImageData(BW->bitmap.image, storage,
   1405 		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
   1406 		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
   1407 		      0, 0);
   1408 
   1409 	DrawImageData(BW, storage, at_x, at_y, value);
   1410 
   1411 	DestroyBitmapImage(&storage);
   1412     }
   1413 }
   1414 
   1415 /* void BWMark(); */
   1416 
   1417 void
   1418 BWMove(Widget w, Position at_x, Position at_y, int value)
   1419 {
   1420     BitmapWidget BW = (BitmapWidget) w;
   1421     XImage *storage;
   1422     char *storage_data;
   1423     Dimension width, height;
   1424 
   1425     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
   1426 
   1427 	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
   1428 	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
   1429 
   1430 	storage_data = CreateCleanData(Length(width, height));
   1431 
   1432 	storage = CreateBitmapImage(BW, storage_data, width, height);
   1433 
   1434 	CopyImageData(BW->bitmap.image, storage,
   1435 		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
   1436 		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
   1437 		      0, 0);
   1438 
   1439 	BWDrawFilledRectangle(w,
   1440 			      BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
   1441 			      BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
   1442 			      Clear);
   1443 
   1444 	DrawImageData(BW, storage, at_x, at_y, value);
   1445 
   1446 	BWMark(w, at_x, at_y,
   1447 	     at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
   1448 	     at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y);
   1449 
   1450 	DestroyBitmapImage(&storage);
   1451     }
   1452 }
   1453 
   1454 void
   1455 BWRedrawMark(Widget w)
   1456 {
   1457     BitmapWidget BW = (BitmapWidget) w;
   1458 
   1459     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
   1460 	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
   1461 		       InWindowX(BW, BW->bitmap.mark.from_x),
   1462 		       InWindowY(BW, BW->bitmap.mark.from_y),
   1463 		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
   1464 		       InWindowX(BW, BW->bitmap.mark.from_x),
   1465 		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
   1466 		       InWindowY(BW, BW->bitmap.mark.from_y));
   1467 }
   1468 
   1469 void
   1470 BWStoreToBufferAction(Widget w, _X_UNUSED XEvent *event,
   1471                       _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
   1472 {
   1473     BWStoreToBuffer(w);
   1474 }
   1475 
   1476 void
   1477 BWStoreToBuffer(Widget w)
   1478 {
   1479     BitmapWidget BW = (BitmapWidget) w;
   1480 
   1481     memmove( BW->bitmap.buffer->data, BW->bitmap.image->data,
   1482 	  Length(BW->bitmap.image->width, BW->bitmap.image->height));
   1483 
   1484     BW->bitmap.buffer_hot = BW->bitmap.hot;
   1485     BW->bitmap.buffer_mark = BW->bitmap.mark;
   1486 }
   1487 
   1488 void
   1489 BWUnmark(Widget w)
   1490 {
   1491     BitmapWidget BW = (BitmapWidget) w;
   1492 
   1493     BW->bitmap.buffer_mark = BW->bitmap.mark;
   1494 
   1495     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
   1496 	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
   1497 		       InWindowX(BW, BW->bitmap.mark.from_x),
   1498 		       InWindowY(BW, BW->bitmap.mark.from_y),
   1499 		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
   1500 		       InWindowX(BW, BW->bitmap.mark.from_x),
   1501 		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
   1502 		       InWindowY(BW, BW->bitmap.mark.from_y));
   1503 
   1504 	BW->bitmap.mark.from_x = BW->bitmap.mark.from_y = NotSet;
   1505 	BW->bitmap.mark.to_x = BW->bitmap.mark.to_y = NotSet;
   1506     }
   1507 }
   1508 
   1509 void
   1510 BWMark(Widget w, Position from_x, Position from_y,
   1511        Position to_x, Position to_y)
   1512 {
   1513     BitmapWidget BW = (BitmapWidget) w;
   1514 
   1515     BWUnmark(w);
   1516 
   1517     if (QuerySet(from_x, from_y)) {
   1518 	if ((from_x == to_x) && (from_y == to_y)) {
   1519 	    /*
   1520 	      BW->bitmap.mark.from_x = 0;
   1521 	      BW->bitmap.mark.from_y = 0;
   1522 	      BW->bitmap.mark.to_x = BW->bitmap.image->width - 1;
   1523 	      BW->bitmap.mark.to_y = BW->bitmap.image->height - 1;
   1524 	      */
   1525 	    return;
   1526 	}
   1527 	else {
   1528 	    QuerySwap(from_x, to_x);
   1529 	    QuerySwap(from_y, to_y);
   1530 	    from_x = max(0, from_x);
   1531 	    from_y = max(0, from_y);
   1532 	    to_x = min(BW->bitmap.image->width - 1, to_x);
   1533 	    to_y = min(BW->bitmap.image->height - 1, to_y);
   1534 
   1535 	    BW->bitmap.mark.from_x = from_x;
   1536 	    BW->bitmap.mark.from_y = from_y;
   1537 	    BW->bitmap.mark.to_x = to_x;
   1538 	    BW->bitmap.mark.to_y = to_y;
   1539 	}
   1540 
   1541 	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
   1542 		       InWindowX(BW, BW->bitmap.mark.from_x),
   1543 		       InWindowY(BW, BW->bitmap.mark.from_y),
   1544 		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
   1545 		       InWindowX(BW, BW->bitmap.mark.from_x),
   1546 		       InWindowY(BW, BW->bitmap.mark.to_y +1) -
   1547 		       InWindowY(BW, BW->bitmap.mark.from_y));
   1548     }
   1549 }
   1550 
   1551 void
   1552 BWMarkAll(Widget w)
   1553 {
   1554   BitmapWidget BW = (BitmapWidget) w;
   1555 
   1556   BWMark(w, 0, 0, BW->bitmap.image->width - 1, BW->bitmap.image->height - 1);
   1557 }
   1558 
   1559 void
   1560 BWUndoAction(Widget w, _X_UNUSED XEvent *event,
   1561              _X_UNUSED String *params, _X_UNUSED Cardinal *num_params)
   1562 {
   1563     BWUndo(w);
   1564 }
   1565 
   1566 void
   1567 BWUndo(Widget w)
   1568 {
   1569     BitmapWidget BW = (BitmapWidget) w;
   1570     Position x, y;
   1571     char *tmp_data;
   1572     XPoint tmp_hot;
   1573     BWArea tmp_mark;
   1574 
   1575     tmp_data = BW->bitmap.image->data;
   1576     BW->bitmap.image->data = BW->bitmap.buffer->data;
   1577     BW->bitmap.buffer->data = tmp_data;
   1578 
   1579     tmp_hot = BW->bitmap.hot;
   1580     tmp_mark = BW->bitmap.mark;
   1581 
   1582     for (x = 0; x < BW->bitmap.image->width; x++)
   1583 	for (y = 0; y < BW->bitmap.image->height; y++)
   1584 	 if (GetBit(BW->bitmap.image, x, y) != GetBit(BW->bitmap.buffer, x, y))
   1585 	     DrawSquare(BW, x, y);
   1586 
   1587     BWSetHotSpot(w, BW->bitmap.buffer_hot.x, BW->bitmap.buffer_hot.y);
   1588 /*
   1589     BWMark(w, BW->bitmap.buffer_mark.from_x, BW->bitmap.buffer_mark.from_y,
   1590 	   BW->bitmap.buffer_mark.to_x, BW->bitmap.buffer_mark.to_y);
   1591 */
   1592     BW->bitmap.buffer_hot = tmp_hot;
   1593     BW->bitmap.buffer_mark= tmp_mark;
   1594 
   1595 }
   1596 
   1597 void
   1598 BWHighlightAxes(Widget w)
   1599 {
   1600     BitmapWidget BW = (BitmapWidget) w;
   1601 
   1602     XDrawLine(XtDisplay(BW), XtWindow(BW),
   1603 	      BW->bitmap.axes_gc,
   1604 	      InWindowX(BW, 0),
   1605 	      InWindowY(BW, 0),
   1606 	      InWindowX(BW, BW->bitmap.width),
   1607 	      InWindowY(BW, BW->bitmap.height));
   1608     XDrawLine(XtDisplay(BW), XtWindow(BW),
   1609 	      BW->bitmap.axes_gc,
   1610 	      InWindowX(BW, BW->bitmap.width),
   1611 	      InWindowY(BW, 0),
   1612 	      InWindowX(BW, 0),
   1613 	      InWindowY(BW, BW->bitmap.height));
   1614     XDrawLine(XtDisplay(BW), XtWindow(BW),
   1615 	      BW->bitmap.axes_gc,
   1616 	      InWindowX(BW, 0),
   1617 	      InWindowY(BW, (float)BW->bitmap.height / 2.0),
   1618 	      InWindowX(BW, BW->bitmap.width),
   1619 	      InWindowY(BW, (float)BW->bitmap.height / 2.0));
   1620     XDrawLine(XtDisplay(BW), XtWindow(BW),
   1621 	      BW->bitmap.axes_gc,
   1622 	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
   1623 	      InWindowY(BW, 0),
   1624 	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
   1625 	      InWindowY(BW, BW->bitmap.height));
   1626 }
   1627 
   1628 typedef struct {
   1629     Position *x, *y;
   1630     Dimension *width, *height;
   1631 } Table;
   1632 
   1633 XImage *
   1634 ScaleBitmapImage(BitmapWidget BW, XImage *src,
   1635 		 double scale_x, double scale_y)
   1636 {
   1637     char *data;
   1638     XImage *dst;
   1639     Table table;
   1640     Position x, y, w, h;
   1641     Dimension width, height;
   1642     bit pixel;
   1643 
   1644     width = max(rint(scale_x * src->width), 1);
   1645     height = max(rint(scale_y * src->height), 1);
   1646 
   1647     data = CreateCleanData(Length(width, height));
   1648     dst = CreateBitmapImage(BW, data, width, height);
   1649 
   1650     /*
   1651      * It would be nice to check if width or height < 1.0 and
   1652      * average the skipped pixels. But, it is slow as it is now.
   1653      */
   1654     if (scale_x == 1.0 && scale_y == 1.0)
   1655 	memmove( dst->data, src->data, Length(width, height));
   1656     else {
   1657 	table.x = (Position *) XtMalloc(sizeof(Position) * src->width);
   1658 	table.y = (Position *) XtMalloc(sizeof(Position) * src->height);
   1659 	table.width = (Dimension *) XtMalloc(sizeof(Dimension) * src->width);
   1660 	table.height = (Dimension *) XtMalloc(sizeof(Dimension) * src->height);
   1661 
   1662 	for (x = 0; x < src->width; x++) {
   1663 	    table.x[x] = rint(scale_x * x);
   1664 	    table.width[x] = rint(scale_x * (x + 1)) - rint(scale_x * x);
   1665 	}
   1666 	for (y = 0; y < src->height; y++) {
   1667 	    table.y[y] = rint(scale_y * y);
   1668 	    table.height[y] = rint(scale_y * (y + 1)) - rint(scale_y * y);
   1669 	}
   1670 
   1671 	for (x = 0; x < src->width; x++)
   1672 	    for (y = 0; y < src->height; y++) {
   1673 	        pixel = GetBit(src, x, y);
   1674 		for (w = 0; (int)w < (int)table.width[x]; w++)
   1675 		    for (h = 0; (int)h < (int)table.height[y]; h++)
   1676 			if (pixel) SetBit(dst,
   1677 					table.x[x] + w,
   1678 					table.y[y] + h);
   1679 	    }
   1680 
   1681 	XtFree((char *)table.x);
   1682 	XtFree((char *)table.y);
   1683 	XtFree((char *)table.width);
   1684 	XtFree((char *)table.height);
   1685     }
   1686 
   1687     return (dst);
   1688 }
   1689 
   1690 /*****************************************************************************/
   1691