Annotation of 43BSD/contrib/X/bitmap/bitmap.c, revision 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.