home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / tk3.3b1 / tkMain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-09  |  10.8 KB  |  416 lines

  1. /* 
  2.  * main.c --
  3.  *
  4.  *    This file contains the main program for "wish", a windowing
  5.  *    shell based on Tk and Tcl.  It also provides a template that
  6.  *    can be used as the basis for main programs for other Tk
  7.  *    applications.
  8.  *
  9.  * Copyright (c) 1990-1993 The Regents of the University of California.
  10.  * All rights reserved.
  11.  *
  12.  * Permission is hereby granted, without written agreement and without
  13.  * license or royalty fees, to use, copy, modify, and distribute this
  14.  * software and its documentation for any purpose, provided that the
  15.  * above copyright notice and the following two paragraphs appear in
  16.  * all copies of this software.
  17.  * 
  18.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  19.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  20.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  21.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22.  *
  23.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  24.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  25.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  26.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  27.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  28.  */
  29.  
  30. #ifndef lint
  31. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkMain.c,v 1.82 93/07/09 09:52:37 ouster Exp $ SPRITE (Berkeley)";
  32. #endif
  33.  
  34. #include "tkConfig.h"
  35. #include "tkInt.h"
  36.  
  37. /*
  38.  * Declarations for library procedures:
  39.  */
  40.  
  41. extern int isatty();
  42.  
  43. /*
  44.  * Global variables used by the main program:
  45.  */
  46.  
  47. static Tk_Window w;        /* The main window for the application.  If
  48.                  * NULL then the application no longer
  49.                  * exists. */
  50. static Tcl_Interp *interp;    /* Interpreter for this application. */
  51. static Tcl_DString command;    /* Used to assemble lines of terminal input
  52.                  * into Tcl commands. */
  53. static int tty;            /* Non-zero means standard input is a
  54.                  * terminal-like device.  Zero means it's
  55.                  * a file. */
  56.  
  57. /*
  58.  * Command-line options:
  59.  */
  60.  
  61. int synchronize = 0;
  62. char *fileName = NULL;
  63. char *name = NULL;
  64. char *display = NULL;
  65. char *geometry = NULL;
  66.  
  67. Tk_ArgvInfo argTable[] = {
  68.     {"-file", TK_ARGV_STRING, (char *) NULL, (char *) &fileName,
  69.     "File from which to read commands"},
  70.     {"-geometry", TK_ARGV_STRING, (char *) NULL, (char *) &geometry,
  71.     "Initial geometry for window"},
  72.     {"-display", TK_ARGV_STRING, (char *) NULL, (char *) &display,
  73.     "Display to use"},
  74.     {"-name", TK_ARGV_STRING, (char *) NULL, (char *) &name,
  75.     "Name to use for application"},
  76.     {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
  77.     "Use synchronous mode for display server"},
  78.     {(char *) NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
  79.     (char *) NULL}
  80. };
  81.  
  82. /*
  83.  * Declaration for Tcl command procedure to create demo widget.  This
  84.  * procedure is only invoked if SQUARE_DEMO is defined.
  85.  */
  86.  
  87. extern int SquareCmd _ANSI_ARGS_((ClientData clientData,
  88.     Tcl_Interp *interp, int argc, char *argv[]));
  89.  
  90. /*
  91.  * Forward declarations for procedures defined later in this file:
  92.  */
  93.  
  94. static void        DelayedMap _ANSI_ARGS_((ClientData clientData));
  95. static void        StdinProc _ANSI_ARGS_((ClientData clientData,
  96.                 int mask));
  97. static void        StructureProc _ANSI_ARGS_((ClientData clientData,
  98.                 XEvent *eventPtr));
  99.  
  100. /*
  101.  *----------------------------------------------------------------------
  102.  *
  103.  * main --
  104.  *
  105.  *    Main program for Wish.
  106.  *
  107.  * Results:
  108.  *    None. This procedure never returns (it exits the process when
  109.  *    it's done
  110.  *
  111.  * Side effects:
  112.  *    This procedure initializes the wish world and then starts
  113.  *    interpreting commands;  almost anything could happen, depending
  114.  *    on the script being interpreted.
  115.  *
  116.  *----------------------------------------------------------------------
  117.  */
  118.  
  119. int
  120. main(argc, argv)
  121.     int argc;                /* Number of arguments. */
  122.     char **argv;            /* Array of argument strings. */
  123. {
  124.     char *args, *p, *msg;
  125.     char buf[20];
  126.     int result;
  127.     Tk_3DBorder border;
  128.  
  129.     interp = Tcl_CreateInterp();
  130. #ifdef TCL_MEM_DEBUG
  131.     Tcl_InitMemory(interp);
  132. #endif
  133.  
  134.     /*
  135.      * Parse command-line arguments.
  136.      */
  137.  
  138.     if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv, argTable, 0)
  139.         != TCL_OK) {
  140.     fprintf(stderr, "%s\n", interp->result);
  141.     exit(1);
  142.     }
  143.     if (name == NULL) {
  144.     if (fileName != NULL) {
  145.         p = fileName;
  146.     } else {
  147.         p = argv[0];
  148.     }
  149.     name = strrchr(p, '/');
  150.     if (name != NULL) {
  151.         name++;
  152.     } else {
  153.         name = p;
  154.     }
  155.     }
  156.  
  157.     /*
  158.      * Initialize the Tk application and arrange to map the main window
  159.      * after the startup script has been executed, if any.  This way
  160.      * the script can withdraw the window so it isn't ever mapped
  161.      * at all.
  162.      */
  163.  
  164.     w = Tk_CreateMainWindow(interp, display, name);
  165.     if (w == NULL) {
  166.     fprintf(stderr, "%s\n", interp->result);
  167.     exit(1);
  168.     }
  169.     Tk_SetClass(w, "Tk");
  170.     Tk_CreateEventHandler(w, StructureNotifyMask, StructureProc,
  171.         (ClientData) NULL);
  172.     Tk_DoWhenIdle(DelayedMap, (ClientData) NULL);
  173.     if (synchronize) {
  174.     XSynchronize(Tk_Display(w), True);
  175.     }
  176.     Tk_GeometryRequest(w, 200, 200);
  177.     border = Tk_Get3DBorder(interp, w, None, "#ffe4c4");
  178.     if (border == NULL) {
  179.     Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
  180.     Tk_SetWindowBackground(w, WhitePixelOfScreen(Tk_Screen(w)));
  181.     } else {
  182.     Tk_SetBackgroundFromBorder(w, border);
  183.     }
  184.     XSetForeground(Tk_Display(w), DefaultGCOfScreen(Tk_Screen(w)),
  185.         BlackPixelOfScreen(Tk_Screen(w)));
  186.  
  187.     /*
  188.      * Make command-line arguments available in the Tcl variables "argc"
  189.      * and "argv".  Also set the "geometry" variable from the geometry
  190.      * specified on the command line.
  191.      */
  192.  
  193.     args = Tcl_Merge(argc-1, argv+1);
  194.     Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
  195.     ckfree(args);
  196.     sprintf(buf, "%d", argc-1);
  197.     Tcl_SetVar(interp, "argc", buf, TCL_GLOBAL_ONLY);
  198.     Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0],
  199.         TCL_GLOBAL_ONLY);
  200.     if (geometry != NULL) {
  201.     Tcl_SetVar(interp, "geometry", geometry, TCL_GLOBAL_ONLY);
  202.     }
  203.  
  204.     /*
  205.      * Add a few application-specific commands to the application's
  206.      * interpreter.
  207.      */
  208.  
  209. #ifdef SQUARE_DEMO
  210.     Tcl_CreateCommand(interp, "square", SquareCmd, (ClientData) w,
  211.         (void (*)()) NULL);
  212. #endif
  213.  
  214.     /*
  215.      * Invoke application-specific initialization.
  216.      */
  217.  
  218.     if (Tcl_AppInit(interp) != TCL_OK) {
  219.     fprintf(stderr, "%s\n", interp->result);
  220.     exit(1);
  221.     }
  222.  
  223.     /*
  224.      * Invoke the script specified on the command line, if any.
  225.      */
  226.  
  227.     tty = isatty(0);
  228.     if (fileName != NULL) {
  229.     result = Tcl_VarEval(interp, "source ", fileName, (char *) NULL);
  230.     if (result != TCL_OK) {
  231.         goto error;
  232.     }
  233.     tty = 0;
  234.     } else {
  235.     /*
  236.      * Commands will come from standard input.  Set up a handler
  237.      * to receive those characters and print a prompt if the input
  238.      * device is a terminal.
  239.      */
  240.  
  241.     Tk_CreateFileHandler(0, TK_READABLE, StdinProc, (ClientData) 0);
  242.     if (tty) {
  243.         printf("wish: ");
  244.     }
  245.     }
  246.     fflush(stdout);
  247.     Tcl_DStringInit(&command);
  248.     (void) Tcl_Eval(interp, "update");
  249.  
  250.     /*
  251.      * Loop infinitely, waiting for commands to execute.  When there
  252.      * are no windows left, Tk_MainLoop returns and we clean up and
  253.      * exit.
  254.      */
  255.  
  256.     Tk_MainLoop();
  257.     Tcl_DeleteInterp(interp);
  258.     Tcl_DStringFree(&command);
  259.     exit(0);
  260.  
  261. error:
  262.     msg = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
  263.     if (msg == NULL) {
  264.     msg = interp->result;
  265.     }
  266.     fprintf(stderr, "%s\n", msg);
  267.     Tcl_Eval(interp, "destroy .");
  268.     exit(1);
  269.     return 0;            /* Needed only to prevent compiler warnings. */
  270. }
  271.  
  272. /*
  273.  *----------------------------------------------------------------------
  274.  *
  275.  * StdinProc --
  276.  *
  277.  *    This procedure is invoked by the event dispatcher whenever
  278.  *    standard input becomes readable.  It grabs the next line of
  279.  *    input characters, adds them to a command being assembled, and
  280.  *    executes the command if it's complete.
  281.  *
  282.  * Results:
  283.  *    None.
  284.  *
  285.  * Side effects:
  286.  *    Could be almost arbitrary, depending on the command that's
  287.  *    typed.
  288.  *
  289.  *----------------------------------------------------------------------
  290.  */
  291.  
  292.     /* ARGSUSED */
  293. static void
  294. StdinProc(clientData, mask)
  295.     ClientData clientData;        /* Not used. */
  296.     int mask;                /* Not used. */
  297. {
  298. #define BUFFER_SIZE 4000
  299.     char input[BUFFER_SIZE+1];
  300.     static int gotPartial = 0;
  301.     char *cmd;
  302.     int result, count;
  303.  
  304.     count = read(fileno(stdin), input, BUFFER_SIZE);
  305.     if (count <= 0) {
  306.     if (!gotPartial) {
  307.         if (tty) {
  308.         Tcl_Eval(interp, "exit");
  309.         exit(0);
  310.         } else {
  311.         Tk_DeleteFileHandler(0);
  312.         }
  313.         return;
  314.     } else {
  315.         count = 0;
  316.     }
  317.     }
  318.     cmd = Tcl_DStringAppend(&command, input, count);
  319.     if (count != 0) {
  320.     if ((input[count-1] != '\n') && (input[count-1] != ';')) {
  321.         gotPartial = 1;
  322.         return;
  323.     }
  324.     if (!Tcl_CommandComplete(cmd)) {
  325.         gotPartial = 1;
  326.         return;
  327.     }
  328.     }
  329.     gotPartial = 0;
  330.  
  331.     /*
  332.      * Disable the stdin file handler;  otherwise if the command
  333.      * re-enters the event loop we might process commands from
  334.      * stdin before the current command is finished.  Among other
  335.      * things, this will trash the text of the command being evaluated.
  336.      */
  337.  
  338.     Tk_CreateFileHandler(0, 0, StdinProc, (ClientData) 0);
  339.     result = Tcl_RecordAndEval(interp, cmd, 0);
  340.     Tk_CreateFileHandler(0, TK_READABLE, StdinProc, (ClientData) 0);
  341.     Tcl_DStringFree(&command);
  342.     if (*interp->result != 0) {
  343.     if ((result != TCL_OK) || (tty)) {
  344.         printf("%s\n", interp->result);
  345.     }
  346.     }
  347.     if (tty) {
  348.     printf("wish: ");
  349.     fflush(stdout);
  350.     }
  351. }
  352.  
  353. /*
  354.  *----------------------------------------------------------------------
  355.  *
  356.  * StructureProc --
  357.  *
  358.  *    This procedure is invoked whenever a structure-related event
  359.  *    occurs on the main window.  If the window is deleted, the
  360.  *    procedure modifies "w" to record that fact.
  361.  *
  362.  * Results:
  363.  *    None.
  364.  *
  365.  * Side effects:
  366.  *    Variable "w" may get set to NULL.
  367.  *
  368.  *----------------------------------------------------------------------
  369.  */
  370.  
  371.     /* ARGSUSED */
  372. static void
  373. StructureProc(clientData, eventPtr)
  374.     ClientData clientData;    /* Information about window. */
  375.     XEvent *eventPtr;        /* Information about event. */
  376. {
  377.     if (eventPtr->type == DestroyNotify) {
  378.     w = NULL;
  379.     }
  380. }
  381.  
  382. /*
  383.  *----------------------------------------------------------------------
  384.  *
  385.  * DelayedMap --
  386.  *
  387.  *    This procedure is invoked by the event dispatcher once the
  388.  *    startup script has been processed.  It waits for all other
  389.  *    pending idle handlers to be processed (so that all the
  390.  *    geometry information will be correct), then maps the
  391.  *    application's main window.
  392.  *
  393.  * Results:
  394.  *    None.
  395.  *
  396.  * Side effects:
  397.  *    The main window gets mapped.
  398.  *
  399.  *----------------------------------------------------------------------
  400.  */
  401.  
  402.     /* ARGSUSED */
  403. static void
  404. DelayedMap(clientData)
  405.     ClientData clientData;    /* Not used. */
  406. {
  407.  
  408.     while (Tk_DoOneEvent(TK_IDLE_EVENTS) != 0) {
  409.     /* Empty loop body. */
  410.     }
  411.     if (w == NULL) {
  412.     return;
  413.     }
  414.     Tk_MapWindow(w);
  415. }
  416.