home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / lang / simpleto.hqx / SimpleTools.c next >
Text File  |  1985-10-02  |  31KB  |  912 lines

  1.  
  2. /*
  3.     Title    : SimpleTools.c
  4.     Author    : Erik Kilk  Copyright 1985
  5.     Date    : June 7, 1985
  6.     
  7.     Version    : 1.2
  8.     Revisions: 
  9.     09/05/85 EK Removed fix needed for a old compiler bug
  10.     07/13/85 EK Fixed menu unhilighting with D.A.'s menus.
  11.     07/16/85 EK Resettable default for new window type and has goaway.
  12.                 Included menu command key usage.
  13.      07/17/85 EK Removed menu changes to avoid flicker. 
  14.              Added return codes to most functions.
  15.             Fixed in-content call from changing event record.
  16.     
  17.     Synopsis: A collection of subroutines to simplify programming
  18.         the Macintosh in C.  These are for those little programs
  19.         you are tempted not to write because of all the hassles
  20.         you have to go through writing programs for the Macintosh
  21.         environment.
  22.         
  23.     Copyright:  These routines are copyrighted by Erik Kilk.  You
  24.         may use them for your programming, as examples for your
  25.         own programming, in your programs, in programs you
  26.         distribute, copy them, and give copies to others who will
  27.         abide by these rules if you send $10 or more to:
  28.                 Erik Kilk
  29.                 325 San Leandro Way
  30.                 San Francisco, CA  94127
  31.         You use this software "as is".  The author make no
  32.         promises and is not responsible nor liable for anything 
  33.         due to your use of these subroutines. 
  34.         
  35.         Thank you for your support.
  36.                 
  37.                 
  38.     Summary of User Routines:
  39.     
  40.     simpletools ("About SimpleTools");        Initialize 
  41.     simpleevents ();                        Process next event
  42.     menu ("Search", "Find", findroutine);    Add a menu
  43.     window ("Sketch", 50,50,200,200, 
  44.       activate,deactivate,update,content);    Add a window
  45.     withwindow ("Sketch");                    Set output to window
  46.     run (routine);                            Periodically call a routine
  47.     stop (routine);                            Stop periodic call
  48.     message ("Welcome to SimpleTools");        Display dialog message
  49.     prompt ("What is your name?", answer);    Ask a question
  50.         
  51.     simpletools("Name");
  52.         Call this once at the very beginning of your program. Pass
  53.     it the name of your program if you want an "About Name" menu
  54.     entry, otherwise pass it just "" as the name. It initializes
  55.      the data structures used by SimpleTools.  It also does all of
  56.     the toolbox initializing and
  57.     installs the Apple, File, and Edit menus.  Only base pointers
  58.     to linked structures and a few flags and scratch variables are
  59.     set.  All other data is dynamically allocated with relocatable
  60.     blocks through the Macintosh memory manager for each new menu
  61.     and window created with these SimpleTools routines.
  62.     
  63.     simpleevents();
  64.         Repeatedly call this routine as fast as you can.  Often this
  65.     routine is in a for(;;) loop in the main procedure.  This routine
  66.     handles menu selection, desk accessory startups, window moves,
  67.     window resizes, close-box clicks, all window events, and the
  68.     periodic calling of routines.  It will only handle menus, windows,
  69.     and periodic routines installed with simpletools(), menu(), 
  70.     window(), and run().
  71.         This routine does the systemtask() and getnextevent() calls
  72.     so you don't have to process them yourself.
  73.         At times simpleevents() will be looking up assigned procedures
  74.     to be executed. These procedures are passed some of information
  75.     particular to its situation.  With Magamax C (and possibly others)
  76.     the called procedure need not declare or use this passed data if
  77.     it has no need for it.  The kind of data passed is described below.
  78.         For key down and autokey events, the procedures set in 
  79.     keydownproc and autokeyproc are passed the address to the event 
  80.     record. By default, keydownproc and autokeyproc are set to 
  81.     a no op procedure.
  82.     
  83.     menu ("Settings", "Trace Execution", hideproc );
  84.         Call this routine for each menu to install or modify.  The 
  85.     first argument is the menu bar title, the second is the item name,
  86.     and the third is either the procedure to be executed when that
  87.     item is selected or a modifier ( 0L, itemdisable; 1L, itemenable;
  88.     2L, itemcheck, 3L, itemuncheck).  The first call with a particular
  89.     menu/item pair will install the menu/item with either a procedure
  90.     or modifier (in which case it is assigned a no op procedure.)  
  91.     Subseqent calls are used to change either the assigned procedure or
  92.     the current active modifiers.  Calling it with a null item name
  93.     will disable or enable the entire menu if the menu already exists
  94.     and the third parameter is either a 0L or 1L as listed above.
  95.         Assigned procedures will be called with a (char *) pointing to
  96.     the item name chosen.
  97.     
  98.     menuhandle mhand ("Settings");
  99.         This function returns the handle to a given menu bar selection
  100.     so that you can call the Menu manager routines yourself.
  101.     
  102.     window ("Trace Output", 256, 50, 500, 300, activateproc, 
  103.           deactivateproc, updateproc, incontentproc);
  104.         Call this routine for each window to install or modify.  The
  105.     first argument is the window's name.  Then the (x,y) of the top
  106.     left corner and the (x,y) of the bottom right corner.  These
  107.     coordinates are only used for installing a window and will be
  108.     ignored for subsequent calls.  Then comes four procedure names.
  109.     Activateproc is called when the window becomes the active window.
  110.     Deactivate when another window is activated.  Updateproc when 
  111.     windows have moved and the window needs redrawn.  And incontentproc
  112.     when the mouse is clicked inside the window.  
  113.          New windows are given a menu selection of their name under
  114.     a menu bar title of "Windows."  Menu() is used to install these.
  115.     The procedure called for each window name is a procedure to
  116.     bring back the window if it was closed by clicking its closebox or
  117.     activate it (in case it is hidden and can't be clicked on.  
  118.     When the close-box of a window is clicked, the window is just
  119.     hidden, it isn't really closed.
  120.          The assigned "in content" procedure will be called with two
  121.     (int)s.  The x and y of the mouse position in that window's
  122.     local coordinates.  Each assigned window procedure is also called
  123.     with a (windowptr) to the target window and an address to
  124.     the event record which just occured.  Before each is called,
  125.     the current port is set to the target window.
  126.     
  127.     withwindow ("Trace Output");
  128.          Call this routine to set the current output port to the
  129.     asked for window.  Remember that proper scrolling of text in the
  130.     window is only taken care of for the active window though output
  131.     can be to any window.
  132.     
  133.     windowptr windowpoint ("Trace Output");
  134.         This function returns a pointer to the given window name in
  135.     case you want to use one of the Window manager routines your
  136.     self.  
  137.     
  138.     run (flashsquareproc);
  139.         Call this routine to install a procedure to be periodically
  140.     executed.  Up do 100 procedures may be installed at once.  These
  141.     procedure are called just after each i/o event is read.  They are
  142.     called with the address of the current unprocessed eventrecord.
  143.     
  144.     stop (flashsquaresproc);
  145.         Call this to remove a procedure from the list of procedures
  146.     running periodically as installed with run().  
  147.         
  148.     message ("Are you sure you want to quit?");
  149.         Puts up a dialog with your message and an OK and Cancel
  150.     button.  Returns true if OK is clicked, false if Cancel hit.
  151.     Memory for the dialog is allocated when it is put up and
  152.     returned to the heap when a button is clicked.
  153.     
  154.     prompt ("What is your name?", answer);
  155.         Where answer is a string set to a default value.  Puts up 
  156.     a dialog with your question, an editable answer field with you
  157.     default answer, the OK and Cancel buttons.  Returns true when
  158.     OK or RETURN is entered, false if Cancel is clicked.
  159. */
  160.  
  161. overlay "simpletools"        /* remove or change this if needed */
  162.  
  163. #include <mem.h>        /* include type defs and constants */
  164. #include <qd.h>            /* for the Macintosh tool box */
  165. #include <qdvars.h>
  166. #include <misc.h>
  167. #include <event.h>
  168. #include <res.h>
  169. #include <win.h>
  170. #include <te.h>
  171. #include <dialog.h>
  172. #include <menu.h>
  173. #include <string.h>
  174. #include <stdio.h>
  175.  
  176. #define TRUE (-1)        /* local definitions */
  177. #define FALSE 0
  178. #define itemdisable 0        /* constants for menu modifiers */
  179. #define itemenable 1
  180. #define itemcheck 2
  181. #define itemuncheck 3
  182. #define maxsruns 50        /* procedure table size */
  183. #define MESSN 30        /* array size for message dialog items */
  184. #define QUESN 40        /* array size for prompt dialog items */
  185.  
  186. typedef struct {        /* structure for an item */
  187.     char itemname[40];    /* to allow reference by name */
  188.     int itemno;        /* item number within menu */
  189.     int menuid;        /* menu id in case menu info is needed */
  190.     menuhandle menuhand;    /* item's menu's handle */
  191.     procptr menurun;    /* procedure to run */
  192.     ptr next;        /* pointer to the next item */
  193. } itemdatum;
  194.  
  195. typedef struct {        /* structure for a menu */
  196.     char menuname[20];    /* to allow reference by name */
  197.     int menuid;        /* menu id used to create the menu */
  198.     menuhandle menuhand;    /* menu handle used to reference menu */
  199.     itemdatum **itemlist;    /* pointer to the list of items */
  200.     ptr next;        /* pointer to the next menu */
  201. } menudatum;
  202.  
  203. typedef struct {        /* structure for a window */
  204.     char windname[80];    /* the window's name and reference */
  205.     windowptr wptr;        /* the window's pointer reference */
  206.     procptr wact;        /* the activate procedure */
  207.     procptr wdeact;        /* the deactivate procedure */
  208.     procptr wupdate;    /* the update procedure */
  209.     procptr wcontent;    /* the content procedure */
  210.     ptr next;        /* pointer to the next window */
  211. } winddatum;
  212.  
  213. menudatum **simplemenus;    /* handle to menu data */
  214. char accname[80];        /* desk accessory name to open */
  215. rect dragrect, sizerect;    /* limits for moving windows */
  216. int wprocid = documentprod;    /* window procedure id */
  217. int dogoaway = TRUE;        /* if window has go away box */
  218. winddatum **simplewinds;    /* handle to window data */
  219. int firstwind;            /* true if no windows have been made */
  220. procptr keydownproc,
  221.   autokeyproc;             /* routines for key down events */
  222. procptr simpleruns[maxsruns];    /* list of procedures to run */
  223. char applestring[2] 
  224.   = {'\024', '\0'};         /* name of apple menu */
  225. windowptr debugw;        /* a window pointer for debugging */
  226. int windmenu = TRUE;        /* whether or not a window menu is made */
  227.  
  228. /******************************************************************/
  229. /* Dialog lists.  These were calculated by using the new resource */
  230. /* editor to make a template for a dialog and then using fedit to */
  231. /* list the hex listing of the item list for the dialog.      */
  232. /******************************************************************/
  233.  
  234. int messd[MESSN] = {2,0,0,0x38,0xf1,0x4c,0x12d,0x402,0x4f4b,0,0,5,5,
  235.         0x36,0x12d,0x800,0,0,0x38,0xac,0x4c,0xe8,0x406,
  236.         0x4361,0x6e63,0x656c};
  237. int quesd[QUESN] = {3,0,0,0x21,0xf0,0x35,0x12c,0x402,0x4f4b,0,0,8,8,
  238.         0x28,0xe8,0x800,0,0,0x2b,8,0x4b,0xe8,0x1000,0,0,
  239.         8,0xf0,0x1c,0x12c,0x406,0x4361,0x6e63,0x656c};
  240.  
  241. stnop()                /* a no op procedure for defaults */
  242. {
  243. }
  244.  
  245. /* Given a menu name, find our data structure for it.  Return a handle
  246.    to this structure.
  247. */
  248.  
  249. menudatum **getourmenuhandle (name)
  250. char *name;            /* name of menu bar menu */
  251. {
  252.     menudatum **here;    /* a handle to our menu structure */
  253.     here = simplemenus;
  254.  
  255.     /* find the menu name or the end of out menu list */
  256.     while ( (strcmp(name,(**here).menuname) != 0) & 
  257.         ((**here).next != (ptr)0L) )   
  258.         here = (menudatum **)(**here).next;
  259.         
  260.     /* see if we found it or just the end of the list */
  261.     if (strcmp(name,(**here).menuname) == 0)
  262.         return (here);
  263.     else
  264.         return ((menudatum **)0L);  /* return 0 if not found */
  265. }
  266.  
  267. /* Given a menu name, return the real menu handle as used by most
  268.    of the Macintosh toolbox menu manager routines.
  269. */
  270.  
  271. menuhandle mhand (name)            /* find menuhandle */
  272. char *name;                /* given name of menu */
  273. {
  274.   menudatum **menu;            /* a handle to our data */
  275.   menu = getourmenuhandle(name);
  276.   if ( (long) menu != 0L )
  277.     return ( (**menu).menuhand);    /* return menu handle */
  278.   else
  279.     return ( (menuhandle) 0 );        /* return 0 if not found */
  280. }
  281.  
  282. /* This takes a handle to our personal item record and either a 
  283.    procedure name or a modifier code.  If it got a procedure name,
  284.    it sets it to the item's procedure to run when the item is chosen.
  285.    If it got a modifier code, it changes the state of the menu's item
  286.    to checked, unchecked, enabled, or disabled.  It especially keeps 
  287.    track of the standard Edit menu items so we can restore them after
  288.    a desk accessory is finished.
  289. */
  290.  
  291. setitem ( items, routine)    /* set a menu item's routine or display */
  292. itemdatum **items;        /* if items is neg, then whole menu */
  293. procptr routine;
  294. {
  295.     int inumber;
  296.     menuhandle mhand;
  297.     
  298.     /* check to see if a procedure pointer was given to us */
  299.     if ( (((long)items)>0L) && (routine > (procptr)0x1000L)) {  
  300.             /* a good procedure value */
  301.         (**items).menurun = routine;
  302.         return;
  303.     }
  304.     
  305.     /* Calculate which item number we are going to modify */
  306.     if ( (long)items < 0L) {    /* the whole menu */
  307.       mhand = (menuhandle) (0L - (long)items);
  308.       inumber = 0;
  309.     }
  310.     else {                /* just one item */
  311.       mhand = (**items).menuhand;
  312.       inumber = (**items).itemno;
  313.     }
  314.     
  315.     /* If a NULL procedure pointer, then set to a no_op routine */
  316.     if ( (inumber > 0) && ((**items).menurun == (procptr)0L) )
  317.       (**items).menurun = stnop;
  318.       
  319.     /* Now change the state of a menu item */
  320.     switch ((int)routine) {
  321.         case itemdisable: 
  322.             disableitem(mhand,inumber); break;
  323.         case itemenable:
  324.             enableitem(mhand, inumber); break;
  325.         case itemcheck:
  326.             checkitem(mhand, inumber, TRUE); break;
  327.         case itemuncheck:
  328.             checkitem(mhand, inumber, FALSE); break;
  329.     }
  330.     if (inumber == 0) drawmenubar();  /* if main menu was changed */
  331.     
  332. }
  333.         
  334. /* This routine is described above.  It takes care of our menu data
  335.    structure by adding or modifying menu entries.  
  336. */
  337.  
  338. menu (name, item, routine)        /* install or change a menu */
  339. char *name;                /* the menu name */
  340. char *item;                /* the item name */
  341. char * routine;                /* a procedure or modifier */
  342. {
  343.     menudatum **here;        /* a roving handle to our data */
  344.     menudatum **ourmhandle;        /* another handle to our data */
  345.     itemdatum **items;        /* a handle to the item */
  346.     menuhandle mhandle;        /* a handle to the real menu */
  347.     int lastid, lastitem;
  348.     
  349.     /* get the handle to menu named 'name' */
  350.     if ((ourmhandle = getourmenuhandle (name)) == 0L) {
  351.     
  352.         /* make a new menu entry by finding the end of the list */
  353.         here = simplemenus;
  354.         while ((**here).next != 0L)
  355.             here = (menudatum **)(**here).next;
  356.             
  357.         /* make a structure for our new entry */
  358.         lastid = (**here).menuid;
  359.         (**here).next = (ptr)newhandle ( (long)sizeof(menudatum));
  360.         here = (menudatum **)(**here).next;
  361.         strcpy ( (**here).menuname, name);
  362.         (**here).menuid = ++lastid;
  363.         (**here).next = (ptr) 0L;
  364.         
  365.         /* make a new item structure */
  366.         (**here).itemlist = (itemdatum **)newhandle ( 
  367.             (long)sizeof(itemdatum));
  368.             
  369.         /* make a new menu entry for the Macintosh */
  370.         (**here).menuhand = newmenu (lastid, name);
  371.         mhandle = (**here).menuhand;
  372.         items = (**here).itemlist;
  373.         strcpy ((**items).itemname, item);
  374.         (**items).itemno = 1;
  375.         (**items).menuid = lastid;
  376.         (**items).menuhand = (**here).menuhand;
  377.         (**items).menurun = (procptr) 0L;
  378.         (**items).next = 0L;
  379.         
  380.         /* install and display the menu */
  381.         appendmenu ((**here).menuhand, item);
  382.         insertmenu ((**here).menuhand,0);
  383.         setitem (items, routine);
  384.         drawmenubar();
  385.         return(TRUE);
  386.     }
  387.     else {
  388.         if (strlen(item) == 0) {
  389.           /* then adjust main menu */
  390.           setitem( 0L - (long) ((**ourmhandle).menuhand), routine);
  391.           return(FALSE);
  392.         }
  393.         /* see if item is in list */
  394.         items = (**ourmhandle).itemlist;
  395.         while ( (strcmp(item,(**items).itemname) != 0) &
  396.             ((**items).next != (ptr)0L)) {
  397.             items = (itemdatum **)(**items).next;
  398.         }
  399.         if (strcmp(item,(**items).itemname) ==0) {
  400.             setitem( items, routine);
  401.             return(FALSE);
  402.         }
  403.         else {
  404.             /* make new item entry */
  405.             lastitem = (**items).itemno;
  406.             (**items).next =(ptr)newhandle(
  407.                 (long)sizeof(itemdatum));
  408.             items = (itemdatum **)(**items).next;
  409.             strcpy ((**items).itemname, item);
  410.             (**items).itemno = ++lastitem;
  411.             (**items).menuid = (**ourmhandle).menuid;
  412.             (**items).menuhand = (**ourmhandle).menuhand;
  413.             (**items).menurun = (procptr) 0L;
  414.             (**items).next = 0L;
  415.             
  416.             /* and install the item in the menu bar */
  417.             appendmenu ((**ourmhandle).menuhand,item);
  418.             setitem (items, routine);
  419.             return(TRUE);
  420.         }
  421.     }
  422. }
  423.     
  424. /* This routine is called by the simpletools() initial routine.  It gets
  425.    the pointer list of menus started, loads the desk accessories into
  426.    the Apple menu, and loads up some standard menu entries.  The reason
  427.    menu File has a New entry, and none others, is because as this code
  428.    currently stands, a menu must have at least one item.  And since we
  429.    want File before Edit, I had to make an entry.  The most commonly used
  430.    item under File is Quit.  But we like quit to be at the end of the list.
  431.    So, since New is usually always first when it is used, that the one
  432.    chosen to start File.  
  433. */
  434.  
  435. initsmenus(about)            /* init simpletools' menus */
  436. char *about;
  437. {
  438.     itemdatum **items;
  439.     simplemenus = (menudatum **) newhandle ( (long)sizeof(menudatum));
  440.     strcpy ( (**simplemenus).menuname, applestring);
  441.     (**simplemenus).menuid = 1;
  442.     (**simplemenus).next = (ptr) 0L;
  443.     (**simplemenus).menuhand = newmenu (1, (**simplemenus).menuname);
  444.     (**simplemenus).itemlist = (itemdatum **)newhandle ( 
  445.             (long)sizeof(itemdatum));
  446.     items = (itemdatum **) (**simplemenus).itemlist;
  447.     strcpy ((**items).itemname, about);
  448.     (**items).itemno = 1;
  449.     (**items).menuid = 1;
  450.     (**items).menuhand = (**simplemenus).menuhand;
  451.     (**items).menurun = stnop;
  452.     (**items).next = 0L;
  453.     appendmenu ((**simplemenus).menuhand, about);
  454.     disableitem ((**simplemenus).menuhand, 1);
  455.     menu (applestring, "-", (procptr) itemdisable);
  456.     addresmenu ((**simplemenus).menuhand, "DRVR");
  457.     insertmenu ((**simplemenus).menuhand, 0);
  458.     menu ("File", "New", (procptr)itemdisable);
  459.     menu ("Edit", "Undo", stnop);
  460.     menu ("Edit", "-", (procptr)itemdisable);
  461.     menu ("Edit", "Cut/X", stnop);
  462.     menu ("Edit", "Copy/C", stnop);
  463.     menu ("Edit", "Paste/V", stnop);
  464.     menu ("Edit", "Clear", stnop);
  465. }
  466.  
  467. /* Given a window's name, return its window pointer so that other
  468.    Macintosh Window Manager routines can be called for that window. */
  469.    
  470. windowptr windowpoint(name)        /* get window pointer */
  471. char *name;                /* given window's name */
  472. {
  473.     winddatum **wind;            /* handle to our window data */
  474.     if (firstwind) return ((windowptr)0); /* forget if there aren't any */
  475.     wind = simplewinds;            /* look for the named window */
  476.     while ( (strcmp ((**wind).windname, name) != 0) & 
  477.       ((**wind).next != (ptr) 0)) {
  478.         wind = (winddatum **) (**wind).next;
  479.     }
  480.     if ( strcmp ((**wind).windname, name) ==0) 
  481.       return ( (**wind).wptr);        /* return pointer */
  482.     else
  483.       return ( (windowptr) 0);        /* or zero if it wasn't found */
  484. }
  485.  
  486. /* This routine is for the Windows menu item.  The Windows menu is
  487.    set up when new windows are added.  It is used to bring forward and
  488.    bring into view windows that may be under other windows or have been
  489.    sent hiding by a click on their close box.
  490. */
  491.  
  492. showawindow(name)            /* show the named window */
  493. char *name;
  494. {
  495.   windowptr foo;
  496.   foo = windowpoint(name);        /* get its window pointer */
  497.   if ( (long)foo != 0L ) {
  498.     showwindow(foo);            /* show it on the screen */
  499.     setport (foo);            /* set further output to it */
  500.     if ( foo != frontwindow())        /* if it isn't active, */
  501.       selectwindow (foo);        /* activate it */
  502.   }
  503. }
  504.  
  505. /* This routine installs a new window onto the screen.  It also gives
  506.    that window an item in the Window menu.  This routine is also used
  507.    to modify a window's associated routines.  The x,y positions are the
  508.    top left and bottom right corners of where the window should originally
  509.    be placed.  The coordinates are never used when this routine is called
  510.    to update an already existing window.  But the spaces must be filled,
  511.    so you can use zeros if you want.  Once the window has been displayed in
  512.    its original position, the user has complete control of its size and
  513.    placement with the mouse.
  514. */
  515.  
  516. window(name, xtop, ytop, xbot, ybot, a, d, u, c)
  517. char *name;            /* window's name */
  518. int xtop, ytop, xbot, ybot;    /* position if this is a new window */
  519. procptr a, d, u, c;        /* activate, deactivate, update, and */
  520. {                /*  content procedure names */
  521.   winddatum **wind;        /* handle to our window data */
  522.   winddatum **newentry;        /* another handle */
  523.   rect newplace;        /* a rectable for the window's placement */
  524.   if (a == (procptr) 0)
  525.     a = stnop;
  526.   if (d == (procptr) 0)
  527.     d = stnop;
  528.   if (u == (procptr) 0)
  529.     u = stnop;
  530.   if (c == (procptr) 0)
  531.     c = stnop;
  532.   if ( !firstwind ) {
  533.   
  534.     /* see if window is in the list */
  535.     wind = simplewinds;
  536.     while ( (strcmp ((**wind).windname, name) != 0) & 
  537.       ((**wind).next != (ptr) 0)) {
  538.         wind = (winddatum **) (**wind).next;
  539.     }
  540.     if ( strcmp ((**wind).windname, name) ==0) {
  541.     
  542.       /* reset the found window's parameters */
  543.       (**wind).wact = (procptr) a;
  544.       (**wind).wdeact = (procptr) d;
  545.       (**wind).wupdate = (procptr) u;
  546.       (**wind).wcontent = (procptr) c;
  547.       setport ( (**wind).wptr);        /* set output to window */
  548.       return(FALSE);
  549.     }
  550.   }
  551.   
  552.   /* make a new window entry */
  553.   newentry = (winddatum **)newhandle ( (long) sizeof (winddatum));
  554.   if (firstwind)
  555.     simplewinds = newentry;
  556.   else
  557.     (**wind).next = (ptr) newentry;
  558.   firstwind = 0;
  559.   strcpy ((**newentry).windname, name);
  560.   setrect (&newplace, xtop, ytop, xbot, ybot);
  561.   (**newentry).wptr = newwindow (0L, &newplace, name, -1, 
  562.     wprocid, -1L, dogoaway, newentry);
  563.   (**newentry).wact = (procptr) a;
  564.   (**newentry).wdeact = (procptr) d;
  565.   (**newentry).wupdate = (procptr) u;
  566.   (**newentry).wcontent = (procptr) c;
  567.   (**newentry).next = (ptr) 0;
  568.   if (windmenu)
  569.     menu ("Windows", name, showawindow);/* make a menu entry for it */ 
  570.   setport ( (**newentry).wptr);        /* set output to it */
  571.   return(TRUE);
  572. }
  573.  
  574. winddatum **wdatum(windpt)        /* return handle to window data */
  575. windowptr windpt;
  576. {
  577.   winddatum **wind;
  578.   if (firstwind) return ((winddatum **) 0L);
  579.   wind = simplewinds;
  580.   while ( ((**wind).wptr != windpt) &    /* search for window's name */
  581.     ((**wind).next != (ptr) 0)) {
  582.       wind = (winddatum **) (**wind).next;
  583.   }
  584.   if ( (**wind).wptr == windpt)
  585.     return (wind);
  586.   else
  587.     return ((winddatum **) 0L);        /* zero if not found */
  588. }
  589.   
  590. withwindow(name)        /* set output to a window by name */
  591. char *name;            /* give it the window's name */
  592. {                /* returns boolean if window exists */
  593.     winddatum **wind;
  594.     wind = simplewinds;
  595.     if (firstwind) return(FALSE);    /* search for the window's name */
  596.     while ( (strcmp ((**wind).windname, name) != 0) & 
  597.       ((**wind).next != (ptr) 0)) {
  598.         wind = (winddatum **) (**wind).next;
  599.     }
  600.     if ( strcmp ((**wind).windname, name) ==0) {
  601.       setport ( (**wind).wptr);    /* set output to it */
  602.       return(TRUE);
  603.     }
  604.     else
  605.       return(FALSE);
  606. }
  607.   
  608. /* This run procedure is used to install routines to be occasionally
  609.    run.  The routine will be run once for each call to simpleevents()
  610. */
  611.  
  612. run(routine)            /* install a run procedure */
  613. procptr routine;        /* give it the procedure */
  614. {                /* return TRUE if successful */
  615.   int i;
  616.   i = 0;            /* add it to the end of the list */
  617.   while ( simpleruns[i] != (procptr) 0L) i++;
  618.   if (i < maxsruns) {
  619.     simpleruns[i] = routine;
  620.     simpleruns[i+1] = (procptr) 0L;
  621.     return(TRUE);
  622.   }
  623.   else
  624.     return(FALSE);
  625. }
  626.  
  627. /* This routine removes a procedure from the list of run procedures */
  628. stop(routine)            /* stop a procedure from running */
  629. procptr routine;        /* give the procedure */
  630. {                /* return TRUE if successful */
  631.   int i;
  632.   i = 0;
  633.   while ( (simpleruns[i] != routine) & (simpleruns[i] != (procptr) 0L))i++;
  634.   if (simpleruns[i] == (procptr) 0L)
  635.     return(FALSE);
  636.   else {
  637.     while ( simpleruns[i] != (procptr)0 ) {
  638.       simpleruns[i] = simpleruns[i+1];
  639.       i++;
  640.     }
  641.     return(TRUE);
  642.   }
  643. }
  644.  
  645. runruns(event)            /* run all the installed run procedures */
  646. eventrecord *event;        /* returns number of routines run */
  647. {
  648.   int i;
  649.   i = 0;
  650.   while ( simpleruns[i] != 0 )
  651.     (*(simpleruns[i++])) (event);
  652.   return(i);
  653. }
  654.  
  655. stdialog( question, answer, type)  /* a general dialog displayer */
  656. char *question;
  657. char *answer;
  658. int  type;            /* type:  1=prompt, 2=message */
  659. {
  660.   dialogptr dialog;            /* dialog reference */
  661.   handle item, items;            /* handles for the dialog items */
  662.   rect screen, box;            /* rectangles for dialog/items */
  663.   int dtype, hit, canc;            /* item type and which was hit */
  664.   char tempanswer[255];            /* address where answer is */
  665.   
  666.   items = newhandle (512L);        /* get memory for items list */
  667.   hlock (items);            /* lock it down */
  668.   if (type == 1)
  669.     blockmove (quesd, *items, (long) QUESN * 2L); /* fill it with list */
  670.   else
  671.     blockmove (messd, *items, (long) MESSN * 2L);
  672.   setrect (&screen, 103, 50, 409, 137);        /* position window */
  673.   dialog = newdialog (0L, &screen, "", 0, dboxproc, -1L, 0, 0L, items);
  674.   getditem (dialog, 2, &dtype, &item, &box);    /* get item#2 handle */
  675.   setitext (item, question);            /* set item#2 text */
  676.   if (type == 1) {            /* set default answer */
  677.     getditem (dialog, 3, &dtype, &item, &box);
  678.     setitext (item, answer);
  679.     canc = 4;
  680.   }
  681.   else
  682.     canc = 3;
  683.   showwindow (dialog);                /* display the dialog */
  684.   do {
  685.     modaldialog (0L, &hit);            /* process the dialog */
  686.   } while ( (hit != 1) & (hit != canc) );
  687.   if (type == 1) {
  688.     getditem (dialog, 3, &dtype, &item, &box);    /* get item#3 handle */
  689.     hlock (item);
  690.     getitext (item, tempanswer);        /* get item#3 text */
  691.     strcpy (answer, tempanswer);        /* make a copy of it */
  692.     hunlock (item);
  693.   }
  694.   hunlock(items);                /* unlock items memory */
  695.   hpurge(items);                /* purge it */
  696.   disposdialog (dialog);            /* get rid of dialog */
  697.   return ( hit==1 );                /* return true if ok */
  698. }  
  699.   
  700. prompt ( question, answer)        /* dialog box question/answer */
  701. char *question;
  702. char *answer;
  703. {
  704.   return (stdialog (question, answer, 1));
  705. }
  706.  
  707. message ( message )            /* dialog box message */
  708. char *message;
  709. {
  710.   return (stdialog (message, message, 2));
  711. }
  712.   
  713. docommand (which, thisevent)
  714. long which;
  715. eventrecord *thisevent;
  716. {
  717.   int themenu, theitem;
  718.   long size;
  719.   char *cpoint;
  720.   grafptr tempport;
  721.   menudatum **here;
  722.   itemdatum **items;
  723.   char **myreshandle;
  724.   handle myhandle;
  725.   themenu = hiword (which);
  726.   theitem = loword (which);
  727.   if ((themenu == 1) && (theitem != 1)) {
  728.     /* start up a desk accessory */
  729.     getitem ((**simplemenus).menuhand,
  730.       theitem, accname);
  731.     setresload (FALSE);
  732.     myreshandle = getnamedresource ("DRVR", accname);
  733.     setresload (TRUE);
  734.     size = sizeresource (myreshandle);
  735.     myhandle = newhandle ( size + 3072L);
  736.     if (myhandle == 0L) 
  737.       message ("Not enough memory to do that.");
  738.     else {
  739.       disposhandle (myhandle);
  740.       getport (&tempport);
  741.       opendeskacc(accname);
  742.       setport (tempport);
  743.     }
  744.     return;
  745.   }
  746.   if (themenu ==3) {
  747.     /* do any system edits */
  748.     if (systemedit(theitem -1) != FALSE) 
  749.       return;
  750.   }
  751.   
  752.   /* now we run an installed menu procedure */
  753.   here = simplemenus;
  754.   
  755.   /* find out menu structure given the menu id */
  756.   while ( ((**here).menuid != themenu) &
  757.     ((**here).next != (ptr)0L) )
  758.   here = (menudatum **)(**here).next;
  759.   
  760.   if ((**here).menuid == themenu) {
  761.     /* now find the item structure */
  762.     items = (**here).itemlist;
  763.     while ( ((**items).itemno != theitem) &
  764.       ((**items).next != (ptr) 0L) )
  765.       items = (itemdatum **)(**items).next;
  766.   
  767.     /* prepare to give the item name to the procedure */
  768.     cpoint = (**items).itemname;
  769.     if ((**items).itemno == theitem) 
  770.       /* if we found the item, call its procedure */
  771.       (*((**items).menurun))(cpoint,thisevent) ;
  772.   }
  773. }
  774.       
  775. domousedown(thisevent)        /* respond to mouse down events */
  776. eventrecord *thisevent;        /* passed the event record */
  777. {
  778.     windowptr whichwindow;
  779.     int code, x, y;
  780.     char *cpoint;
  781.     menudatum **omhand;
  782.     winddatum **thewdatum;
  783.     long newplace;
  784.     point temp;
  785.     code = findwindow(&(thisevent->where), &whichwindow);
  786.     switch (code) {
  787.         case inmenubar:
  788.           docommand(menuselect(&(thisevent->where)),thisevent);
  789.           break;
  790.         case insyswindow:
  791.             systemclick(thisevent, whichwindow); break;
  792.         case indrag:
  793.             dragwindow(whichwindow, &(thisevent->where),
  794.               &dragrect); break;
  795.         case ingrow:
  796.           newplace= growwindow(whichwindow, &(thisevent->where),
  797.             &sizerect);
  798.           sizewindow(whichwindow, loword(newplace), 
  799.             hiword(newplace), TRUE);
  800.           break;
  801.         case ingoaway:
  802.           if ( trackgoaway(whichwindow, &(thisevent->where))) {
  803.             hidewindow (whichwindow);
  804.           }
  805.           break;
  806.         case incontent:
  807.         
  808.           /* make the window active if it isn't yet */
  809.           if (whichwindow != frontwindow()) {
  810.             selectwindow(whichwindow);
  811.           }
  812.   
  813.           /* find our window data */
  814.           thewdatum = wdatum (whichwindow);
  815.           if ((long) thewdatum != 0L) {
  816.           
  817.             /* convert the point of click to the window's
  818.                own coordinates since this will be always
  819.                more useful than the global coordintates */
  820.             temp = thisevent->where;
  821.             setport (whichwindow);
  822.             globaltolocal (&temp);
  823.             x = temp.a.h;
  824.             y = temp.a.v;
  825.             
  826.             /* call the window's in content routine */
  827.             (*((**thewdatum).wcontent))(x, y, whichwindow,
  828.                 thisevent);
  829.           }
  830.           break;
  831.     }
  832. }
  833.             
  834. simpletools(about)    /* to be called at the beginning of program */
  835. char *about;
  836. {
  837.     maxapplzone();        /* allow maximum heap expansion */
  838.     flushevents (everyevent,0);  /* ignore left over events */
  839.     initgraf (&theport);    /* initialize the screen */
  840.     initfonts();        
  841.     initwindows();
  842.     initmenus();
  843.     initcursor();        /* make the arrow cursor */
  844.     teinit();
  845.     initdialogs(0L);
  846.     setrect ( &sizerect, 20, 50, 250, 330);
  847.     /*
  848.     debugw = newwindow(0L,&sizerect,"Debug",-1,documentproc,-1L,-1L,0L);
  849.     */
  850.     simpleruns[0] = (procptr) 0;  /* empty the run list */
  851.     /* These are the bounds we are allowed to size a window or
  852.        move a window to.  
  853.     */
  854.     setrect ( &sizerect, 20, 20, 511, 341);
  855.     setrect ( &dragrect, 4, 24, 507, 337);
  856.     firstwind = 1;            /* empty window table */
  857.     keydownproc = stnop;        /* default key hit procedures */
  858.     autokeyproc = stnop;
  859.     initsmenus(about);        /* install the menus */
  860. }
  861.  
  862. simpleevents()        /* to be called in the main loop */
  863. {
  864.     eventrecord newevent;
  865.     winddatum **thewdatum;
  866.     systemtask();        /* Do the system D.A. etc. stuff */
  867.     hilitemenu(0);
  868.     getnextevent(everyevent, &newevent);
  869.     runruns(&newevent);    /* Do our run procedures */
  870.     switch (newevent.what) {
  871.         case mousedown:
  872.           domousedown(&newevent); break;
  873.         case keydown: 
  874.           if ((newevent.modifiers & cmdkey) != 0)
  875.             docommand(menukey((char)(newevent.message & 0xffL)),
  876.               &newevent);
  877.           (*(keydownproc))(&newevent);
  878.           break;
  879.         case autokey: 
  880.           if ((newevent.modifiers & cmdkey) != 0)
  881.             docommand(menukey((char)(newevent.message & 0xffL)),
  882.                       &newevent);
  883.           (*(autokeyproc))(&newevent);
  884.           break;
  885.         case activateevt: 
  886.           thewdatum = wdatum(newevent.message);
  887.           if ((long)thewdatum != 0L) {
  888.             setport(newevent.message);
  889.             if ((newevent.modifiers & 1) == 1) {
  890.               (*((**thewdatum).wact))(newevent.message, 
  891.                 &newevent);
  892.             }
  893.             else {
  894.               (*((**thewdatum).wdeact))(newevent.message,
  895.                 &newevent);
  896.             }
  897.           }
  898.           break;
  899.         case updateevt:
  900.           thewdatum = wdatum(newevent.message);
  901.           if ((long)thewdatum != 0L) {
  902.             setport (newevent.message);
  903.             beginupdate (newevent.message);
  904.             (*((**thewdatum).wupdate))(newevent.message,
  905.               &newevent);
  906.             endupdate (newevent.message);
  907.           }
  908.         break;
  909.     }
  910. }
  911.  
  912.