Annotation of 43BSD/contrib/X/bitmap/bitmap.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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