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

Defined functions

AskUserForArea defined in line 1425; used 3 times
AskUserForDest defined in line 1532; used 1 times
BackupName defined in line 937; used 3 times
ClearHotSpot defined in line 1325; used 2 times
ClearOrSetAll defined in line 1160; used 3 times
ClearOrSetArea defined in line 1183; used 3 times
CopyOrMoveArea defined in line 1261; used 3 times
DialogInputHandler defined in line 1609; used 2 times
DimensionsFromFile defined in line 860; used 1 times
ExThroughRectangle defined in line 1718; used 12 times
ExThroughSquare defined in line 1729; used 2 times
FlushLineBuffer defined in line 1778; used 4 times
GetRasterBit defined in line 774; used 2 times
HandleExposure defined in line 373; used 2 times
HandleOutputError defined in line 1641; used 2 times
HighlightHotSpot defined in line 1699; used 13 times
InitialValuesFromFile defined in line 894; used 1 times
InvertAll defined in line 1212; used 2 times
InvertArea defined in line 1233; used 2 times
InvertCommandWindow defined in line 610; used 4 times
InvertRasterBit defined in line 796; used 3 times
InvertSquare defined in line 759; used 2 times
LayoutStage1 defined in line 989; used 1 times
LayoutStage2 defined in line 1091; used 2 times
LineIntoBuffer defined in line 1767; used 4 times
MouseMovedEventQueued defined in line 532; used 1 times
OuterWindowDims defined in line 1148; used 2 times
PaintSquare defined in line 746; used 5 times
PlusThroughRectangle defined in line 1741; used 5 times
PlusThroughSquare defined in line 1751; used 1 times
ProcessCommandButtonEvent defined in line 558; used 1 times
ProcessEvent defined in line 338; used 6 times
ProcessEventReally defined in line 354; used 3 times
ProcessGridWindowEvent defined in line 408; used 1 times
ProcessOuterWindowEvent defined in line 540; used 1 times
Quit defined in line 1674; used 2 times
RefillGrid defined in line 724; used 1 times
RefillGridPartially defined in line 731; used 9 times
RepaintGridLines defined in line 643; used 3 times
RepaintGridLinesPartially defined in line 649; used 4 times
RepaintRaster defined in line 806; used 8 times
RepaintRasterInverted defined in line 822; used 8 times
RepaintRectangles defined in line 1383; used 1 times
SetHotSpot defined in line 1333; used 2 times
SetRasterBit defined in line 784; used 7 times
SetUp defined in line 139; used 1 times
StringEndsWith defined in line 971; used 5 times
StripName defined in line 920; used 2 times
TmpFileName defined in line 948; used 1 times
WhatSquare defined in line 629; used 7 times
WriteOutput defined in line 1623; used 4 times
WriteOutputToFile defined in line 838; used 1 times
ffs defined in line 1788; used 1 times
main defined in line 126; never used

Defined variables

DottedPattern defined in line 71; used 1 times
InverseDottedPattern defined in line 75; used 1 times
background defined in line 50; used 21 times
backmap defined in line 51; used 8 times
backup_filename defined in line 67; used 5 times
border defined in line 52; used 12 times
borderwidth defined in line 53; used 5 times
buffer defined in line 1764; used 7 times
buffer_length defined in line 1765; used 9 times
commands defined in line 92; used 35 times
cross defined in line 65; used 6 times
dot defined in line 65; used 2 times
filename defined in line 66; used 19 times
font defined in line 63; used 6 times
fontInfo defined in line 64; used 7 times
foreground defined in line 49; used 14 times
frames defined in line 97; used 14 times
grid_window defined in line 61; used 17 times
highlightplane defined in line 55; used 6 times
invertplane defined in line 54; used 12 times
lower_right defined in line 65; used 2 times
mousepix defined in line 56; used 6 times
outer_frame defined in line 97; used 12 times
outer_window defined in line 61; used 27 times
progname defined in line 70; used 18 times
raster defined in line 59; used 32 times
raster_invert_window defined in line 62; used 3 times
raster_length defined in line 60; used 9 times
raster_window defined in line 62; used 3 times
rcsid_bitmap_c defined in line 6; never used
square_size defined in line 96; used 60 times
squares_high defined in line 58; used 25 times
squares_wide defined in line 57; used 29 times
stripped_name defined in line 68; used 6 times
upper_left defined in line 65; used 3 times
x1_square_exed_through defined in line 104; used 11 times
x1_square_plus_through defined in line 110; used 13 times
x2_square_exed_through defined in line 106; used 12 times
x2_square_plus_through defined in line 112; used 9 times
x_hot_spot defined in line 116; used 21 times
y1_square_exed_through defined in line 105; used 9 times
y1_square_plus_through defined in line 111; used 9 times
y2_square_exed_through defined in line 107; used 12 times
y2_square_plus_through defined in line 113; used 9 times
y_hot_spot defined in line 117; used 15 times

Defined struct's

command_data defined in line 82; used 8 times

Defined enum's

RepaintGridType defined in line 122; used 4 times
output_error defined in line 1619; used 2 times

Defined macros

AROUND_RASTER_MARGIN defined in line 26; used 4 times
BOTTOM_MARGIN defined in line 25; used 2 times
BUFFER_MAXLENGTH defined in line 1763; used 2 times
DEFAULT_SQUARE_SIZE defined in line 31; used 1 times
DISCARD_IT defined in line 336; used 2 times
FALSE defined in line 36; used 12 times
GRID_TO_COMMAND_MARGIN defined in line 27; used 3 times
LEFT_MARGIN defined in line 24; used 3 times
MIN_SQUARE_SIZE defined in line 30; used 1 times
N_COMMANDS defined in line 81; used 17 times
OUT_OF_RANGE defined in line 37; used 44 times
PROCESS_IT defined in line 335; used 4 times
RIGHT_MARGIN defined in line 28; used 2 times
TOP_MARGIN defined in line 23; used 4 times
TRUE defined in line 35; used 31 times
bit defined in line 33; used 5 times
boolean defined in line 34; used 15 times
max defined in line 40; used 10 times
min defined in line 39; used 17 times
swap defined in line 1397; used 5 times
this_event defined in line 430; used 5 times
Last modified: 1986-02-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5806
Valid CSS Valid XHTML 1.0 Strict