Annotation of micropolis/src/sim/w_tk.c, revision 1.1.1.1

1.1       root        1: /* w_tk.c
                      2:  *
                      3:  * Micropolis, Unix Version.  This game was released for the Unix platform
                      4:  * in or about 1990 and has been modified for inclusion in the One Laptop
                      5:  * Per Child program.  Copyright (C) 1989 - 2007 Electronic Arts Inc.  If
                      6:  * you need assistance with this program, you may contact:
                      7:  *   http://wiki.laptop.org/go/Micropolis  or email  [email protected].
                      8:  * 
                      9:  * This program is free software: you can redistribute it and/or modify
                     10:  * it under the terms of the GNU General Public License as published by
                     11:  * the Free Software Foundation, either version 3 of the License, or (at
                     12:  * your option) any later version.
                     13:  * 
                     14:  * This program is distributed in the hope that it will be useful, but
                     15:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     17:  * General Public License for more details.  You should have received a
                     18:  * copy of the GNU General Public License along with this program.  If
                     19:  * not, see <http://www.gnu.org/licenses/>.
                     20:  * 
                     21:  *             ADDITIONAL TERMS per GNU GPL Section 7
                     22:  * 
                     23:  * No trademark or publicity rights are granted.  This license does NOT
                     24:  * give you any right, title or interest in the trademark SimCity or any
                     25:  * other Electronic Arts trademark.  You may not distribute any
                     26:  * modification of this program using the trademark SimCity or claim any
                     27:  * affliation or association with Electronic Arts Inc. or its employees.
                     28:  * 
                     29:  * Any propagation or conveyance of this program must include this
                     30:  * copyright notice and these terms.
                     31:  * 
                     32:  * If you convey this program (or any modifications of it) and assume
                     33:  * contractual liability for the program to recipients of it, you agree
                     34:  * to indemnify Electronic Arts for any liability that those contractual
                     35:  * assumptions impose on Electronic Arts.
                     36:  * 
                     37:  * You may not misrepresent the origins of this program; modified
                     38:  * versions of the program must be marked as such and not identified as
                     39:  * the original program.
                     40:  * 
                     41:  * This disclaimer supplements the one included in the General Public
                     42:  * License.  TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
                     43:  * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
                     44:  * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK.  THE ENTIRE RISK OF
                     45:  * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU.  ELECTRONIC ARTS
                     46:  * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
                     47:  * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
                     48:  * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
                     49:  * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
                     50:  * USAGE, OR TRADE PRACTICE.  ELECTRONIC ARTS DOES NOT WARRANT AGAINST
                     51:  * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
                     52:  * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
                     53:  * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
                     54:  * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
                     55:  * CORRECTED.  NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
                     56:  * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY.  SOME
                     57:  * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
                     58:  * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
                     59:  * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
                     60:  * NOT APPLY TO YOU.
                     61:  */
                     62: #include "sim.h"
                     63: 
                     64: #ifdef MSDOS
                     65: #define filename2UNIX(name)    \
                     66:     {   char *p; for (p = name; *p; p++) if (*p == '\\') *p = '/'; }
                     67: #else
                     68: #define filename2UNIX(name)    /**/
                     69: #endif
                     70: 
                     71: 
                     72: Tcl_Interp *tk_mainInterp = NULL;
                     73: Tcl_CmdBuf buffer = NULL;
                     74: Tk_TimerToken sim_timer_token = 0;
                     75: int sim_timer_idle = 0;
                     76: int sim_timer_set = 0;
                     77: Tk_Window MainWindow;
                     78: int UpdateDelayed = 0;
                     79: int AutoScrollEdge = 16;
                     80: int AutoScrollStep = 16;
                     81: int AutoScrollDelay = 10;
                     82: Tk_TimerToken earthquake_timer_token;
                     83: int earthquake_timer_set = 0;
                     84: int earthquake_delay = 3000;
                     85: int PerformanceTiming;
                     86: double FlushTime;
                     87: int NeedRest = 0;
                     88: 
                     89: 
                     90: #define DEF_VIEW_FONT  "-Adobe-Helvetica-Bold-R-Normal-*-140-*"
                     91: 
                     92: Tk_ConfigSpec TileViewConfigSpecs[] = {
                     93:     {TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,
                     94:        DEF_VIEW_FONT, Tk_Offset(SimView, fontPtr), 0},
                     95:     {TK_CONFIG_STRING, "-messagevar", (char *) NULL, (char *) NULL,
                     96:        NULL, Tk_Offset(SimView, message_var), 0},
                     97:     {TK_CONFIG_PIXELS, "-width", "width", "Width",
                     98:        0, Tk_Offset(SimView, width), 0},
                     99:     {TK_CONFIG_PIXELS, "-height", "height", "Height",
                    100:        0, Tk_Offset(SimView, height), 0},
                    101:     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
                    102:        (char *) NULL, 0, 0}
                    103: };
                    104: 
                    105: 
                    106: int TileViewCmd(CLIENT_ARGS);
                    107: int ConfigureTileView(Tcl_Interp *interp, SimView *view,
                    108:                      int argc, char **argv, int flags);
                    109: static void TileViewEventProc(ClientData clientData, XEvent *eventPtr);
                    110: static void DestroyTileView(ClientData clientData);
                    111: 
                    112: int ConfigureSimGraph(Tcl_Interp *interp, SimGraph *graph,
                    113:                      int argc, char **argv, int flags);
                    114: 
                    115: static void MicropolisTimerProc(ClientData clientData);
                    116: 
                    117: int SimCmd(CLIENT_ARGS);
                    118: int DoEditorCmd(CLIENT_ARGS);
                    119: int DoMapCmd(CLIENT_ARGS);
                    120: int GraphViewCmd(CLIENT_ARGS);
                    121: int DoGraphCmd(CLIENT_ARGS);
                    122: int SpriteCmd(CLIENT_ARGS);
                    123: extern int Tk_PieMenuCmd();
                    124: extern int Tk_IntervalCmd();
                    125: 
                    126: 
                    127: int
                    128: TileViewCmd(CLIENT_ARGS)
                    129: {
                    130:   Tk_Window tkwin = (Tk_Window) clientData;
                    131:   SimView *view;
                    132:   int viewclass;
                    133: 
                    134:   if (argc < 2) {
                    135:     Tcl_AppendResult(interp, "wrong # args:  should be \"",
                    136:                     argv[0], " pathName ?options?\"", (char *) NULL);
                    137:     return TCL_ERROR;
                    138:   }
                    139: 
                    140:   if (strcmp(argv[0], "editorview") == 0)
                    141:     viewclass = Editor_Class;
                    142:   else if (strcmp(argv[0], "mapview") == 0)
                    143:     viewclass = Map_Class;
                    144:   else {
                    145:     return TCL_ERROR;
                    146:   }
                    147: 
                    148:   tkwin = Tk_CreateWindowFromPath(interp, tkwin,
                    149:                                  argv[1], (char *) NULL);
                    150:   if (tkwin == NULL) {
                    151:     return TCL_ERROR;
                    152:   }
                    153: 
                    154:   view = (SimView *)ckalloc(sizeof (SimView));
                    155: 
                    156:   view->tkwin = tkwin;
                    157:   view->interp = interp;
                    158:   view->flags = 0;
                    159: 
                    160:   if (viewclass == Editor_Class) {
                    161:     Tk_SetClass(view->tkwin, "EditorView");
                    162: 
                    163:     Tk_CreateEventHandler(view->tkwin,
                    164:                          VisibilityChangeMask |
                    165:                          ExposureMask |
                    166:                          StructureNotifyMask |
                    167:                          EnterWindowMask |
                    168:                          LeaveWindowMask |
                    169:                          PointerMotionMask,
                    170:                          TileViewEventProc, (ClientData) view);
                    171:     Tcl_CreateCommand(interp, Tk_PathName(view->tkwin),
                    172:                      DoEditorCmd, (ClientData) view, (void (*)()) NULL);
                    173:   } else {
                    174:     Tk_SetClass(view->tkwin, "MapView");
                    175: 
                    176:     Tk_CreateEventHandler(view->tkwin,
                    177:                          VisibilityChangeMask |
                    178:                          ExposureMask |
                    179:                          StructureNotifyMask /* |
                    180:                          EnterWindowMask |
                    181:                          LeaveWindowMask |
                    182:                          PointerMotionMask */ ,
                    183:                          TileViewEventProc, (ClientData) view);
                    184:     Tcl_CreateCommand(interp, Tk_PathName(view->tkwin),
                    185:                      DoMapCmd, (ClientData) view, (void (*)()) NULL);
                    186:   }
                    187: 
                    188:   Tk_MakeWindowExist(view->tkwin);
                    189: 
                    190:   if (getenv("XSYNCHRONIZE") != NULL) {
                    191:     XSynchronize(Tk_Display(tkwin), 1);
                    192:   }
                    193: 
                    194:   if (viewclass == Editor_Class) {
                    195:     InitNewView(view, "MicropolisEditor", Editor_Class, EDITOR_W, EDITOR_H);
                    196:     DoNewEditor(view);
                    197:   } else {
                    198:     InitNewView(view, "MicropolisMap", Map_Class, MAP_W, MAP_H);
                    199:     DoNewMap(view);
                    200:   }
                    201: 
                    202:   if (ConfigureTileView(interp, view, argc-2, argv+2, 0) != TCL_OK) {
                    203:     /* XXX: destroy view */
                    204:     Tk_DestroyWindow(view->tkwin);
                    205:     return TCL_ERROR;
                    206:   }
                    207: 
                    208:   switch (view->class) {
                    209:   case Editor_Class:
                    210:     break;
                    211:   case Map_Class:
                    212:     view->invalid = 1;
                    213:     view->update = 1;
                    214:     DoUpdateMap(view);
                    215:     break;
                    216:   }
                    217: 
                    218:   interp->result = Tk_PathName(view->tkwin);
                    219:   return TCL_OK;
                    220: }
                    221: 
                    222: 
                    223: int
                    224: ConfigureTileView(Tcl_Interp *interp, SimView *view,
                    225:             int argc, char **argv, int flags)
                    226: {
                    227:   if (Tk_ConfigureWidget(interp, view->tkwin, TileViewConfigSpecs,
                    228:                         argc, argv, (char *) view, flags) != TCL_OK) {
                    229:     return TCL_ERROR;
                    230:   }
                    231: 
                    232:   if (view->class == Map_Class) {
                    233:     Tk_GeometryRequest(view->tkwin, MAP_W, MAP_H);
                    234:   } else {
                    235:     if (view->width || view->height) {
                    236:       Tk_GeometryRequest(view->tkwin, view->width, view->height);
                    237:     }
                    238:   }
                    239:   EventuallyRedrawView(view);
                    240:   return TCL_OK;
                    241: }
                    242: 
                    243: 
                    244: InvalidateMaps()
                    245: {
                    246:   SimView *view;
                    247: 
                    248: //fprintf(stderr, "InvalidateMaps\n");
                    249:   for (view = sim->map; view != NULL; view = view->next) {
                    250:     view->invalid = 1;
                    251:     view->skip = 0;
                    252:     EventuallyRedrawView(view);
                    253:   }
                    254:   sim_skip = 0;
                    255: }
                    256: 
                    257: 
                    258: InvalidateEditors()
                    259: {
                    260:   SimView *view;
                    261: 
                    262: //fprintf(stderr, "InvalidateEditors\n");
                    263:   for (view = sim->editor; view != NULL; view = view->next) {
                    264:     view->invalid = 1;
                    265:     view->skip = 0;
                    266:     EventuallyRedrawView(view);
                    267:   }
                    268:   sim_skip = 0;
                    269: }
                    270: 
                    271: 
                    272: RedrawMaps()
                    273: {
                    274:   SimView *view;
                    275: 
                    276: //fprintf(stderr, "RedrawMaps\n");
                    277: 
                    278:   for (view = sim->map; view != NULL; view = view->next) {
                    279:     view->skip = 0;
                    280:     EventuallyRedrawView(view);
                    281:   }
                    282:   sim_skip = 0;
                    283: }
                    284: 
                    285: 
                    286: RedrawEditors()
                    287: {
                    288:   SimView *view;
                    289: 
                    290: //fprintf(stderr, "RedrawEditors\n");
                    291: 
                    292:   for (view = sim->editor; view != NULL; view = view->next) {
                    293:     view->skip = 0;
                    294:     EventuallyRedrawView(view);
                    295:   }
                    296:   sim_skip = 0;
                    297: }
                    298: 
                    299: 
                    300: static void
                    301: DisplayTileView(ClientData clientData)
                    302: {
                    303:   SimView *view = (SimView *) clientData;
                    304:   Tk_Window tkwin = view->tkwin;
                    305:   Pixmap pm = None;
                    306:   Drawable d;
                    307: 
                    308:   view->flags &= ~VIEW_REDRAW_PENDING;
                    309:   if (view->visible && (tkwin != NULL) && Tk_IsMapped(tkwin)) {
                    310:     switch (view->class) {
                    311:     case Editor_Class:
                    312:       view->skip = 0;
                    313:       view->update = 1;
                    314:       DoUpdateEditor(view);
                    315:       break;
                    316:     case Map_Class:
                    317: //fprintf(stderr, "DisplayTileView\n");
                    318:       view->skip = 0;
                    319:       view->update = 1;
                    320:       DoUpdateMap(view);
                    321:       break;
                    322:     }
                    323:   }
                    324: }
                    325: 
                    326: 
                    327: /* comefrom:
                    328:     ConfigureTileView
                    329:     TileViewEventProc expose configure motion
                    330:     InvalidateMaps
                    331:     EraserTo
                    332:     DoSetMapState
                    333:     AddInk
                    334:     EraserTo
                    335:  */
                    336: 
                    337: EventuallyRedrawView(SimView *view)
                    338: {
                    339:   if (!(view->flags & VIEW_REDRAW_PENDING)) {
                    340:     Tk_DoWhenIdle(DisplayTileView, (ClientData) view);
                    341:     view->flags |= VIEW_REDRAW_PENDING;
                    342:   }
                    343: 
                    344: }
                    345: 
                    346: 
                    347: CancelRedrawView(SimView *view)
                    348: {
                    349:   if (view->flags & VIEW_REDRAW_PENDING) {
                    350:     Tk_CancelIdleCall(DisplayTileView, (ClientData) view);
                    351:   }
                    352:   view->flags &= ~VIEW_REDRAW_PENDING;
                    353: }
                    354: 
                    355: 
                    356: static void
                    357: TileAutoScrollProc(ClientData clientData)
                    358: {
                    359:   SimView *view = (SimView *)clientData;
                    360:   char buf[256];
                    361: 
                    362:   if (view->tool_mode != 0) {
                    363:     int dx = 0, dy = 0;
                    364:     int result, root_x, root_y, x, y;
                    365:     unsigned int key_buttons;
                    366:     Window root, child;
                    367: 
                    368:     XQueryPointer(Tk_Display(view->tkwin), Tk_WindowId(view->tkwin),
                    369:                  &root, &child, &root_x, &root_y, &x, &y, &key_buttons);
                    370: 
                    371:     if (x < AutoScrollEdge)
                    372:       dx = -AutoScrollStep;
                    373:     else if (x > (view->w_width - AutoScrollEdge))
                    374:       dx = AutoScrollStep;
                    375:     if (y < AutoScrollEdge)
                    376:       dy = -AutoScrollStep;
                    377:     else if (y > (view->w_height - AutoScrollEdge))
                    378:       dy = AutoScrollStep;
                    379: 
                    380:     if (dx || dy) {
                    381:       int px = view->pan_x, py = view->pan_y;
                    382: 
                    383:       if (view->tool_mode == -1) {
                    384:        dx = -dx; dy = -dy;
                    385:       }
                    386: 
                    387:       DoPanBy(view, dx, dy);
                    388:       view->tool_x += view->pan_x - px;
                    389:       view->tool_y += view->pan_y - py;
                    390:       view->auto_scroll_token =
                    391:        Tk_CreateTimerHandler(AutoScrollDelay, TileAutoScrollProc,
                    392:                              (ClientData) view);
                    393: 
                    394:       sprintf(buf, "UIDidPan %s %d %d", Tk_PathName(view->tkwin), x, y);
                    395:       Eval(buf);
                    396:     }
                    397:   }
                    398: }
                    399: 
                    400: 
                    401: static void
                    402: TileViewEventProc(ClientData clientData, XEvent *eventPtr)
                    403: {
                    404:   SimView *view = (SimView *) clientData;
                    405: 
                    406:   if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
                    407:     view->visible = 1;
                    408:     EventuallyRedrawView(view);
                    409:   } else if (eventPtr->type == MapNotify) {
                    410:     view->visible = 1;
                    411:   } else if (eventPtr->type == UnmapNotify) {
                    412:     view->visible = 0;
                    413:   } else if (eventPtr->type == VisibilityNotify) {
                    414:     if (eventPtr->xvisibility.state == VisibilityFullyObscured)
                    415:       view->visible = 0;
                    416:     else
                    417:       view->visible = 1;
                    418:   } else if (eventPtr->type == ConfigureNotify) {
                    419:     if (view->class == Editor_Class)
                    420:       DoResizeView(view,
                    421:                   eventPtr->xconfigure.width,
                    422:                   eventPtr->xconfigure.height);
                    423:     EventuallyRedrawView(view);
                    424:   } else if (eventPtr->type == DestroyNotify) {
                    425:     Tcl_DeleteCommand(view->interp, Tk_PathName(view->tkwin));
                    426:     view->tkwin = NULL;
                    427:     CancelRedrawView(view);
                    428:     Tk_EventuallyFree((ClientData) view, DestroyTileView);
                    429:   } else if ((view->class == Editor_Class) &&
                    430:             (view->show_me != 0) &&
                    431:             ((eventPtr->type == EnterNotify) ||
                    432:              (eventPtr->type == LeaveNotify) ||
                    433:              (eventPtr->type == MotionNotify))) {
                    434:     int last_x = view->tool_x, last_y = view->tool_y,
                    435:         last_showing = view->tool_showing;
                    436:     int x, y, showing, autoscroll;
                    437: 
                    438:     if (eventPtr->type == EnterNotify) {
                    439:       showing = 1;
                    440:       x = eventPtr->xcrossing.x; y = eventPtr->xcrossing.y;
                    441:     } else if (eventPtr->type == LeaveNotify) {
                    442:       showing = 0;
                    443:       x = eventPtr->xcrossing.x; y = eventPtr->xcrossing.y;
                    444:     } else {
                    445:       showing = 1;
                    446:       x = eventPtr->xmotion.x; y = eventPtr->xmotion.y;
                    447:     }
                    448: 
                    449:     if (view->tool_mode != 0) {
                    450: 
                    451:       if ((x < AutoScrollEdge) ||
                    452:          (x > (view->w_width - AutoScrollEdge)) ||
                    453:          (y < AutoScrollEdge) ||
                    454:          (y > (view->w_height - AutoScrollEdge))) {
                    455:        if (!view->auto_scroll_token) {
                    456:          view->auto_scroll_token =
                    457:            Tk_CreateTimerHandler(AutoScrollDelay, TileAutoScrollProc,
                    458:                                  (ClientData) view);
                    459:        }
                    460:       } else {
                    461:        if (view->auto_scroll_token) {
                    462:          Tk_DeleteTimerHandler(view->auto_scroll_token);
                    463:          view->auto_scroll_token = 0;
                    464:        }
                    465:       }
                    466:     }
                    467: 
                    468:     ViewToPixelCoords(view, x, y, &x, &y);
                    469:     view->tool_showing = showing;
                    470: 
                    471:     if (view->tool_mode != -1) {
                    472:       view->tool_x = x; view->tool_y = y;
                    473:     }
                    474: 
                    475: /* XXX: redraw all views showing cursor */
                    476: /* XXX: also, make sure switching tools works w/out moving */
                    477:     if (((view->tool_showing != last_showing) ||
                    478:         (view->tool_x != last_x) ||
                    479:         (view->tool_y != last_y))) {
                    480: #if 1
                    481:       EventuallyRedrawView(view);
                    482: #else
                    483:       RedrawEditors();
                    484: #endif
                    485:     }
                    486:   }
                    487: }
                    488: 
                    489: 
                    490: static void
                    491: DestroyTileView(ClientData clientData)
                    492: {
                    493:   SimView *view = (SimView *) clientData;
                    494: 
                    495:   DestroyView(view);
                    496: }
                    497: 
                    498: 
                    499: void
                    500: StdinProc(ClientData clientData, int mask)
                    501: {
                    502:   char line[200];
                    503:   static int gotPartial = 0;
                    504:   char *cmd;
                    505:   int result;
                    506:   
                    507:   if (mask & TK_READABLE) {
                    508:     if (fgets(line, 200, stdin) == NULL) {
                    509:       if (!gotPartial) {
                    510:        if (sim_tty) {
                    511:          sim_exit(0); // Just sets tkMustExit and ExitReturn
                    512:          return;
                    513:        } else {
                    514:          Tk_DeleteFileHandler(0);
                    515:        }
                    516:        return;
                    517:       } else {
                    518:        line[0] = 0;
                    519:       }
                    520:     }
                    521:     cmd = Tcl_AssembleCmd(buffer, line);
                    522:     if (cmd == NULL) {
                    523:       gotPartial = 1;
                    524:       return;
                    525:     }
                    526:     gotPartial = 0;
                    527:     result = Tcl_RecordAndEval(tk_mainInterp, cmd, 0);
                    528:     if (*tk_mainInterp->result != 0) {
                    529:       if ((result != TCL_OK) || sim_tty) {
                    530:        printf("%s\n", tk_mainInterp->result);
                    531:       }
                    532:     }
                    533:     if (sim_tty) {
                    534:       printf("sim:\n");
                    535:       fflush(stdout);
                    536:     }
                    537:   }
                    538: }
                    539: 
                    540: 
                    541: static void
                    542: StructureProc(ClientData clientData, XEvent *eventPtr)
                    543: {
                    544:   if (eventPtr->type == DestroyNotify) {
                    545:     MainWindow = NULL;
                    546:   }
                    547: }
                    548: 
                    549: 
                    550: static void
                    551: DelayedMap(ClientData clientData)
                    552: {
                    553:   while (Tk_DoOneEvent(TK_IDLE_EVENTS) != 0) {
                    554:     /* Empty loop body. */
                    555:   }
                    556:   if (MainWindow == NULL) {
                    557:     return;
                    558:   }
                    559:   Tk_MapWindow(MainWindow);
                    560: }
                    561: 
                    562: 
                    563: DidStopPan(SimView *view)
                    564: {
                    565:   char buf[256];
                    566:   sprintf(buf, "UIDidStopPan %s", Tk_PathName(view->tkwin));
                    567:        
                    568:   Eval(buf);
                    569: }
                    570: 
                    571: 
                    572: static void
                    573: MicropolisTimerProc(ClientData clientData)
                    574: {
                    575:   sim_timer_token = NULL;
                    576:   sim_timer_set = 0;
                    577: 
                    578:   if (NeedRest > 0) {
                    579:     NeedRest--;
                    580:   }
                    581: 
                    582:   if (SimSpeed) {
                    583:     sim_loop(1);
                    584:     StartMicropolisTimer();
                    585:   } else {
                    586:     StopMicropolisTimer();
                    587:   }
                    588: }
                    589: 
                    590: 
                    591: void
                    592: ReallyStartMicropolisTimer(ClientData clientData)
                    593: {
                    594:   int delay = sim_delay;
                    595:   XDisplay *xd = XDisplays;
                    596: 
                    597:   StopMicropolisTimer();
                    598: 
                    599:   while (xd != NULL) {
                    600:     if ((NeedRest > 0) ||
                    601:        ShakeNow ||
                    602:        (xd->tkDisplay->buttonWinPtr != NULL) ||
                    603:        (xd->tkDisplay->grabWinPtr != NULL)) {
                    604:       if (ShakeNow || NeedRest) {
                    605:        if (delay < 50000) delay = 50000;
                    606:       } else {
                    607:       }
                    608:       break;
                    609:     }
                    610:     xd = xd->next;
                    611:   }
                    612: 
                    613:   sim_timer_token =
                    614:     Tk_CreateMicroTimerHandler(
                    615:       0,
                    616:       delay,
                    617:       MicropolisTimerProc,
                    618:       (ClientData)0);
                    619: 
                    620:   sim_timer_set = 1;
                    621: }
                    622: 
                    623: 
                    624: StartMicropolisTimer()
                    625: {
                    626:   if (sim_timer_idle == 0) {
                    627:     sim_timer_idle = 1;
                    628:     Tk_DoWhenIdle(
                    629:       ReallyStartMicropolisTimer,
                    630:       NULL);
                    631:   }
                    632: }
                    633: 
                    634: 
                    635: StopMicropolisTimer()
                    636: {
                    637:   if (sim_timer_idle != 0) {
                    638:     sim_timer_idle = 0;
                    639:     Tk_CancelIdleCall(
                    640:       ReallyStartMicropolisTimer,
                    641:       NULL);
                    642:   }
                    643: 
                    644:   if (sim_timer_set) {
                    645:     if (sim_timer_token != 0) {
                    646:       Tk_DeleteTimerHandler(sim_timer_token);
                    647:       sim_timer_token = 0;
                    648:     }
                    649:     sim_timer_set = 0;
                    650:   }
                    651: }
                    652: 
                    653: 
                    654: FixMicropolisTimer()
                    655: {
                    656:   if (sim_timer_set) {
                    657:     StartMicropolisTimer(NULL);
                    658:   }
                    659: }
                    660: 
                    661: 
                    662: static void
                    663: DelayedUpdate(ClientData clientData)
                    664: {
                    665: //fprintf(stderr, "DelayedUpdate\n");
                    666:   UpdateDelayed = 0;
                    667:   sim_skip = 0;
                    668:   sim_update();
                    669: }
                    670: 
                    671: 
                    672: Kick()
                    673: {
                    674:   if (!UpdateDelayed) {
                    675:     UpdateDelayed = 1;
                    676:     Tk_DoWhenIdle(DelayedUpdate, (ClientData) NULL);
                    677:   }
                    678: }
                    679: 
                    680: 
                    681: void
                    682: StopEarthquake()
                    683: {
                    684:   ShakeNow = 0;
                    685:   if (earthquake_timer_set) {
                    686:     Tk_DeleteTimerHandler(earthquake_timer_token);
                    687:   }
                    688:   earthquake_timer_set = 0;
                    689: }
                    690: 
                    691: 
                    692: DoEarthQuake(void)
                    693: {
                    694:   MakeSound("city", "Explosion-Low");
                    695:   Eval("UIEarthQuake");
                    696:   ShakeNow++;
                    697:   if (earthquake_timer_set) {
                    698:     Tk_DeleteTimerHandler(earthquake_timer_token);
                    699:   }
                    700:   Tk_CreateTimerHandler(earthquake_delay, (void (*)())StopEarthquake, (ClientData) 0);
                    701:   earthquake_timer_set = 1;
                    702: }
                    703: 
                    704: 
                    705: StopToolkit()
                    706: {
                    707:   if (tk_mainInterp != NULL) {
                    708:     Eval("catch {DoStopMicropolis}");
                    709:   }
                    710: }
                    711: 
                    712: 
                    713: Eval(char *buf)
                    714: {
                    715:   int result = Tcl_Eval(tk_mainInterp, buf, 0, (char **) NULL);
                    716:   if (result != TCL_OK) {
                    717:     char *errorinfo = Tcl_GetVar(tk_mainInterp, "errorInfo",
                    718:                                 TCL_GLOBAL_ONLY);
                    719:     if (errorinfo == NULL) errorinfo = "<no backtrace>";
                    720:     fprintf(stderr, "Micropolis: error in TCL code: %s\n%s\n",
                    721:            tk_mainInterp->result, errorinfo);
                    722:   }
                    723:   return (result);
                    724: }
                    725: 
                    726: 
                    727: tk_main()
                    728: {
                    729:   char *p, *msg;
                    730:   char buf[20];
                    731:   char initCmd[256];
                    732:   Tk_3DBorder border;
                    733: 
                    734:   tk_mainInterp = Tcl_CreateExtendedInterp();
                    735: 
                    736: #if 0
                    737:   /* XXX: Figure out Extended TCL */
                    738:   tclAppName     = "Wish";
                    739:   tclAppLongname = "Wish - Tk Shell";
                    740:   tclAppVersion  = TK_VERSION;
                    741:   Tcl_ShellEnvInit (interp, TCLSH_ABORT_STARTUP_ERR,
                    742:                     name,
                    743:                     0, NULL,           /* argv var already set  */
                    744:                     fileName == NULL,  /* interactive?          */
                    745:                     NULL);             /* Standard default file */
                    746: #endif
                    747: 
                    748:   MainWindow = Tk_CreateMainWindow(tk_mainInterp, FirstDisplay, "Micropolis");
                    749:   if (MainWindow == NULL) {
                    750:     fprintf(stderr, "%s\n", tk_mainInterp->result);
                    751:     sim_really_exit(1); // Just sets tkMustExit and ExitReturn
                    752:   }
                    753:   Tk_SetClass(MainWindow, "Tk");
                    754:   Tk_CreateEventHandler(MainWindow, StructureNotifyMask,
                    755:                        StructureProc, (ClientData) NULL);
                    756: /*  Tk_DoWhenIdle(DelayedMap, (ClientData) NULL); */
                    757: 
                    758:   Tk_GeometryRequest(MainWindow, 256, 256);
                    759:   border = Tk_Get3DBorder(tk_mainInterp, MainWindow, None, "gray75");
                    760:   if (border == NULL) {
                    761:     Tcl_SetResult(tk_mainInterp, (char *) NULL, TCL_STATIC);
                    762:     Tk_SetWindowBackground(MainWindow,
                    763:                           WhitePixelOfScreen(Tk_Screen(MainWindow)));
                    764:   } else {
                    765:     Tk_SetBackgroundFromBorder(MainWindow, border);
                    766:   }
                    767:   XSetForeground(Tk_Display(MainWindow),
                    768:                 DefaultGCOfScreen(Tk_Screen(MainWindow)),
                    769:                 BlackPixelOfScreen(Tk_Screen(MainWindow)));
                    770: 
                    771:   sim_command_init();
                    772:   map_command_init();
                    773:   editor_command_init();
                    774:   graph_command_init();
                    775:   date_command_init();
                    776:   sprite_command_init();
                    777: 
                    778: #ifdef CAM
                    779:   cam_command_init();
                    780: #endif
                    781: 
                    782:   Tcl_CreateCommand(tk_mainInterp, "piemenu", Tk_PieMenuCmd,
                    783:                    (ClientData)MainWindow, (void (*)()) NULL);
                    784:   Tcl_CreateCommand(tk_mainInterp, "interval", Tk_IntervalCmd,
                    785:                    (ClientData)MainWindow, (void (*)()) NULL);
                    786: 
                    787:   sim = MakeNewSim();
                    788: 
                    789:   sprintf(initCmd, "source %s/micropolis.tcl", ResourceDir);
                    790:   filename2UNIX(initCmd);
                    791:   if (Eval(initCmd)) {
                    792:     sim_exit(1); // Just sets tkMustExit and ExitReturn
                    793:     goto bail;
                    794:   }
                    795: 
                    796:   sim_init();
                    797: 
                    798:   buffer = Tcl_CreateCmdBuf();
                    799: 
                    800:   if (sim_tty) {
                    801:     Tk_CreateFileHandler(0, TK_READABLE, StdinProc, (ClientData) 0);
                    802:   }
                    803: 
                    804:   { char buf[1024];
                    805: 
                    806:     sprintf(buf, "UIStartMicropolis {%s} {%s} {%s}",
                    807:            HomeDir, ResourceDir, HostName);
                    808:     filename2UNIX(buf);
                    809:     if (Eval(buf) != TCL_OK) {
                    810:       sim_exit(1); // Just sets tkMustExit and ExitReturn
                    811:       goto bail;
                    812:     }
                    813:   }
                    814: 
                    815:   if (sim_tty) {
                    816:     printf("sim:\n");
                    817:   }
                    818:   fflush(stdout);
                    819: 
                    820:   Tk_MainLoop();
                    821: 
                    822:   sim_exit(0); // Just sets tkMustExit and ExitReturn
                    823: 
                    824:  bail:
                    825: 
                    826:   if (buffer != NULL) {
                    827:     Tcl_DeleteCmdBuf(buffer);
                    828:   }
                    829: 
                    830:   Tcl_DeleteInterp(tk_mainInterp);
                    831: }
                    832: 

unix.superglobalmegacorp.com

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