Annotation of researchv9/X11/src/X.V11R1/clients/bitmap/bitmap.c, revision 1.1.1.1

1.1       root        1: #ifndef lint
                      2: static char *rcsid_bitmap_c = "$Header: bitmap.c,v 1.12 87/09/11 23:19:52 sun Exp $";
                      3: #endif
                      4: 
                      5: #include <errno.h>
                      6: #include <stdio.h>
                      7: #include <X11/Xlib.h>
                      8: #include <X11/Xutil.h>
                      9: #include <X11/cursorfont.h>  
                     10: #include <sys/types.h>
                     11: #include <strings.h>
                     12: 
                     13: #define TOP_MARGIN 10
                     14: #define LEFT_MARGIN 10
                     15: #define BOTTOM_MARGIN 10
                     16: #define AROUND_RASTER_MARGIN 20
                     17: #define GRID_TO_COMMAND_MARGIN 5
                     18: #define RIGHT_MARGIN 5
                     19: 
                     20: #define MIN_SQUARE_SIZE 3
                     21: #define DEFAULT_SQUARE_SIZE 13
                     22: 
                     23: #define bit int
                     24: #define boolean int
                     25: #define TRUE 1
                     26: #define FALSE 0
                     27: #define OUT_OF_RANGE 10000
                     28: 
                     29: #define COPY           0
                     30: #define MOVE           1
                     31: #define OVERLAY                2
                     32: 
                     33: #define min(x,y) ((x < y) ? x : y)
                     34: #define max(x,y) ((x < y) ? y : x)
                     35: 
                     36: /* error handling stuff */
                     37: extern int errno;
                     38: extern char *sys_errlist[];
                     39: extern int _Xdebug;
                     40: 
                     41: /* global "constants" -- set once at startup time */
                     42: /* the first few variables are not static because they are shared
                     43:    with dialog.c */
                     44: Display *d;
                     45: int screen;
                     46: GC gc;
                     47: unsigned long foreground; /* pixel */
                     48: unsigned long background; /* pixel */
                     49: unsigned long border;     /* pixel */
                     50: int borderwidth = 3;
                     51: int invertplane = 1;
                     52: static int highlightplane = 1;
                     53: 
                     54: static XImage image = {
                     55:    0, 0,                       /* width, height */
                     56:    0, XYBitmap, NULL,          /* xoffset, format, data */
                     57:    LSBFirst, 8,                /* byte-order, bitmap-unit */
                     58:    LSBFirst, 8, 1              /* bitmap-bit-order, bitmap-pad, depth */
                     59:    };
                     60: 
                     61: static char *raster;
                     62: static int raster_length; /* how many chars in the raster[] array */
                     63: static Window outer_window, grid_window;
                     64: static Window raster_window, raster_invert_window;
                     65: static XFontStruct *font;
                     66: static Cursor cross, upper_left, lower_right, dot;
                     67: static char *filename = NULL; /* name of input file */
                     68: static char *backup_filename;
                     69: static char *stripped_name; 
                     70:   /* file name without directory path or extension */
                     71: static char *progname; /* name this program was invoked by */
                     72: 
                     73: 
                     74: /* command-button data */
                     75: void ClearOrSetAll(), InvertAll(),
                     76:       ClearOrSetArea(), InvertArea(), CopyOrMoveArea(),
                     77:       Line(), Circle(),
                     78:       SetHotSpot(), ClearHotSpot(), Quit();
                     79: boolean WriteOutput();
                     80: 
                     81: static struct command_data {
                     82:   char *name;
                     83:   void (*proc)(); 
                     84:      /* function to invoke when command button is "pressed" */
                     85:   int data;  /* arbitrary instance data to call procedure back with */
                     86:   Window window;
                     87:   int name_length;
                     88:   int x_offset;  /* so text is centered within command box */
                     89:   boolean inverted;
                     90:   } commands [] = {
                     91:        {"Clear All",   ClearOrSetAll, 0},
                     92:        {"Set All",     ClearOrSetAll, 1},
                     93:        {"Invert All",  InvertAll},
                     94: 
                     95:        {"Clear Area",  ClearOrSetArea, 0},
                     96:        {"Set Area",    ClearOrSetArea, 1},
                     97:        {"Invert Area", InvertArea},
                     98: 
                     99:        {"Copy Area",   CopyOrMoveArea, COPY},
                    100:        {"Move Area",   CopyOrMoveArea, MOVE},
                    101:        {"Overlay Area",CopyOrMoveArea, OVERLAY},
                    102: 
                    103:        {"Line",          Line},
                    104:        {"Circle",        Circle, 0},
                    105:        {"Filled Circle", Circle, 1},
                    106: 
                    107:        {"Set HotSpot",   SetHotSpot},
                    108:        {"Clear HotSpot", ClearHotSpot},
                    109: 
                    110:        {"Write Output", (void (*)()) WriteOutput},
                    111:        {"Quit",         Quit}
                    112:   };
                    113: #define N_COMMANDS (sizeof(commands)/sizeof(commands[0]))
                    114: 
                    115: /* global variables */
                    116: /* layout-related variables */
                    117: static int square_size;  /* length of square's side, in pixels */
                    118: static int outer_width = 1, outer_height = 1; /* real values set by ConfigureNotify event */
                    119: static int right_side_bottom, right_side_width;
                    120: 
                    121:   /* location of x'd-through squares, if any */
                    122: static int x1_square_exed_through = OUT_OF_RANGE;
                    123: static int y1_square_exed_through = OUT_OF_RANGE;
                    124: static int x2_square_exed_through = OUT_OF_RANGE;
                    125: static int y2_square_exed_through = OUT_OF_RANGE;
                    126: 
                    127:   /* location of "plus'd through" squares, if any */
                    128: static int x1_square_plus_through = OUT_OF_RANGE;
                    129: static int y1_square_plus_through = OUT_OF_RANGE;
                    130: static int x2_square_plus_through = OUT_OF_RANGE;
                    131: static int y2_square_plus_through = OUT_OF_RANGE;
                    132: 
                    133:   /* location of hot spot, if any */
                    134: static int x_hot_spot = OUT_OF_RANGE;
                    135: static int y_hot_spot = OUT_OF_RANGE;
                    136: 
                    137: static boolean changed = FALSE;
                    138:    /* has user changed bitmap since starting program or last write? */
                    139: 
                    140: static enum RepaintGridType {e_AgainstBackground, e_AgainstForeground, e_Invert};
                    141: 
                    142: extern char *malloc();
                    143: 
                    144: main (argc, argv)
                    145:   int argc;
                    146:   char **argv;
                    147:   {
                    148:   SetUp (argc, argv);
                    149:   while (TRUE) {
                    150:     XEvent event;
                    151:     XNextEvent(d, &event);
                    152:     ProcessEvent(&event);
                    153:     }
                    154:   }
                    155: 
                    156: 
                    157: static cleanup(data, stream)
                    158:   char *data;
                    159:   FILE *stream;
                    160: {
                    161:   if (data) free(data);
                    162:   fclose(stream);
                    163: }
                    164: 
                    165: int ReadBitmapFile(filename)
                    166:      char *filename;
                    167: {
                    168: #define MAX_LINE 81
                    169:   FILE *stream;
                    170:   char *ptr;
                    171:   char line[MAX_LINE];
                    172:   int bytes;
                    173:   char name_and_type[MAX_LINE];
                    174:   char *t;
                    175:   int value;
                    176:   int version10p;
                    177:   int padding;
                    178: 
                    179:   if (!(stream = fopen(filename, "r")))
                    180:     return(BitmapOpenFailed);
                    181: 
                    182:   for (;;) {
                    183:     if (!fgets(line, MAX_LINE, stream))
                    184:       break;
                    185:     if (strlen(line) == MAX_LINE-1) {
                    186:       cleanup(image.data, stream);
                    187:       return(BitmapFileInvalid);
                    188:     }
                    189: 
                    190:     if (sscanf(line, "#define %s %d", name_and_type, &value) == 2) {
                    191:       if (!(t = rindex(name_and_type, '_')))
                    192:        t = name_and_type;
                    193:       else
                    194:        t++;
                    195:       if (!strcmp("width", t))
                    196:        image.width = value;
                    197:       if (!strcmp("height", t))
                    198:        image.height = value;
                    199:       if (!strcmp("hot", t)) {
                    200:        if (t--==name_and_type || t--==name_and_type)
                    201:          continue;
                    202:        if (!strcmp("x_hot", t))
                    203:          x_hot_spot = value;
                    204:        if (!strcmp("y_hot", t))
                    205:          y_hot_spot = value;
                    206:       }
                    207:       continue;
                    208:     }
                    209:     
                    210:     if (sscanf(line, "static short %s = {", name_and_type) == 1)
                    211:       version10p = 1;
                    212:     else if (sscanf(line, "static char %s = {", name_and_type) == 1)
                    213:       version10p = 0;
                    214:     else continue;
                    215:  
                    216:     if (!(t = rindex(name_and_type, '_')))
                    217:       t = name_and_type;
                    218:     else
                    219:       t++;
                    220:     if (strcmp("bits[]", t))
                    221:       continue;
                    222:     
                    223:     if (!image.width || !image.height) {
                    224:       cleanup(image.data, stream);
                    225:       return(BitmapFileInvalid);
                    226:     }
                    227: 
                    228:     padding = 0;
                    229:     if ((image.width % 16) && ((image.width % 16) < 9) && version10p)
                    230:       padding = 1;
                    231: 
                    232:     image.bytes_per_line = (image.width+7)/8 + padding;
                    233:     
                    234:     raster_length =  image.bytes_per_line * image.height;
                    235:     image.data = (char *) malloc( raster_length );
                    236:     if (!image.data) {
                    237:       cleanup(image.data, stream);
                    238:       return(BitmapNoMemory);
                    239:     }
                    240: 
                    241:     if (version10p)
                    242:       for (bytes=0, ptr=image.data; bytes<raster_length; (bytes += 2)) {
                    243:        if (fscanf(stream, " 0x%x%*[,}]%*[ \n]", &value) != 1) {
                    244:          cleanup(image.data, stream);
                    245:          return(BitmapFileInvalid);
                    246:        }
                    247:        *(ptr++) = value & 0xff;
                    248:        if (!padding || ((bytes+2) % image.bytes_per_line))
                    249:          *(ptr++) = value >> 8;
                    250:       }
                    251:     else
                    252:       for (bytes=0, ptr=image.data; bytes<raster_length; bytes++, ptr++) {
                    253:        if (fscanf(stream, " 0x%x%*[,}]%*[ \n]", &value) != 1) {
                    254:          cleanup(image.data, stream);
                    255:          return(BitmapFileInvalid);
                    256:        }
                    257:        *ptr=value;
                    258:       }
                    259:     
                    260:   }
                    261: 
                    262:   if (!image.data) {
                    263:     cleanup(image.data, stream);
                    264:     return(BitmapFileInvalid);
                    265:   }
                    266: 
                    267:   fclose(stream);
                    268:   return(BitmapSuccess);
                    269: #undef MAX_LINE
                    270: }
                    271: 
                    272: SetUp (argc, argv)
                    273:   int argc;
                    274:   char **argv;
                    275:   {
                    276:   char *StripName(), *BackupName(), *index();
                    277:   char *option;
                    278:   FILE *file;
                    279:   char *geometry = NULL, *host = NULL, *dimensions = NULL;
                    280:   int i;
                    281:   int status;
                    282: 
                    283:   progname = argv[0];
                    284:   setlinebuf (stderr);
                    285: 
                    286:   /* Parse command line */
                    287:   for (i = 1; i < argc; i++) {
                    288:     if (argv[i][0] == '=')
                    289:        geometry = argv[i];
                    290: 
                    291:     else if (index (argv[i], ':') != NULL)
                    292:        host = argv[i];
                    293:        
                    294:     else if (filename == NULL)
                    295:        filename = argv[i];
                    296: 
                    297:     else 
                    298:        dimensions = argv[i];
                    299:     }
                    300: 
                    301:   if (filename == NULL) {
                    302:     fprintf (stderr, "%s: no file name specified\n", progname);
                    303:     exit (1);
                    304:     }
                    305:   
                    306:   stripped_name = StripName (filename);
                    307:   backup_filename = BackupName (filename);
                    308: 
                    309:   status = ReadBitmapFile(filename, image, &x_hot_spot, &y_hot_spot);
                    310:   if (status == BitmapFileInvalid) {
                    311:       fprintf(stderr, "Bitmap file invalid\n");
                    312:       exit (1);
                    313:   }
                    314:   else if (status == BitmapOpenFailed) {
                    315:       register int i;
                    316: 
                    317:       if (dimensions) {
                    318:          if (sscanf (dimensions, "%dx%d", &image.width, &image.height) != 2) {
                    319:            fprintf (stderr, "%s: invalid dimensions '%s'\n",
                    320:               progname, dimensions);
                    321:            exit (1);
                    322:         }
                    323:          if ((image.width <=0) || (image.height <=0)) {
                    324:             fprintf (stderr, "%s: dimensions must be positive\n", progname);
                    325:             exit (1);
                    326:          }
                    327:       }
                    328:       
                    329:       else /* dimensions not supplied on command line */
                    330:          image.width = image.height = 16;
                    331: 
                    332:       image.bytes_per_line = (image.width+7)/8;
                    333:       raster_length = image.bytes_per_line * image.height;
                    334:       raster = image.data = malloc (raster_length);
                    335: 
                    336:       /* set raster to all 0's (background color) */
                    337:       for (i=0;i<raster_length;i++)
                    338:         raster[i] = 0;
                    339:   }
                    340:   else  /* status == BitmapSuccess */
                    341:       raster = image.data;
                    342: 
                    343:   if (!(d = XOpenDisplay(host))) {
                    344:        fprintf(stderr, "%s: Can't open display '%s'\n",
                    345:                argv[0], XDisplayName(host));
                    346:        exit (1);
                    347:     }
                    348: 
                    349:   screen = DefaultScreen(d);
                    350:   gc = DefaultGC (d, screen);
                    351:   XSetLineAttributes (d, gc, 0, LineSolid, CapNotLast, JoinMiter);
                    352: 
                    353:   if ((option = XGetDefault(d, progname, "BorderWidth")) != NULL)
                    354:     borderwidth = atoi(option);
                    355:   if ((option = XGetDefault(d, progname, "BodyFont")) == NULL)
                    356:     option = "fixed";
                    357:   font = XLoadQueryFont (d, option);
                    358:   XSetFont (d, gc, font->fid);
                    359: 
                    360:   upper_left = XCreateFontCursor (d, XC_ul_angle);
                    361:   lower_right = XCreateFontCursor (d, XC_lr_angle);
                    362:   cross = XCreateFontCursor (d, XC_crosshair);
                    363:   dot = XCreateFontCursor (d, XC_dot);
                    364: 
                    365:   foreground = border = BlackPixel (d, screen);
                    366:   background = WhitePixel (d, screen);
                    367: 
                    368:   if (DisplayCells(d, screen) > 2) {
                    369:     Colormap cmap = DefaultColormap (d, screen);
                    370:     char *fore_color = XGetDefault(d, progname, "Foreground");
                    371:     char *back_color = XGetDefault(d, progname, "Background");
                    372:     char *high_color = XGetDefault(d, progname, "Highlight");
                    373:     char *brdr_color = XGetDefault(d, progname, "Border");
                    374:     char *mous_color = XGetDefault(d, progname, "Mouse");
                    375:     XColor fdef, bdef, hdef;
                    376:     unsigned long masks[2];
                    377:     if (fore_color && XParseColor(d, cmap, fore_color, &fdef) &&
                    378:       back_color && XParseColor(d, cmap, back_color, &bdef) &&
                    379:       (high_color == NULL || XParseColor(d, cmap, high_color, &hdef)) &&
                    380:       XAllocColorCells(d, cmap, FALSE, masks, high_color ? 2 : 1,
                    381:         &background, 1)) {
                    382:       bdef.pixel = background;
                    383:       XStoreColor(&bdef);
                    384:       invertplane = masks[0];
                    385:       if (high_color) {
                    386:        highlightplane = masks[1];
                    387:        hdef.pixel = background | highlightplane;
                    388:        XStoreColor(&hdef);
                    389:        hdef.pixel |= invertplane;
                    390:        XStoreColor(&hdef);
                    391:       } else
                    392:        highlightplane = invertplane;
                    393:       fdef.pixel = foreground = background | invertplane;
                    394:       XStoreColor(&fdef);
                    395:     }
                    396:     if (brdr_color && XParseColor(d, cmap, brdr_color, &bdef) &&
                    397:        XAllocColor(&bdef))
                    398:       border = bdef.pixel;
                    399:   }
                    400: 
                    401:   {
                    402:   XSizeHints hints;
                    403:   int display_width = DisplayWidth(d, screen);
                    404:   int display_height = DisplayHeight(d, screen);
                    405:   XSetWindowAttributes attrs;
                    406:   attrs.background_pixel = background;
                    407:   attrs.border_pixel = border;
                    408:   attrs.event_mask = StructureNotifyMask;  /* to detect size changes */
                    409:   attrs.cursor = cross;
                    410: 
                    411:   outer_window = XCreateWindow (d, RootWindow (d, screen),
                    412:      0, 0, 1, 1,  /* dummy x, y, width, height; see MoveResizeWindow below */
                    413:      borderwidth, CopyFromParent, CopyFromParent, CopyFromParent,
                    414:      CWBackPixel | CWBorderPixel | CWEventMask | CWCursor,
                    415:      &attrs);
                    416:   LayoutStage1(); /* sets global variables
                    417:                      right_side_bottom, right_side_width */
                    418:   OuterWindowDims (MIN_SQUARE_SIZE, right_side_width, right_side_bottom,
                    419:     &hints.min_width, &hints.min_height);
                    420:   hints.flags = PMinSize;
                    421:   if (geometry) {
                    422:      int geom_result = XParseGeometry (geometry, &hints.x, &hints.y, &hints.width, &hints.height);
                    423:      if ((geom_result & WidthValue) && (geom_result & HeightValue)) {
                    424:         if (hints.width < hints.min_width) hints.width = hints.min_width;
                    425:         if (hints.height < hints.min_height) hints.height = hints.min_height;
                    426:         hints.flags |= USSize;
                    427:         }
                    428:      if ((geom_result & XValue) && (geom_result & YValue))
                    429:         hints.flags |= USPosition;
                    430:      }
                    431:   if (!(hints.flags & USSize)) {
                    432:      OuterWindowDims (DEFAULT_SQUARE_SIZE, right_side_width, right_side_bottom,
                    433:         &hints.width, &hints.height);
                    434:      hints.flags |= PSize;
                    435:      }
                    436:   if (!(hints.flags & USPosition)) {
                    437:      hints.x = min (200, display_width - hints.width - 2*borderwidth);
                    438:      hints.y = min (200, display_height - hints.height - 2*borderwidth);
                    439:      hints.flags |= PPosition;
                    440:      }
                    441:   if (hints.x < 0) hints.x += display_width - hints.width;
                    442:   if (hints.y < 0) hints.y += display_height - hints.height;
                    443:   XMoveResizeWindow (d, outer_window, hints.x, hints.y, hints.width, hints.height);
                    444:   XSetStandardProperties (d, outer_window, "Bitmap Editor", "bitmap", None, argv, argc, &hints);
                    445:   }
                    446: 
                    447:   XMapWindow (d, outer_window);
                    448: 
                    449:   /* the above XMoveResizeWindow will generate a ConfigureNotify event
                    450:      telling us the actual size of the window when it is mapped.  We
                    451:      wait for this event before proceeding to LayoutStage2() and
                    452:      mapping the subwindows. */
                    453:   }
                    454: 
                    455: 
                    456: ProcessEvent (event)
                    457:   register XEvent *event;
                    458:   {
                    459:   register Window w = event->xany.window;
                    460:   register int i;
                    461:   if (w == grid_window)
                    462:     ProcessGridWindowEvent (event);
                    463:   else if (w == outer_window)
                    464:     ProcessOuterWindowEvent (event);
                    465:   else if (w == raster_window)
                    466:     RepaintRaster();
                    467:   else if (w == raster_invert_window)
                    468:     RepaintRasterInverted();
                    469:   else for (i=0;i<N_COMMANDS;i++)
                    470:     if (w == commands[i].window)
                    471:       ProcessCommandButtonEvent (&commands[i], event);
                    472:   }
                    473: 
                    474: 
                    475: ProcessGridWindowEvent (event)
                    476:   XEvent *event;
                    477:   {
                    478:   int x_square, y_square;
                    479:   static int x_square_prev, y_square_prev;
                    480:   static boolean raster_outdated;
                    481:   switch (event->type) {
                    482: 
                    483:     case Expose: {
                    484: #define this_event ((XExposeEvent *)event)
                    485:       int x1 = this_event->x;
                    486:       int y1 = this_event->y;
                    487:       int x2 = x1 + this_event->width;
                    488:       int y2 = y1 + this_event->height;
                    489: #undef this_event
                    490:       x1 /= square_size;
                    491:       x2 /= square_size;
                    492:       y1 /= square_size;
                    493:       y2 /= square_size;
                    494:       if (x2 >= image.width)
                    495:         x2 = image.width - 1;  /* sanity check */
                    496:       if (y2 >= image.height)
                    497:         y2 = image.height - 1;  /* sanity check */
                    498:       RepaintGridLinesPartially(x1,y1,x2+1,y2+1,e_AgainstBackground,TRUE);
                    499:       RefillGridPartially (x1,y1,x2,y2,FALSE);
                    500:       if (x1_square_exed_through != OUT_OF_RANGE)
                    501:         ExThroughRectangle (
                    502:          max (x1, x1_square_exed_through),
                    503:          max (y1, y1_square_exed_through),
                    504:          min (x2, x2_square_exed_through),
                    505:          min (y2, y2_square_exed_through));
                    506:       if (x1_square_plus_through != OUT_OF_RANGE)
                    507:         PlusThroughRectangle (
                    508:          max (x1, x1_square_plus_through),
                    509:          max (y1, y1_square_plus_through),
                    510:          min (x2, x2_square_plus_through),
                    511:          min (y2, y2_square_plus_through));
                    512:       if (x_hot_spot >= x1 && x_hot_spot <= x2
                    513:        && y_hot_spot >= y1 && y_hot_spot <= y2)
                    514:            HighlightHotSpot();
                    515:       break;
                    516:       }
                    517: 
                    518:     case ButtonPress:
                    519:       if (WhatSquare (event, &x_square, &y_square))
                    520:         return;  /* mouse outside grid; really shouldn't happen, but... */
                    521:       switch (((XButtonPressedEvent *)event)->button) {
                    522:        case 1: /* Left button */
                    523:          PaintSquare (x_square, y_square, foreground);
                    524:          if (x_square == x_hot_spot && y_square == y_hot_spot)
                    525:            HighlightHotSpot();
                    526:          SetRasterBit (raster, x_square, y_square, 1);
                    527:          break;
                    528:        case 2: /* Middle button */
                    529:          InvertSquare (x_square, y_square);
                    530:          InvertRasterBit (raster, x_square, y_square);
                    531:          break;
                    532:        case 3: /* Right button */
                    533:          PaintSquare (x_square, y_square, background);
                    534:          if (x_square == x_hot_spot && y_square == y_hot_spot)
                    535:            HighlightHotSpot();
                    536:          SetRasterBit (raster, x_square, y_square, 0);
                    537:          break;
                    538:        }
                    539:       RepaintRaster();
                    540:       RepaintRasterInverted();
                    541:       x_square_prev = x_square;
                    542:       y_square_prev = y_square;
                    543:       raster_outdated = FALSE;
                    544:       changed = TRUE;
                    545:       break;
                    546:     
                    547:     case MotionNotify:
                    548:       if (WhatSquare (event, &x_square, &y_square))
                    549:         return;  /* mouse outside grid; really shouldn't happen, but... */
                    550:       if ((x_square != x_square_prev) || (y_square != y_square_prev))
                    551:                  switch (((XMotionEvent *)event)->state) {
                    552:            case Button1Mask: /* left button down */
                    553:              PaintSquare (x_square, y_square, foreground);
                    554:              if (x_square == x_hot_spot && y_square == y_hot_spot)
                    555:                HighlightHotSpot();
                    556:              SetRasterBit (raster, x_square, y_square, 1);
                    557:              changed = raster_outdated = TRUE;
                    558:              break;
                    559:            case Button2Mask: /* middle button down */
                    560:              InvertSquare (x_square, y_square);
                    561:              InvertRasterBit (raster, x_square, y_square);
                    562:              changed = raster_outdated = TRUE;
                    563:              break;
                    564:            case Button3Mask: /* right button down */
                    565:              PaintSquare (x_square, y_square, background);
                    566:              if (x_square == x_hot_spot && y_square == y_hot_spot)
                    567:                HighlightHotSpot();
                    568:              SetRasterBit (raster, x_square, y_square, 0);
                    569:              changed = raster_outdated = TRUE;
                    570:              break;
                    571:            default: /* ignore events with multiple buttons down */
                    572:              break; 
                    573:            }
                    574:       if (raster_outdated && !MouseMovedEventQueued()) {
                    575:        RepaintRaster();
                    576:        RepaintRasterInverted();
                    577:        raster_outdated = FALSE;
                    578:        }
                    579:       x_square_prev = x_square;
                    580:       y_square_prev = y_square;
                    581:       break;
                    582:   
                    583:     }
                    584:   }
                    585: 
                    586: boolean MouseMovedEventQueued () {
                    587:   XEvent event;
                    588:   if (XPending(d) == 0) return (FALSE);
                    589:   XPeekEvent (d, &event);
                    590:   return (event.type == MotionNotify);
                    591:   }
                    592: 
                    593: 
                    594: ProcessOuterWindowEvent (event)
                    595:   XEvent *event;
                    596:   {
                    597:   if (event->type != ConfigureNotify)
                    598:     return;
                    599:   if ((outer_height == ((XConfigureEvent *)event)->height)
                    600:      && (outer_width == ((XConfigureEvent *)event)->width))
                    601:      /* if this isn't a resize, there's nothing to do here. */
                    602:      return;
                    603: 
                    604:   /* the outer window's size has changed.  Must rearrange subwindows. */
                    605:   outer_height = ((XConfigureEvent *)event)->height;
                    606:   outer_width = ((XConfigureEvent *)event)->width;
                    607:   LayoutStage2 ();
                    608:   XMapSubwindows (d, outer_window);
                    609:   }
                    610:   
                    611: ProcessCommandButtonEvent (command, event)
                    612:   struct command_data *command;
                    613:   XEvent *event;
                    614:   {
                    615:   static struct command_data *button_down_command;
                    616:   
                    617:   switch (event->type) {
                    618: 
                    619:     case Expose:
                    620:       if (((XExposeEvent *)event)->count)
                    621:        break;  /* repaint only when last exposure is received */
                    622:       if (command->inverted)
                    623:         XClearWindow (d, command->window);
                    624:       XSetState (d, gc, foreground, background, GXcopy, AllPlanes);
                    625:       XDrawString (d, command->window, gc, command->x_offset, font->ascent,
                    626:         command->name, command->name_length);
                    627:       if (command->inverted)
                    628:        InvertCommandWindow (command);
                    629:       break;
                    630: 
                    631:     case ButtonPress:
                    632:       if (button_down_command != NULL)
                    633:         break;  /* must be a second button push--ignore */
                    634:       button_down_command = command;
                    635:       InvertCommandWindow (command);
                    636:       command->inverted = TRUE;
                    637:       break;
                    638: 
                    639:     case LeaveNotify:
                    640:       if (command == button_down_command) {
                    641:        InvertCommandWindow (command);
                    642:        command->inverted = FALSE;
                    643:        button_down_command = NULL;
                    644:        }
                    645:       break;
                    646: 
                    647:     case ButtonRelease:
                    648:       if (command == button_down_command) {
                    649:        (*command->proc)(command->data);
                    650:        button_down_command = NULL;
                    651:        InvertCommandWindow (command);
                    652:        command->inverted = FALSE;
                    653:        }
                    654:       break;
                    655:       
                    656:     }
                    657:   }
                    658: 
                    659: 
                    660: InvertCommandWindow (command)
                    661:   struct command_data *command;
                    662:   {
                    663:   XSetState (d, gc, 1L, 0L, GXinvert, invertplane);
                    664:   XFillRectangle (d, command->window, gc, 0, 0, 1000, 1000);
                    665:   }
                    666: 
                    667:          
                    668: /* WhatSquare returns TRUE if mouse is outside grid, FALSE if inside.
                    669:    If it returns FALSE, it assigns to *x_square and *y_square. */
                    670: 
                    671: boolean WhatSquare (event, x_square, y_square)
                    672:   register XEvent *event;
                    673:   register int *x_square, *y_square; /*RETURN*/
                    674:   {
                    675:   int x = ((XButtonEvent *)event)->x;
                    676:   int y = ((XButtonEvent *)event)->y;
                    677:   if ((x < 0) || (y < 0))
                    678:     return (TRUE);
                    679:   *x_square = x/square_size;
                    680:   *y_square = y/square_size;
                    681:   return ((*x_square >= image.width) || (*y_square >= image.height));
                    682:   }
                    683: 
                    684: 
                    685: RepaintGridLines(how)
                    686:   enum RepaintGridType how;
                    687:   {
                    688:   RepaintGridLinesPartially (0, 0, image.width, image.height, how, TRUE);
                    689:   }
                    690: 
                    691: RepaintGridLinesPartially (x1, y1, x2, y2, how, include_boundaries)
                    692:   int x1, y1, x2, y2;
                    693:   enum RepaintGridType how;
                    694:   boolean include_boundaries;
                    695:   {
                    696:   register int i;
                    697:   int px1, px2, py1, py2;
                    698: 
                    699:   switch (how) {
                    700:     XGCValues gcv;
                    701:     case e_AgainstBackground:
                    702:         gcv.foreground = foreground;
                    703:        gcv.function = GXcopy;
                    704:        gcv.plane_mask = AllPlanes;
                    705:         gcv.line_style = LineOnOffDash;
                    706:        gcv.dashes = 1;
                    707:        gcv.dash_offset = 0;
                    708:         XChangeGC (d, gc, GCForeground | GCFunction | GCPlaneMask |
                    709:           GCLineStyle | GCDashList | GCDashOffset, &gcv);
                    710:        break;
                    711:     case e_AgainstForeground:
                    712:         gcv.foreground = background;
                    713:        gcv.function = GXcopy;
                    714:        gcv.plane_mask = AllPlanes;
                    715:         gcv.line_style = LineOnOffDash;
                    716:        gcv.dashes = 1;
                    717:        gcv.dash_offset = 1;
                    718:         XChangeGC (d, gc, GCForeground | GCFunction | GCPlaneMask |
                    719:           GCLineStyle | GCDashList | GCDashOffset, &gcv);
                    720:        break;
                    721:     case e_Invert:
                    722:         gcv.function = GXinvert;
                    723:         gcv.plane_mask = invertplane;
                    724:         gcv.line_style = LineSolid;
                    725:         XChangeGC (d, gc, GCFunction | GCPlaneMask | GCLineStyle, &gcv);
                    726:        break;
                    727:     }
                    728:     
                    729:   /* draw vertical grid lines */
                    730:   py1 = y1*square_size;
                    731:   py1 += (py1 & 1);  /* make sure pattern is aligned on even bit boundary */
                    732:   py2 = y2*square_size;
                    733:   if (!include_boundaries) {x1++;x2--;}
                    734:   px1 = x1*square_size;
                    735:   for (i=x1;i<=x2; i++) {
                    736:      XDrawLine (d, grid_window, gc, px1, py1, px1, py2);
                    737:      px1 += square_size;
                    738:      }
                    739:   if (!include_boundaries) {x1--;x2++;}
                    740: 
                    741:   /* draw horizontal grid lines */
                    742:   px1 = x1*square_size;
                    743:   px1 += (px1 & 1);  /* make sure pattern is aligned on even bit boundary */
                    744:   px2 = x2*square_size;
                    745:   if (!include_boundaries) {y1++;y2--;}
                    746:   py1 = y1*square_size;
                    747:   for (i=y1;i<=y2;i++) {
                    748:      XDrawLine (d, grid_window, gc, px1, py1, px2, py1);
                    749:      py1 += square_size;
                    750:      }
                    751:   }
                    752: 
                    753: 
                    754: RefillGridPartially(x1, y1, x2, y2, paint_background)
                    755:   register int x1, y1, x2, y2;
                    756:   boolean paint_background;
                    757:   {
                    758:   register i, j;
                    759:   for (i=x1; i<=x2; i++) {
                    760:     for (j=y1; j<=y2; j++) {
                    761:       bit b = GetRasterBit (raster, i, j);
                    762:       if (b || paint_background)
                    763:        PaintSquare (i, j, (b ? foreground : background));
                    764:       }
                    765:     }
                    766:   }
                    767: 
                    768: 
                    769: PaintSquare(x, y, pixel)
                    770:   int x, y;
                    771:   unsigned long pixel;
                    772:   {
                    773:   XSetState (d, gc, pixel, 0L /* ignored */, GXcopy, AllPlanes);
                    774:   XFillRectangle (d, grid_window, gc, x*square_size + 1, y*square_size + 1,
                    775:     square_size - 1, square_size - 1);
                    776:   }
                    777: 
                    778: InvertSquare(x, y)
                    779:   int x, y;
                    780:   {
                    781:   XSetState (d, gc, 1L, 0L, GXinvert, invertplane);
                    782:   XFillRectangle (d, grid_window, gc, x*square_size + 1, y*square_size + 1,
                    783:     square_size - 1, square_size - 1);
                    784:   }
                    785: 
                    786: bit GetRasterBit (raster, x, y)
                    787:   char *raster;
                    788:   register int x;
                    789:   int y;
                    790:   {
                    791:   register char *byte = raster + x/8 + y*((image.width+7)/8);
                    792:   return ( (*byte & (1 << (x % 8))) ? 1 : 0);
                    793:   }
                    794: 
                    795: 
                    796: SetRasterBit (raster, x, y, new)
                    797:   char *raster;
                    798:   register int x;
                    799:   int y;
                    800:   bit new;
                    801:   {
                    802:   register char *byte = raster + x/8 + y*((image.width+7)/8);
                    803:   x %= 8;
                    804:   *byte = (new << x) | (*byte & ~(1 << x));
                    805:   }
                    806: 
                    807: 
                    808: InvertRasterBit (raster, x, y)
                    809:   char *raster;
                    810:   register int x;
                    811:   int y;
                    812:   {
                    813:   register char *byte = raster + x/8 + y*((image.width+7)/8);
                    814:   *byte ^= (1 << (x % 8));
                    815:   }
                    816: 
                    817: 
                    818: RepaintRaster() {
                    819:   XSetState (d, gc, foreground, background, GXcopy, AllPlanes);
                    820:   XPutImage (d, raster_window, gc, &image,
                    821:      0, 0, 3, 3, image.width, image.height);
                    822:   }
                    823: 
                    824: 
                    825: RepaintRasterInverted () {
                    826:   XSetState (d, gc, background, foreground, GXcopy, AllPlanes);
                    827:   XPutImage (d, raster_invert_window, gc, &image,
                    828:      0, 0, 3, 3, image.width, image.height);
                    829:   }
                    830: 
                    831: 
                    832: WriteOutputToFile (file)
                    833:   FILE *file;
                    834:   {
                    835:   register int i;
                    836:   fprintf (file, "#define %s_width %d\n", stripped_name, image.width);
                    837:   fprintf (file, "#define %s_height %d\n", stripped_name, image.height);
                    838:   if (x_hot_spot != OUT_OF_RANGE)
                    839:     fprintf (file, "#define %s_x_hot %d\n", stripped_name, x_hot_spot);
                    840:   if (y_hot_spot != OUT_OF_RANGE)
                    841:     fprintf (file, "#define %s_y_hot %d\n", stripped_name, y_hot_spot);
                    842:   fprintf (file, "static char %s_bits[] = {\n   0x%02x",
                    843:     stripped_name, (unsigned char) raster[0]);
                    844: 
                    845:   for (i=1;i<raster_length;i++) {
                    846:     fprintf (file, ",");
                    847:     fprintf (file, (i % 12) ? " " : "\n   ");
                    848:     fprintf (file, "0x%02x", (unsigned char) raster[i]);
                    849:     }
                    850:   fprintf (file, "};\n");
                    851:   }
                    852: 
                    853: 
                    854: char *StripName(name)
                    855:   char *name;
                    856:   {
                    857:   char *rindex(), *index();
                    858:   char *begin = rindex (name, '/');
                    859:   char *end, *result;
                    860:   int length;
                    861:   begin = (begin ? begin+1 : name);
                    862:   end = index (begin, '.');
                    863:   length = (end ? (end - begin) : strlen (begin));
                    864:   result = (char *) malloc (length + 1);
                    865:   strncpy (result, begin, length);
                    866:   result [length] = '\0';
                    867:   return (result);
                    868:   }
                    869: 
                    870: 
                    871: char *BackupName(name)
                    872:   char *name;
                    873:   {
                    874:   int name_length = strlen (name);
                    875:   char *result = (char *) malloc (name_length+2);
                    876:   strncpy (result, name, name_length);
                    877:   result [name_length] = '~';
                    878:   result [name_length+1] = '\0';
                    879:   return (result);
                    880:   }
                    881: 
                    882: char *TmpFileName(name)
                    883:   char *name;
                    884:   {
                    885:   {
                    886:   char *rindex();
                    887:   char *begin = rindex (name, '/');
                    888:   if (begin)
                    889:     name = begin+1;
                    890:   }
                    891:   {
                    892:   char *tmp = "/tmp/";
                    893:   int name_length = strlen (name);
                    894:   int tmp_length = strlen (tmp);
                    895:   int result_length = name_length + tmp_length;
                    896:   char *result = (char *) malloc (result_length + 1);
                    897:   strncpy (result, tmp, tmp_length);
                    898:   strncpy (result+tmp_length, name, name_length);
                    899:   result [result_length] = '\0';
                    900:   return (result);
                    901:   }
                    902:   }
                    903: 
                    904: /* StringEndsWith returns TRUE if "s" ends with "suffix", else returns FALSE */
                    905: boolean StringEndsWith (s, suffix)
                    906:   char *s, *suffix;
                    907:   {
                    908:   int s_len = strlen (s);
                    909:   int suffix_len = strlen (suffix);
                    910:   return (strcmp (s + s_len - suffix_len, suffix) == 0);
                    911:   }
                    912: 
                    913: /* LayoutStage1 creates the grid window, all commmand windows and both
                    914:    raster windows.
                    915: 
                    916:    The grid window is created with its proper x and y positions; a later call
                    917:    on LayoutStage2 will set its height and width before it is mapped.
                    918: 
                    919:    The command and raster windows are created with their proper height
                    920:    width, and y positions; it's up to LayoutStage2 to give them proper
                    921:    x positions before mapping them.  LayoutStage1 fills in everything in
                    922:    the commands[] array.
                    923: 
                    924:    This routine is called only once, at startup time.
                    925:    Everything done at this stage stays the same even if the user later
                    926:    reshapes the window. */
                    927: 
                    928: LayoutStage1 ()
                    929:   {
                    930:   int widths [N_COMMANDS];
                    931:   int command_width = 0;
                    932:   int ypos = TOP_MARGIN;
                    933:   int fontHeight = font->ascent + font->descent;
                    934:   register int i;
                    935:   XSetWindowAttributes attrs;
                    936: 
                    937:   /* first determine how wide the commands should be */
                    938:   for (i=0;i<N_COMMANDS;i++) {
                    939:     register struct command_data *command = &commands[i];
                    940:     command->name_length = strlen (command->name);
                    941:     widths[i] = XTextWidth (font, command->name, command->name_length);
                    942:     if (command_width < widths[i])
                    943:       command_width = widths[i];
                    944:     }
                    945: 
                    946:   command_width += 4; /* so even widest command has a little space around it */
                    947: 
                    948:   /* now create the command windows.  Command strings will be centered in them */
                    949:   /* x position of commands will be determined later */
                    950: 
                    951:   attrs.win_gravity = UnmapGravity;
                    952:   attrs.event_mask =
                    953:       ButtonPressMask | ButtonReleaseMask | LeaveWindowMask | ExposureMask;
                    954:   attrs.background_pixel = background;
                    955: 
                    956:   for (i=0;i<N_COMMANDS;i++) {
                    957:     register struct command_data *command = &commands[i];
                    958:     command->x_offset = (command_width - widths[i])/2;
                    959:     command->window = XCreateWindow (d, outer_window, 0, ypos,
                    960:        command_width, fontHeight, 1, CopyFromParent, CopyFromParent,
                    961:         CopyFromParent, CWBackPixel | CWWinGravity | CWEventMask, &attrs);
                    962:     ypos += fontHeight + 5;
                    963:     if (i==2 || i == 5 || i == 8 || i == 11 || i == 13)
                    964:       ypos += fontHeight + 5;
                    965:       /* for gaps between command groups;  pretty random! */
                    966:     }
                    967:   
                    968:   /* set up raster window; x position to be determined later */
                    969:   attrs.event_mask = ExposureMask;
                    970:   ypos += AROUND_RASTER_MARGIN;
                    971:   raster_window = XCreateWindow (d, outer_window, 0, ypos,
                    972:        image.width + 6, image.height + 6, 1, CopyFromParent, CopyFromParent,
                    973:        CopyFromParent, CWBackPixel | CWWinGravity | CWEventMask, &attrs);
                    974:   
                    975:   /* set up raster invert window; x position to be determined later */
                    976:   ypos += image.height + 8 + AROUND_RASTER_MARGIN;
                    977:   raster_invert_window = XCreateWindow (d, outer_window, 0, ypos,
                    978:        image.width + 6, image.height + 6, 1, CopyFromParent, CopyFromParent,
                    979:        CopyFromParent, CWBackPixel | CWWinGravity | CWEventMask, &attrs);
                    980: 
                    981:   /* set up the grid window; width and height to be determined later */
                    982:   attrs.event_mask =  Button1MotionMask | Button2MotionMask | Button3MotionMask
                    983:     | ExposureMask | ButtonPressMask | ButtonReleaseMask;
                    984:     /* ButtonRelease is selected for AskUserForArea's benefit */
                    985:   grid_window = XCreateWindow (d, outer_window, LEFT_MARGIN, TOP_MARGIN,
                    986:        1, 1, 0, CopyFromParent, CopyFromParent,
                    987:        CopyFromParent, CWBackPixel | CWWinGravity | CWEventMask, &attrs);
                    988: 
                    989:   /* assign global variables based on this layout */
                    990:   right_side_bottom = ypos + image.height
                    991:      + 2 /* borders */ + AROUND_RASTER_MARGIN;
                    992:   right_side_width = 2 /* borders */ + max (
                    993:      command_width + GRID_TO_COMMAND_MARGIN + RIGHT_MARGIN,
                    994:      AROUND_RASTER_MARGIN + image.width);
                    995:   }
                    996: 
                    997: 
                    998: /* LayoutStage2 is called whenever a ConfigureNotify event occurs,
                    999:    whether this is at startup time or when the user resizes the outer
                   1000:    window.  It figures out what the new grid square size should be,
                   1001:    determines the new size of the grid window and the positions of all
                   1002:    command and raster windows, then reconfigures those windows
                   1003:    appropriately. */
                   1004: 
                   1005: LayoutStage2 ()
                   1006:   {
                   1007:   int x_room = outer_width - 1 - LEFT_MARGIN - right_side_width;
                   1008:   int y_room = outer_height - 1 - TOP_MARGIN - BOTTOM_MARGIN;
                   1009:   register int i;
                   1010:   int grid_width;
                   1011:   XWindowChanges changes;
                   1012:   
                   1013:   x_room /= image.width;
                   1014:   y_room /= image.height;
                   1015:   square_size = min (x_room, y_room);
                   1016:   if (square_size < 1) square_size = 1;
                   1017: 
                   1018:   /* set the grid window's dimensions */
                   1019:   grid_width = (image.width * square_size) + 1;
                   1020:   XResizeWindow (d, grid_window, grid_width, (image.height * square_size) + 1);
                   1021: 
                   1022:   /* set x positions of command windows */
                   1023:   changes.x = LEFT_MARGIN + grid_width + GRID_TO_COMMAND_MARGIN;
                   1024:   for (i=0;i<N_COMMANDS;i++)
                   1025:     XConfigureWindow (d, commands[i].window, CWX, &changes);
                   1026: 
                   1027:   /* set x offsets for raster and raster-inverted windows */
                   1028:   changes.x = LEFT_MARGIN + grid_width + AROUND_RASTER_MARGIN;
                   1029:   XConfigureWindow (d, raster_window, CWX, &changes);
                   1030:   XConfigureWindow (d, raster_invert_window, CWX, &changes);
                   1031:   }
                   1032: 
                   1033: /* OuterWindowDims determines the minimum size for the outer window,
                   1034:    based on three constraints:  the grid square size, the width of
                   1035:    the command/raster area, and the minimum height of the
                   1036:    command/raster area ("right side" of the window).  It is called
                   1037:    at startup time. */
                   1038: 
                   1039: OuterWindowDims (square_size, right_side_width,
                   1040:   right_side_bottom, width, height)
                   1041:   int square_size, right_side_width, right_side_bottom;
                   1042:   int *width, *height; /* RETURN */
                   1043:   {
                   1044:   *width = LEFT_MARGIN + image.width*square_size + 1 + right_side_width;
                   1045:   *height = TOP_MARGIN + image.height*square_size + 1 + BOTTOM_MARGIN;
                   1046:   if (*height < right_side_bottom)
                   1047:     *height = right_side_bottom;
                   1048:   }
                   1049: 
                   1050: 
                   1051: void ClearOrSetAll(b)
                   1052:   bit b;  /* 0 for clear, 1 for set */
                   1053:   {
                   1054:   register int i;
                   1055:   register int new = (b ? ~0: 0);
                   1056:   for (i=0;i<raster_length;i++)
                   1057:     raster[i] = new;
                   1058:   changed = TRUE;
                   1059:   XSetState (d, gc, b ? foreground : background, 0L /* ignored */,
                   1060:     GXcopy, AllPlanes);
                   1061:   XFillRectangle (d, grid_window, gc, 0, 0, 
                   1062:     image.width*square_size+1, image.height*square_size+1);
                   1063:   RepaintGridLines (b ? e_AgainstForeground : e_AgainstBackground);
                   1064:   RepaintRaster();
                   1065:   RepaintRasterInverted();
                   1066:   if (x_hot_spot != OUT_OF_RANGE)
                   1067:     HighlightHotSpot();
                   1068:   }
                   1069: 
                   1070: 
                   1071: void ClearOrSetArea(b)
                   1072:   bit b;  /* 0 for clear, 1 for set */
                   1073:   {
                   1074:   int x1, y1, x2, y2;
                   1075:   register int x, y;
                   1076:   if (AskUserForArea (&x1, &y1, &x2, &y2))
                   1077:     return;
                   1078:   for (x=x1;x<=x2;x++)
                   1079:     for (y=y1;y<=y2;y++)
                   1080:       SetRasterBit (raster, x, y, b);
                   1081:   XSetState (d, gc, b ? foreground : background, 0L /* ignored */,
                   1082:     GXcopy, AllPlanes);
                   1083:   XFillRectangle (d, grid_window, gc, x1*square_size+1, y1*square_size+1, 
                   1084:     (x2-x1+1)*square_size-1, (y2-y1+1)*square_size-1);
                   1085:   RepaintGridLinesPartially (x1, y1, x2+1, y2+1,
                   1086:      b ? e_AgainstForeground : e_AgainstBackground, FALSE);
                   1087:   if (x_hot_spot >= x1 && x_hot_spot <= x2
                   1088:     && y_hot_spot >= y1 && y_hot_spot <= y2)
                   1089:        HighlightHotSpot();
                   1090:   changed = TRUE;
                   1091:   RepaintRaster();
                   1092:   RepaintRasterInverted();
                   1093:   x1_square_exed_through = y1_square_exed_through = OUT_OF_RANGE;
                   1094:   x2_square_exed_through = y2_square_exed_through = OUT_OF_RANGE;
                   1095:   }
                   1096: 
                   1097: 
                   1098: void InvertAll() {
                   1099:   register int i;
                   1100:   for (i=0;i<raster_length;i++)
                   1101:     raster[i] ^= ~0;  /* invert = exclusive or with all 1's */
                   1102:   changed = TRUE;
                   1103:   XSetState (d, gc, 1L, 0L, GXinvert, invertplane);
                   1104:   XFillRectangle (d, grid_window, gc, 0, 0,
                   1105:     image.width*square_size+1, image.height*square_size+1);
                   1106:   RepaintGridLines (e_Invert);
                   1107:   RepaintRaster();
                   1108:   RepaintRasterInverted();
                   1109:   }
                   1110: 
                   1111: 
                   1112: void InvertArea() {
                   1113:   int x1, y1, x2, y2;
                   1114:   register int x, y;
                   1115:   if (AskUserForArea (&x1, &y1, &x2, &y2))
                   1116:     return;
                   1117:   for (x=x1;x<=x2;x++)
                   1118:     for (y=y1;y<=y2;y++)
                   1119:       InvertRasterBit (raster, x, y);
                   1120:   ExThroughRectangle (x1, y1, x2, y2);  /* wipe out X-outs */
                   1121:   XSetState (d, gc, 1L, 0L, GXinvert, invertplane);
                   1122:   XFillRectangle (d, grid_window, gc, x1*square_size+1,  y1*square_size+1,
                   1123:     (x2-x1+1)*square_size-1,  (y2-y1+1)*square_size-1);
                   1124:   RepaintGridLinesPartially (x1, y1, x2+1, y2+1, e_Invert, FALSE);
                   1125:   changed = TRUE;
                   1126:   RepaintRaster();
                   1127:   RepaintRasterInverted();
                   1128:   x1_square_exed_through = y1_square_exed_through = OUT_OF_RANGE;
                   1129:   x2_square_exed_through = y2_square_exed_through = OUT_OF_RANGE;
                   1130:   }
                   1131: 
                   1132: 
                   1133: void CopyOrMoveArea (what)
                   1134:   {
                   1135:   int x1, y1, x2, y2;
                   1136:   int x1dest, y1dest;
                   1137:   if (AskUserForArea (&x1, &y1, &x2, &y2))
                   1138:     return;
                   1139:   if (AskUserForDest (&x1dest, &y1dest, x2-x1+1, y2-y1+1))
                   1140:     /* button released outside grid */
                   1141:     ExThroughRectangle (x1_square_exed_through, y1_square_exed_through,
                   1142:       x2_square_exed_through, y2_square_exed_through);
                   1143:   else {
                   1144:     register int xsrc, ysrc, xdest, ydest;
                   1145:     register char *new_raster = malloc (raster_length);
                   1146: 
                   1147:     if (x_hot_spot != OUT_OF_RANGE)
                   1148:        HighlightHotSpot();  /* actually UNhighlight it */
                   1149: 
                   1150:     /* copy whole raster to new raster */
                   1151:     bcopy (raster, new_raster, raster_length);
                   1152:     
                   1153:     if (what == MOVE)
                   1154:       /* clear source bits in new raster.  this is VERY inefficient.
                   1155:          sure wish we had BitBlt available in user memory! */
                   1156:       for (xsrc = x1; xsrc <= x2; xsrc++)
                   1157:         for (ysrc = y1; ysrc <= y2; ysrc++)
                   1158:          SetRasterBit (new_raster, xsrc, ysrc, 0);
                   1159: 
                   1160:     /* copy old source bits to new destination. this is VERY inefficient.
                   1161:        sure wish we had BitBlt available in user memory! */
                   1162: 
                   1163:     for (xsrc = x1, xdest = x1dest;
                   1164:       xsrc<=x2 && xdest < image.width; xsrc++, xdest++) 
                   1165:         for (ysrc = y1, ydest = y1dest;
                   1166:           ysrc<=y2 && ydest < image.height; ysrc++, ydest++)
                   1167:            if (what == OVERLAY) {
                   1168:                if (GetRasterBit (raster, xsrc, ysrc))
                   1169:                    SetRasterBit (new_raster, xdest, ydest, 1);
                   1170:            } else
                   1171:                SetRasterBit (new_raster, xdest, ydest, 
                   1172:                  GetRasterBit (raster, xsrc, ysrc));
                   1173: 
                   1174:     free (raster);
                   1175:     raster = image.data = new_raster;
                   1176:     if (what == MOVE)
                   1177:        RepaintRectangles (x1, y1, x2, y2, x1dest, y1dest);
                   1178:     else {
                   1179:        ExThroughRectangle (x1_square_exed_through, y1_square_exed_through,
                   1180:            x2_square_exed_through, y2_square_exed_through);
                   1181:        RefillGridPartially (x1dest, y1dest, xdest-1, ydest-1, TRUE);
                   1182:        }
                   1183: 
                   1184:     if (x_hot_spot != OUT_OF_RANGE)
                   1185:        HighlightHotSpot();  /* put the hot spot back on the screen */
                   1186: 
                   1187:     RepaintRaster();
                   1188:     RepaintRasterInverted();
                   1189:     changed = TRUE;
                   1190:     x1_square_plus_through = y1_square_plus_through = OUT_OF_RANGE;
                   1191:     x2_square_plus_through = y2_square_plus_through = OUT_OF_RANGE;
                   1192:     }
                   1193:     
                   1194:   x1_square_exed_through = y1_square_exed_through = OUT_OF_RANGE;
                   1195:   x2_square_exed_through = y2_square_exed_through = OUT_OF_RANGE;
                   1196:   }
                   1197: 
                   1198: #define MAX(a,b)       (((a) > (b)) ? (a) : (b))
                   1199: #define MIN(a,b)       (((a) < (b)) ? (a) : (b))
                   1200: #define ABS(a)         (((a) >= 0) ? (a) : -(a))
                   1201: #define CheckSetRasterBit(r,x,y,c)     \
                   1202:        if ((x) >= 0 && (x) < image.width && (y) >= 0 && (y) < image.height) \
                   1203:                SetRasterBit(r, x, y, c)
                   1204: 
                   1205: void Line ()
                   1206: {
                   1207:        int     i, x1, y1, x2, y2;
                   1208:        double  dx, dy, x, y, diff;
                   1209: 
                   1210:        if (AskUserForPoint(&x1, &y1, 0))
                   1211:                return;
                   1212:        if (AskUserForPoint(&x2, &y2, 1))
                   1213:                return;
                   1214:        ExThroughRectangle (x1_square_exed_through, y1_square_exed_through,
                   1215:                x2_square_exed_through, y2_square_exed_through);
                   1216:        PlusThroughRectangle (x1_square_plus_through, y1_square_plus_through,
                   1217:                x2_square_plus_through, y2_square_plus_through);
                   1218: 
                   1219:        dx = x2 - x1;
                   1220:        dy = y2 - y1;
                   1221:        x = x1 + 0.5;
                   1222:        y = y1 + 0.5;
                   1223:        diff = MAX(ABS(dx), ABS(dy));
                   1224:        if (diff == 0)
                   1225:                diff = 0.9;
                   1226:        dx /= diff;
                   1227:        dy /= diff;
                   1228:        for (i = 0; i <= (int)diff; i++) {
                   1229:                SetRasterBit(raster, (int)x, (int)y, 1);
                   1230:                x += dx;
                   1231:                y += dy;
                   1232:        }
                   1233:        RefillGridPartially(MIN(x1, x2), MIN(y1, y2), MAX(x1, x2), MAX(y1, y2),
                   1234:                FALSE);
                   1235:        changed = TRUE;
                   1236:        x1_square_exed_through = y1_square_exed_through = OUT_OF_RANGE;
                   1237:        x2_square_exed_through = y2_square_exed_through = OUT_OF_RANGE;
                   1238:        x1_square_plus_through = y1_square_plus_through = OUT_OF_RANGE;
                   1239:        x2_square_plus_through = y2_square_plus_through = OUT_OF_RANGE;
                   1240:        RepaintRaster();
                   1241:        RepaintRasterInverted();
                   1242: }
                   1243: 
                   1244: #include <math.h>
                   1245: 
                   1246: void Circle(filled)
                   1247: {
                   1248:        int     i, j, x, x1, y1, x2, y2, dx, dy;
                   1249:        double  rad, half;
                   1250: 
                   1251:        if (AskUserForPoint(&x1, &y1, 0))
                   1252:                return;
                   1253:        if (AskUserForPoint(&x2, &y2, 1))
                   1254:                return;
                   1255:        ExThroughRectangle (x1_square_exed_through, y1_square_exed_through,
                   1256:                x2_square_exed_through, y2_square_exed_through);
                   1257:        PlusThroughRectangle (x1_square_plus_through, y1_square_plus_through,
                   1258:                x2_square_plus_through, y2_square_plus_through);
                   1259: 
                   1260:        dx = x2 - x1;
                   1261:        dy = y2 - y1;
                   1262:        rad = sqrt((double)(dx * dx + dy * dy)) + 0.5;
                   1263:        if (filled)
                   1264:                for (i = 0; i <= (int)rad; i++) {
                   1265:                        x = sqrt(rad * rad - i * i);
                   1266:                        for (j = x1 - x; j <= x1 + x; j++) {
                   1267:                                CheckSetRasterBit(raster, j, y1 - i, 1);
                   1268:                                CheckSetRasterBit(raster, j, y1 + i, 1);
                   1269:                        }
                   1270:                }
                   1271:        else {
                   1272:                half = rad * sqrt(2.0)/2;
                   1273:                for (i = 0; i <= (int)half; i++) {
                   1274:                        x = sqrt(rad * rad - i * i);
                   1275:                        CheckSetRasterBit(raster, x1 - x, y1 - i, 1);
                   1276:                        CheckSetRasterBit(raster, x1 - x, y1 + i, 1);
                   1277:                        CheckSetRasterBit(raster, x1 + x, y1 - i, 1);
                   1278:                        CheckSetRasterBit(raster, x1 + x, y1 + i, 1);
                   1279:                        CheckSetRasterBit(raster, x1 - i, y1 - x, 1);
                   1280:                        CheckSetRasterBit(raster, x1 - i, y1 + x, 1);
                   1281:                        CheckSetRasterBit(raster, x1 + i, y1 - x, 1);
                   1282:                        CheckSetRasterBit(raster, x1 + i, y1 + x, 1);
                   1283:                }
                   1284:        }
                   1285:        RefillGridPartially(x1-(int)rad, y1-(int)rad, 
                   1286:                x1+(int)rad, y1+(int)rad, FALSE);
                   1287:        changed = TRUE;
                   1288:        x1_square_exed_through = y1_square_exed_through = OUT_OF_RANGE;
                   1289:        x2_square_exed_through = y2_square_exed_through = OUT_OF_RANGE;
                   1290:        x1_square_plus_through = y1_square_plus_through = OUT_OF_RANGE;
                   1291:        x2_square_plus_through = y2_square_plus_through = OUT_OF_RANGE;
                   1292:        RepaintRaster();
                   1293:        RepaintRasterInverted();
                   1294: }
                   1295: 
                   1296: void ClearHotSpot() {
                   1297:     if (x_hot_spot == OUT_OF_RANGE)
                   1298:        return;
                   1299:     HighlightHotSpot();  /* UNhighlight existing hot spot */
                   1300:     x_hot_spot = y_hot_spot = OUT_OF_RANGE;
                   1301:     changed = TRUE;
                   1302:     }
                   1303: 
                   1304: void SetHotSpot() {
                   1305:     XDefineCursor (d, outer_window, dot);
                   1306:     XSelectInput (d, outer_window,
                   1307:        ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
                   1308:        /* so that we can detect button pressed outside grid */
                   1309: 
                   1310:     while (TRUE) {
                   1311:        XEvent event;
                   1312:        int x1, y1;
                   1313:        XNextEvent (d, &event);
                   1314:        switch (event.type) {
                   1315: 
                   1316:            case ButtonPress:
                   1317:            case MotionNotify:
                   1318:                if ((event.xany.window == grid_window)
                   1319:                && !WhatSquare (&event, &x1, &y1)
                   1320:                && (x_hot_spot != x1 || y_hot_spot != y1)) {
                   1321: 
                   1322:                    /* UNhighlight old hot spot */
                   1323:                    if (x_hot_spot != OUT_OF_RANGE)
                   1324:                        HighlightHotSpot();  
                   1325: 
                   1326:                    x_hot_spot = x1;
                   1327:                    y_hot_spot = y1;
                   1328: 
                   1329:                    /* highlight new hot spot */
                   1330:                    HighlightHotSpot();
                   1331: 
                   1332:                    changed = TRUE;
                   1333:                    }
                   1334:                break;  /* keep looping until button is released */
                   1335: 
                   1336:            case ButtonRelease:
                   1337:                XDefineCursor (d, outer_window, cross);
                   1338:                XSelectInput (d, outer_window, StructureNotifyMask);
                   1339:                return;
                   1340: 
                   1341:            case Expose:
                   1342:            case ConfigureNotify:
                   1343:                ProcessEvent (&event);
                   1344:                break;
                   1345:                
                   1346:            default:
                   1347:                break;  /* just throw it away */
                   1348:                
                   1349:            }
                   1350:        }
                   1351:     }
                   1352: 
                   1353: RepaintRectangles (x1, y1, x2, y2, x3, y3)
                   1354:     int x1, y1; /* first rectangle's top & left */
                   1355:     int x2, y2; /* first rectangle's bottom & right */
                   1356:     int x3, y3; /* second rectangle's top & left */
                   1357:     {
                   1358:     int x4 = x3 + (x2 - x1);  /* second rectangle's right edge */
                   1359:     int y4 = y3 + (y2 - y1);  /* second rectangle's bottom edge */
                   1360: 
                   1361:     if (x4 >= image.width) x4 = image.width-1;
                   1362:     if (y4 >= image.width) y4 = image.height-1;
                   1363: 
                   1364:     /* if first rectangle is right of second, swap "first" and "second" variables */
                   1365:     if (x1 > x3)
                   1366:        {int temp;
                   1367: #define swap(a,b) {temp = a; a = b; b = temp;}
                   1368:        swap (x1, x3); swap (y1, y3); swap (x2, x4); swap (y2, y4);
                   1369: #undef swap
                   1370:        }
                   1371:     
                   1372:     RefillGridPartially (x1, y1, x2, y2, TRUE);
                   1373: 
                   1374:     if ((x3 > x2) || (max (y1, y3) > min (y2, y4)))
                   1375:        /* rectangles don't overlap */
                   1376:        RefillGridPartially (x3, y3, x4, y4, TRUE);
                   1377: 
                   1378:     else if (y1 < y3) {
                   1379:        /* second rectangle is below & right of first */
                   1380:        RefillGridPartially (x2+1, y3, x4, y2, TRUE);
                   1381:        RefillGridPartially (x3, y2+1, x4, y4, TRUE);
                   1382:        }
                   1383: 
                   1384:     else {
                   1385:        /* second rectangle is above & right of first */
                   1386:        RefillGridPartially (x3, y3, x4, y1-1, TRUE);
                   1387:        RefillGridPartially (x2+1, y1, x4, y4, TRUE);
                   1388:        }
                   1389:     }
                   1390: 
                   1391: 
                   1392: /* AskUserForArea returns FALSE if the user has defined a valid area,
                   1393:    TRUE if the user hasn't (e.g. by clicking outside grid) */
                   1394: 
                   1395: boolean AskUserForArea(px1, py1, px2, py2) 
                   1396:   int *px1, *py1, *px2, *py2;
                   1397:   {
                   1398:   XEvent event;
                   1399:   int x1, y1, x2, y2;
                   1400:   boolean result;
                   1401: 
                   1402:   XSelectInput (d, outer_window, ButtonPressMask | StructureNotifyMask);
                   1403:     /* so that we can detect button pressed outside grid */
                   1404: 
                   1405:   XDefineCursor (d, outer_window, upper_left);
                   1406:   
                   1407:   while (TRUE) {
                   1408:     XNextEvent (d, &event);
                   1409:     switch (event.type) {
                   1410:       case ButtonPress:
                   1411:         if ((event.xany.window != grid_window)
                   1412:        || WhatSquare (&event, &x1, &y1)) {
                   1413:           XDefineCursor (d, outer_window, cross);
                   1414:          XSelectInput (d, outer_window, StructureNotifyMask);
                   1415:           return (TRUE);
                   1416:          }
                   1417:        goto out1;  /* get out of the loop */
                   1418:       case Expose:
                   1419:       case ConfigureNotify:
                   1420:        ProcessEvent (&event);
                   1421:        break;
                   1422:       default:
                   1423:        break;  /* just throw it away */
                   1424:       }
                   1425:     }
                   1426: 
                   1427:   out1:
                   1428:   ExThroughSquare (x1, y1);
                   1429:   FlushLineBuffer();
                   1430:   x1_square_exed_through = x2_square_exed_through = x2 = x1;
                   1431:   y1_square_exed_through = y2_square_exed_through = y2 = y1;
                   1432:   XDefineCursor (d, outer_window, lower_right);
                   1433:   
                   1434:   while (TRUE) {
                   1435:     XNextEvent (d, &event);
                   1436:     switch (event.type) {
                   1437:       case ButtonPress:
                   1438:        result = TRUE;
                   1439:        goto out2;
                   1440:       case Expose:
                   1441:       case ConfigureNotify:
                   1442:        ProcessEvent (&event);
                   1443:        break;
                   1444:       case MotionNotify:
                   1445:       case ButtonRelease: {
                   1446:         int x, y;
                   1447:        result = (event.xany.window != grid_window)
                   1448:             || WhatSquare (&event, &x, &y)  /* mouse outside grid? */
                   1449:            || (x < x1) || (y < y1);
                   1450:        if (result) {
                   1451:          ExThroughRectangle (x1+1, y1, x2, y2);
                   1452:          ExThroughRectangle (x1, y1+1, x1, y2);
                   1453:          x2 = x2_square_exed_through = x1;
                   1454:          y2 = y2_square_exed_through = y1;
                   1455:          }
                   1456:        else if ((x == x2) && (y == y2))
                   1457:          ; /* both dimensions the same; do nothing */
                   1458:        else if ((x > x2) == (y > y2)) {
                   1459:          /* both dimensions bigger or smaller */
                   1460:          ExThroughRectangle (min(x2,x)+1, y1, max(x2,x), max(y2,y));
                   1461:          ExThroughRectangle (x1, min(y2,y)+1, min(x2,x), max(y2,y));
                   1462:          x2 = x2_square_exed_through = x;
                   1463:          y2 = y2_square_exed_through = y;
                   1464:          }
                   1465:         else {
                   1466:          /* one dimension bigger, the other smaller */
                   1467:          ExThroughRectangle (min(x2,x)+1, y1, max(x2,x), min(y2,y));
                   1468:          ExThroughRectangle (x1, min(y2,y)+1, min(x2,x), max(y2,y));
                   1469:          x2 = x2_square_exed_through = x;
                   1470:          y2 = y2_square_exed_through = y;
                   1471:          }
                   1472:        if (event.type == ButtonRelease)
                   1473:          goto out2;
                   1474:        break;
                   1475:        }
                   1476:       default:
                   1477:        break;  /* just throw it away */
                   1478:       }
                   1479:     }
                   1480: 
                   1481:   out2:
                   1482:   XSelectInput (d, outer_window, StructureNotifyMask);
                   1483:   XDefineCursor (d, outer_window, cross);
                   1484:   if (result) {
                   1485:     /* no area properly selected; remove X-outs from display */
                   1486:     ExThroughRectangle (x1, y1, x2, y2);
                   1487:     x1_square_exed_through = y1_square_exed_through = OUT_OF_RANGE;
                   1488:     x2_square_exed_through = y2_square_exed_through = OUT_OF_RANGE;
                   1489:     }
                   1490:   else {
                   1491:     *px1 = x1;
                   1492:     *px2 = x2;
                   1493:     *py1 = y1;
                   1494:     *py2 = y2;
                   1495:     }
                   1496:   return (result);
                   1497:   }
                   1498: 
                   1499: boolean AskUserForDest (px1, py1, width, height)
                   1500:   int *px1, *py1;
                   1501:   int width, height;
                   1502:   {
                   1503:   XEvent event;
                   1504:   boolean result;
                   1505:   XSelectInput (d, outer_window,
                   1506:     ButtonPressMask | ButtonReleaseMask | StructureNotifyMask);
                   1507:     /* so we can detect button action outside grid */
                   1508:   XDefineCursor (d, outer_window, upper_left);
                   1509: 
                   1510:   while (TRUE) {
                   1511:     XNextEvent (d, &event);
                   1512:     switch (event.type) {
                   1513: 
                   1514:       case Expose:
                   1515:       case ConfigureNotify:
                   1516:         ProcessEvent (&event);
                   1517:        break;
                   1518: 
                   1519:       case ButtonPress:
                   1520:       case MotionNotify: {
                   1521:        int x1_new, y1_new;
                   1522:        boolean this_window = (event.xany.window == grid_window)
                   1523:          && !WhatSquare (&event, &x1_new, &y1_new);
                   1524: 
                   1525:        if (this_window && (x1_new == *px1) && (y1_new == *py1))
                   1526:          break;  /* mouse is still in same square as before; do nothing */
                   1527: 
                   1528:         if (x1_square_plus_through != OUT_OF_RANGE)
                   1529:           PlusThroughRectangle (x1_square_plus_through, y1_square_plus_through,
                   1530:               x2_square_plus_through, y2_square_plus_through);
                   1531: 
                   1532:        if (this_window) {
                   1533:          *px1 = x1_square_plus_through = x1_new;
                   1534:          *py1 = y1_square_plus_through = y1_new;
                   1535:          x2_square_plus_through = min (x1_new + width, image.width) - 1;
                   1536:          y2_square_plus_through = min (y1_new + height, image.height) - 1;
                   1537:           PlusThroughRectangle (x1_square_plus_through, y1_square_plus_through,
                   1538:               x2_square_plus_through, y2_square_plus_through);
                   1539:          }
                   1540:        else {
                   1541:           x1_square_plus_through = y1_square_plus_through = OUT_OF_RANGE;
                   1542:           x2_square_plus_through = y2_square_plus_through = OUT_OF_RANGE;
                   1543:          *px1 = *py1 = OUT_OF_RANGE;
                   1544:          }
                   1545:         break;
                   1546:        }
                   1547: 
                   1548:       case ButtonRelease: {
                   1549:         result = (event.xany.window != grid_window)
                   1550:           || WhatSquare (&event, px1, py1);
                   1551:        goto out;
                   1552:        }
                   1553: 
                   1554:       default:
                   1555:         break;  /* throw it away */
                   1556:       }
                   1557:     }
                   1558: 
                   1559:     out:
                   1560:     if (result) {
                   1561:       /* button released outside grid */
                   1562:       if (x1_square_plus_through != OUT_OF_RANGE)
                   1563:         PlusThroughRectangle (x1_square_plus_through, y1_square_plus_through,
                   1564:           x2_square_plus_through, y2_square_plus_through);
                   1565:       x1_square_plus_through = y1_square_plus_through = OUT_OF_RANGE;
                   1566:       x2_square_plus_through = y2_square_plus_through = OUT_OF_RANGE;
                   1567:       }
                   1568: 
                   1569:     XSelectInput (d, outer_window, StructureNotifyMask);
                   1570:     XDefineCursor (d, outer_window, cross);
                   1571:     return (result);
                   1572:     }
                   1573: 
                   1574: boolean AskUserForPoint (xp, yp, plus)
                   1575:   int *xp, *yp;
                   1576:   {
                   1577:   XEvent event;
                   1578:   boolean this_window;
                   1579: 
                   1580:   XSelectInput (d, outer_window, ButtonPressMask | StructureNotifyMask);
                   1581:     /* so we can detect button action outside grid */
                   1582:   XDefineCursor (d, outer_window, dot);
                   1583: 
                   1584:   while (TRUE) {
                   1585:     XNextEvent (d, &event);
                   1586:     switch (event.type) {
                   1587: 
                   1588:       case Expose:
                   1589:       case ConfigureNotify:
                   1590:         ProcessEvent (&event);
                   1591:        break;
                   1592: 
                   1593:       case ButtonRelease:
                   1594:        this_window = (event.xany.window == grid_window)
                   1595:                              && !WhatSquare (&event, xp, yp);
                   1596:        if (this_window) {
                   1597:                if (plus) {
                   1598:                        PlusThroughRectangle (*xp, *yp, *xp, *yp);
                   1599:                        x1_square_plus_through = x2_square_plus_through = *xp;
                   1600:                        y1_square_plus_through = y2_square_plus_through = *yp;
                   1601:                } else {
                   1602:                        ExThroughRectangle (*xp, *yp, *xp, *yp);
                   1603:                        x1_square_exed_through = x2_square_exed_through = *xp;
                   1604:                        y1_square_exed_through = y2_square_exed_through = *yp;
                   1605:                }
                   1606:        }
                   1607:        goto out;
                   1608:         break;
                   1609: 
                   1610:       default:
                   1611:         break;  /* throw it away */
                   1612:       }
                   1613:     }
                   1614: 
                   1615:     out:
                   1616:     XSelectInput (d, outer_window, StructureNotifyMask);
                   1617:     XDefineCursor (d, outer_window, cross);
                   1618:     return (!this_window);
                   1619:     }
                   1620: 
                   1621: DialogInputHandler (event)
                   1622:   XEvent *event;
                   1623:   {
                   1624:   if (event->type == Expose || event->type == ConfigureNotify)
                   1625:        ProcessEvent (event);
                   1626:   }
                   1627: 
                   1628: enum output_error {e_rename, e_write};
                   1629: 
                   1630: /* WriteOutput returns TRUE if output successfully written, FALSE if not */
                   1631: 
                   1632: boolean WriteOutput() {
                   1633:   FILE *file;
                   1634:   if (!changed)
                   1635:     return (TRUE);
                   1636:   if (rename (filename, backup_filename) && errno != ENOENT)
                   1637:     return (HandleOutputError(e_rename));
                   1638:   file = fopen (filename, "w+");
                   1639:   if (!file)
                   1640:     return (HandleOutputError(e_write));
                   1641:   WriteOutputToFile (file);
                   1642:   fclose (file);
                   1643:   changed = FALSE;
                   1644:   return (TRUE);
                   1645:   }
                   1646: 
                   1647: 
                   1648: /* HandleOutputError returns TRUE if alternate file written, FALSE if not */
                   1649: 
                   1650: int HandleOutputError(e)
                   1651:   enum output_error e;
                   1652:   {
                   1653:   int result;
                   1654:   static char *strings[] = {"Yes", "No"};
                   1655:   char msg1[120], msg2[120];
                   1656:   char *tmp_filename;
                   1657:   if (e == e_rename)
                   1658:     sprintf (msg1, "Can't rename %s to %s -- %s",
                   1659:       filename, backup_filename, sys_errlist[errno]);
                   1660:   else
                   1661:     sprintf (msg1, "Can't write on file %s -- %s",
                   1662:       filename, sys_errlist[errno]);
                   1663:   tmp_filename = TmpFileName (filename);
                   1664:   sprintf (msg2, "Should I write output to file %s?", tmp_filename);
                   1665:   result = dialog (outer_window, font,
                   1666:      msg1, msg2, strings, 2, DialogInputHandler);
                   1667: 
                   1668:   if (result == 0)  /* "yes" */ {
                   1669:     filename = tmp_filename;
                   1670:     free (backup_filename);
                   1671:     backup_filename = BackupName (filename);
                   1672:     return (WriteOutput());
                   1673:     }
                   1674:   else {  /* "no" */
                   1675:     free (tmp_filename);
                   1676:     return (FALSE);
                   1677:     }
                   1678:   }
                   1679: 
                   1680:     
                   1681: void Quit() {
                   1682:   if (changed) {
                   1683:     int result;
                   1684:     static char *strings[3] = {"Yes", "No", "Cancel"};
                   1685:     result = dialog (outer_window, font,
                   1686:       "Save changes before quitting?", "", strings, 3, DialogInputHandler);
                   1687:       
                   1688:     switch (result) {
                   1689:       case 0:     /* "yes" */
                   1690:        if (WriteOutput())
                   1691:          exit(0);
                   1692:        else return;
                   1693:       case 1:    /* "no" */
                   1694:         exit(0);
                   1695:       default:  /* "cancel" */
                   1696:        return;
                   1697:       }
                   1698:     }
                   1699: 
                   1700:   exit(0);
                   1701:   }
                   1702: 
                   1703: HighlightHotSpot() {
                   1704:   /* Draw a diamond in the hot spot square */
                   1705:   /* x1 and y1 are the center of the hot spot square */
                   1706:   register int x1 = x_hot_spot*square_size + square_size/2;
                   1707:   register int y1 = y_hot_spot*square_size + square_size/2;
                   1708:   register int radius = square_size/6;
                   1709:   XPoint points[5];
                   1710:   points[0].x = points[2].x = points[4].x = x1;
                   1711:   points[1].x = x1 + radius;
                   1712:   points[3].x = x1 - radius;
                   1713:   points[0].y = points[4].y = y1 + radius;
                   1714:   points[1].y = points[3].y = y1;
                   1715:   points[2].y = y1 - radius;
                   1716:   XSetLineAttributes (d, gc, 0, LineSolid, CapNotLast, JoinMiter);
                   1717:   XSetState (d, gc, 1L, 0L, GXinvert, highlightplane);
                   1718:   XDrawLines (d, grid_window, gc, points, 5, CoordModeOrigin);
                   1719:   }
                   1720: 
                   1721: ExThroughRectangle (x1, y1, x2, y2)
                   1722:   register int x1, y1, x2, y2;
                   1723:   {
                   1724:   register int x, y;
                   1725:   for (x=x1;x<=x2;x++)
                   1726:     for (y=y1;y<=y2;y++)
                   1727:       ExThroughSquare (x, y);
                   1728:   FlushLineBuffer();
                   1729:   }
                   1730: 
                   1731: 
                   1732: ExThroughSquare (x, y)
                   1733:   register int x, y;
                   1734:   {
                   1735:   register int x1 = x*square_size;
                   1736:   register int y1 = y*square_size;
                   1737:   LineIntoBuffer (x1+1, y1+1,
                   1738:     x1+square_size, y1+square_size);
                   1739:   LineIntoBuffer (x1+square_size-1, y1+1,
                   1740:     x1, y1+square_size);
                   1741:   }
                   1742: 
                   1743: 
                   1744: PlusThroughRectangle (x1, y1, x2, y2)
                   1745:   register int x1, y1, x2, y2;
                   1746:   {
                   1747:   register int x, y;
                   1748:   for (x=x1;x<=x2;x++)
                   1749:     for (y=y1;y<=y2;y++)
                   1750:       PlusThroughSquare (x, y);
                   1751:   FlushLineBuffer();
                   1752:   }
                   1753: 
                   1754: PlusThroughSquare (x, y)
                   1755:   register int x, y;
                   1756:   {
                   1757:   register int x1 = x*square_size;
                   1758:   register int y1 = y*square_size;
                   1759:   LineIntoBuffer (x1+square_size/2, y1+1,
                   1760:     x1+square_size/2, y1+square_size);
                   1761:   LineIntoBuffer (x1+1, y1+square_size/2,
                   1762:     x1+square_size, y1+square_size/2);
                   1763:   }
                   1764: 
                   1765: 
                   1766: #define BUFFER_MAXLENGTH 100
                   1767: static XSegment buffer [BUFFER_MAXLENGTH];
                   1768: static int buffer_length = 0;
                   1769: 
                   1770: LineIntoBuffer (x1, y1, x2, y2) {
                   1771:   register XSegment *seg = &buffer[buffer_length];
                   1772:   seg->x1 = x1;
                   1773:   seg->y1 = y1;
                   1774:   seg->x2 = x2;
                   1775:   seg->y2 = y2;
                   1776:   if (++buffer_length == BUFFER_MAXLENGTH)
                   1777:     FlushLineBuffer();
                   1778:   }
                   1779:   
                   1780: FlushLineBuffer () {
                   1781:   XSetLineAttributes (d, gc, 0, LineSolid, CapNotLast, JoinMiter);
                   1782:   XSetState (d, gc, 1L, 0L, GXinvert, highlightplane);
                   1783:   XDrawSegments (d, grid_window, gc, buffer, buffer_length);
                   1784:   buffer_length = 0;
                   1785:   }
                   1786: 
                   1787: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.