home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / frntsdk1.cpt / Frontier SDK 1.0 ƒ / Menu Sharing Toolkit / menusharing.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-05  |  13.9 KB  |  600 lines

  1.  
  2. /*⌐ Copyright 1991 UserLand Software, Inc.  All Rights Reserved.*/
  3.  
  4.  
  5. #include <processes.h>
  6. #include <Menus.h>
  7. #include <GestaltEqu.h>
  8. #include <iac.h>
  9. #include <menusharing.h> 
  10.  
  11.  
  12.  
  13. tyMSglobals MSglobals; /*Menu Sharing globals, all in one struct*/
  14.  
  15.  
  16.  
  17. static pascal Boolean ProcessInForeground () {
  18.     
  19.     /*
  20.     return true if we're running in the foreground, false if we're in the
  21.     background.
  22.     */
  23.     
  24.     ProcessSerialNumber currentprocess, frontprocess;
  25.     Boolean fl;
  26.     
  27.     GetCurrentProcess (¤tprocess);
  28.     
  29.     GetFrontProcess (&frontprocess);
  30.     
  31.     SameProcess (¤tprocess, &frontprocess, &fl);
  32.     
  33.     return (fl);
  34.     } /*cometofront*/
  35.     
  36.     
  37. static OSType GetProcessCreator (void) {
  38.     
  39.     /*
  40.     get the 4-character creator identifier for the application we're running 
  41.     inside of.
  42.     */
  43.     
  44.     ProcessSerialNumber psn;
  45.     ProcessInfoRec info;
  46.     
  47.     GetCurrentProcess (&psn);
  48.     
  49.     info.processInfoLength = (long) sizeof (info);
  50.     
  51.     info.processName = nil;
  52.     
  53.     info.processAppSpec = nil;
  54.     
  55.     GetProcessInformation (&psn, &info);
  56.     
  57.     return (info.processSignature);
  58.     } /*GetProcessCreator*/
  59.     
  60.     
  61. static Boolean ServerIsRunning (void) {
  62.     
  63.     /*
  64.     return true if the server application is running. 
  65.     */
  66.     
  67.     ProcessInfoRec info;
  68.     ProcessSerialNumber psn;
  69.     Str255 bsname;
  70.     FSSpec fss;
  71.     
  72.     info.processInfoLength = sizeof (info);
  73.     
  74.     info.processName = bsname; /*place to store process name*/
  75.     
  76.     info.processAppSpec = &fss; /*place to store process filespec*/
  77.     
  78.     psn.highLongOfPSN = kNoProcess;
  79.     
  80.     psn.lowLongOfPSN = kNoProcess;
  81.     
  82.     while (GetNextProcess (&psn) == noErr) {
  83.         
  84.          info.processInfoLength = sizeof (ProcessInfoRec);
  85.          
  86.         if (GetProcessInformation (&psn, &info) != noErr)
  87.             continue; /*keep going -- ignore error*/
  88.         
  89.         if (info.processSignature == MSglobals.serverid)
  90.             return (true);
  91.         } /*while*/
  92.     
  93.     return (false); /*loop completed, no server*/
  94.     } /*ServerIsRunning*/
  95.  
  96.  
  97. static short CountMenuArray (void) {
  98.     
  99.     /*
  100.     return the number of menus in the menu array.
  101.     */
  102.     
  103.     register hdlmenuarray hm = MSglobals.hsharedmenus;
  104.     
  105.     if (hm == nil)
  106.         return (0);
  107.     
  108.     return ((short) (GetHandleSize ((Handle) hm) / sizeof (tysharedmenurecord)));
  109.     } /*CountMenuArray*/
  110.  
  111.  
  112. static pascal Boolean InstallSharedMenus (short idmenuafter) {
  113.     
  114.     /*
  115.     insert all of the menus in the menuarray into the menu bar.  main 
  116.     menus are inserted in front of idmenuafter. if idmenuafter is zero, 
  117.     main (non-hierarchic) menus will be added to the right of all others.
  118.     */
  119.     
  120.     register hdlmenuarray hm = MSglobals.hsharedmenus;
  121.     register short i, ct;
  122.     tysharedmenurecord item;
  123.     
  124.     ct = CountMenuArray ();
  125.     
  126.     for (i = 0; i < ct; i++) {
  127.         
  128.         item = (**hm) [i];
  129.         
  130.         if (item.flhierarchic)
  131.             InsertMenu (item.hmenu, -1);
  132.         else
  133.             InsertMenu (item.hmenu, idmenuafter);
  134.         
  135.         (**hm) [i].flinserted = true; /*so we'll know it needs to be removed*/
  136.         } /*for*/
  137.     
  138.     return (true);
  139.     } /*InstallSharedMenus*/
  140.  
  141.  
  142. static short GetMenuHandles (void) {
  143.     
  144.     /*
  145.     loop through the menuarray, send an IAC message to the menu server requesting
  146.     that each MenuHandle be sent to us.
  147.     */
  148.     
  149.     register hdlmenuarray hm = MSglobals.hsharedmenus;
  150.     register short i, ct;
  151.     AppleEvent event, reply;
  152.     register short fl;
  153.     long id;
  154.     MenuHandle hmenu;
  155.     
  156.     ct = CountMenuArray ();
  157.     
  158.     for (i = 0; i < ct; i++) {
  159.     
  160.         if (!IACnewverb (MSglobals.serverid, MSglobals.serverid, 'gmhd', &event))
  161.             return (false);
  162.         
  163.         IACglobals.event = &event;
  164.         
  165.         if (!IACpushlongparam (MSglobals.clientid, 'menp'))
  166.             return (false);
  167.         
  168.         if (!IACpushshortparam (i, 'idix'))
  169.             return (false);
  170.         
  171.         if (!IACsendverb (IACglobals.event, &reply))
  172.             return (false);
  173.         
  174.         IACglobals.reply = &reply;
  175.         
  176.         IACglobals.event = &reply;
  177.         
  178.         fl = IACgetbinaryparam (keyDirectObject, (Handle *) &hmenu);
  179.         
  180.         IACdisposeverb (&reply);
  181.         
  182.         if (!fl)
  183.             return (false);
  184.         
  185.         (**hm) [i].hmenu = hmenu;
  186.         } /*for*/
  187.     
  188.     return (true);
  189.     } /*GetMenuHandles*/
  190.  
  191.  
  192. static pascal Boolean GetSharedMenus (short firstresource) {
  193.     
  194.     /*
  195.     call the menu server to get a menuarray, keyed off of our application id.
  196.     
  197.     firstresource is the starting id to be used for the menus; if there are 
  198.     n menus, their ids will range from firstresource to firstresource + n - 1.
  199.     */
  200.     
  201.     AppleEvent event, reply;
  202.     register short fl;
  203.     OSType id;
  204.     
  205.     if (!IACnewverb (MSglobals.serverid, MSglobals.serverid, 'gmry', &event))
  206.         return (false);
  207.         
  208.     IACglobals.event = &event;
  209.     
  210.     if (!IACpushlongparam (MSglobals.clientid, 'menp'))
  211.         return (false);
  212.     
  213.     if (!IACpushshortparam (firstresource, 'res1'))
  214.         return (false);
  215.         
  216.     if (!IACsendverb (&event, &reply))
  217.         return (false);
  218.         
  219.     IACglobals.event = &reply;
  220.     
  221.     fl = IACgetbinaryparam (keyDirectObject, (Handle *) &MSglobals.hsharedmenus);
  222.     
  223.     IACdisposeverb (&reply);
  224.     
  225.     if (!fl)
  226.         return (false);
  227.     
  228.     return (GetMenuHandles ());
  229.     } /*GetSharedMenus*/
  230.  
  231.  
  232. pascal Boolean DisposeSharedMenus (void) {
  233.     
  234.     /*
  235.     completely dispose of the menuarray and the menu handles it contains.
  236.     
  237.     10/10/91 DW: check for no shared menus before disposing, save code if 
  238.     its ever called from more than one place. also set the global handle to
  239.     nil after disposing and redraw the menu bar.
  240.     */
  241.     
  242.     register hdlmenuarray hm = MSglobals.hsharedmenus;
  243.     register short i;
  244.     register short ctmenus;
  245.     tysharedmenurecord item;
  246.     
  247.     if (hm == nil) /*no shared menus to toss*/
  248.         return (true);
  249.     
  250.     ctmenus = CountMenuArray ();
  251.     
  252.     for (i = 0; i < ctmenus; i++) {
  253.         
  254.         item = (**hm) [i];
  255.         
  256.         if (item.flinserted)
  257.             DeleteMenu (item.idmenu);
  258.         
  259.         DisposeMenu (item.hmenu);
  260.         } /*for*/
  261.     
  262.     DisposHandle ((Handle) hm);
  263.     
  264.     MSglobals.hsharedmenus = nil;
  265.     
  266.     DrawMenuBar ();
  267.     
  268.     return (true);
  269.     } /*DisposeSharedMenus*/
  270.  
  271.  
  272. pascal Boolean IsSharedMenu (short idmenu) {
  273.     
  274.     /*
  275.     return true if the indicated menu is one of the shared menus.
  276.     */
  277.     
  278.     register hdlmenuarray hm = MSglobals.hsharedmenus;
  279.     register short ct, i;
  280.     tysharedmenurecord item;
  281.     
  282.     ct = CountMenuArray ();
  283.     
  284.     for (i = 0; i < ct; i++) {
  285.         
  286.         item = (**hm) [i];
  287.         
  288.         if (item.idmenu == idmenu)
  289.             return (true);
  290.         } /*for*/
  291.         
  292.     return (false);
  293.     } /*IsSharedMenu*/
  294.  
  295.  
  296. pascal Boolean EnableSharedMenus (Boolean flenable) {
  297.     
  298.     /*
  299.     Enables or disables the the menus in the specified menu array.
  300.     
  301.     Always returns true.
  302.     */
  303.     
  304.     register hdlmenuarray hm = MSglobals.hsharedmenus;
  305.     register short i;
  306.     register short ctmenus;
  307.     register MenuHandle hmenu;
  308.     
  309.     ctmenus = CountMenuArray ();
  310.     
  311.     for (i = 0; i < ctmenus; i++) {
  312.         
  313.         hmenu = (**hm) [i].hmenu;
  314.         
  315.         if (flenable)
  316.             EnableItem (hmenu, 0);
  317.         else
  318.             DisableItem (hmenu, 0);
  319.         } /*for*/
  320.     
  321.     DrawMenuBar ();
  322.     
  323.     return (true);
  324.     } /*EnableSharedMenus*/
  325.  
  326.  
  327. pascal Boolean RunSharedMenuItem (short idmenu, short iditem) {
  328.      
  329.     /*
  330.     call the menu server to run the script linked to the indicated menu item.
  331.     
  332.     the script will execute asynchonously, after this call returns.
  333.     */
  334.     
  335.     AppleEvent event, reply;
  336.     OSType id;
  337.     Boolean fl;
  338.     long refcon;
  339.     
  340.     if (!IACnewverb (MSglobals.serverid, MSglobals.serverid, 'runm', &event))
  341.         return (false);
  342.     
  343.     IACglobals.event = &event;
  344.     
  345.     if (!IACpushlongparam (MSglobals.clientid, 'menp'))
  346.         return (false);
  347.     
  348.     if (!IACpushshortparam (idmenu, 'mid '))
  349.         return (false);
  350.     
  351.     if (!IACpushshortparam (iditem, 'mitm'))
  352.         return (false);
  353.     
  354.     if (!IACsendverb (&event, &reply))
  355.         return (false);
  356.         
  357.     IACglobals.event = &reply;
  358.         
  359.     fl = IACgetlongparam (keyDirectObject, &refcon);
  360.     
  361.     IACdisposeverb (&reply);
  362.     
  363.     return (fl && (refcon != 0));
  364.     } /*RunSharedMenuItem*/
  365.  
  366.  
  367. pascal Boolean CheckSharedMenus (idinsertafter) short idinsertafter; {
  368.     
  369.     /*
  370.     call this from your main event loop after receiving and processing every
  371.     event. if the menus need updating, we send a message to the server asking
  372.     for our shared menus.
  373.     
  374.     if we load menus, they are assigned resource ids starting with idinsertafter.
  375.     this number must be less than 255 to allow for hierarchic menus, and must be
  376.     small enough so that no menu has an id of greater than 255. 
  377.     
  378.     9/28/91 DW: only update menus if we're the front process. this catches the
  379.     delay on re-loading a changed menu structure on the Multifinder switch. No
  380.     extra burden on the script writer editing the menu bar.
  381.     */
  382.         
  383.     if (!ProcessInForeground ()) /*only update menus if we're the front process*/
  384.         return (true);
  385.     
  386.     if (!MSglobals.fldirtysharedmenus) /*no need for an update, return quickly*/
  387.         return (true);
  388.         
  389.     DisposeSharedMenus ();
  390.     
  391.     if (ServerIsRunning ()) {
  392.     
  393.         if (GetSharedMenus (idinsertafter)) {
  394.     
  395.             InstallSharedMenus (0); /*install to the right of all other menus*/
  396.             
  397.             DrawMenuBar ();
  398.             }
  399.         
  400.         MSglobals.fldirtysharedmenus = false;
  401.         }
  402.         
  403.     else { /*server not running, menus have been updated (ie there are no shared menus*/
  404.     
  405.         MSglobals.fldirtysharedmenus = false;
  406.         }
  407.         
  408.     return (true);
  409.     } /*CheckSharedMenus*/
  410.     
  411.     
  412. pascal Boolean SharedScriptRunning () {
  413.     
  414.     /*
  415.     returns true if a shared script is currently running, false otherwise.
  416.     
  417.     it's provided so that an application can intelligently handle cmd-period
  418.     script termination in its keystroke handling routine.
  419.     */
  420.     
  421.     return (MSglobals.flscriptrunning);
  422.     } /*SharedScriptRunning*/
  423.     
  424.     
  425. pascal Boolean CancelSharedScript () {
  426.     
  427.     /*
  428.     call this when the user presses cmd-period or otherwise indicates to you that
  429.     he or she wants the currently running script to be halted. we record the fact
  430.     in the globals record. the next time we receive a message from the menu server
  431.     we'll send back an error, indicating that the script has been cancelled.
  432.     */
  433.     
  434.     if (MSglobals.flscriptrunning)
  435.         MSglobals.flscriptcancelled = true;
  436.         
  437.     return (true);
  438.     } /*CancelSharedScript*/
  439.     
  440.     
  441. pascal Boolean SharedMenuHit (idmenu, iditem) short idmenu, iditem; {
  442.  
  443.     /*
  444.     returns true if the indicated menu and item indicate a shared menu item.
  445.     
  446.     if not, we return false -- the item is in one of your menus, you should
  447.     process the command as you normally would.
  448.     
  449.     we send an IAC message to the menu server, requesting that the script
  450.     linked into that item be run.
  451.     
  452.     we disable the shared menus, awaiting a 'done' message to re-enable them.
  453.     */
  454.  
  455.     if (!IsSharedMenu (idmenu)) /*not a shared menu*/
  456.         return (false);
  457.         
  458.     HiliteMenu (0);
  459.         
  460.     if (RunSharedMenuItem (idmenu, iditem)) {
  461.     
  462.         MSglobals.flscriptrunning = true;
  463.     
  464.         EnableSharedMenus (false);
  465.         }
  466.             
  467.     return (true);
  468.     } /*SharedMenuHit*/
  469.     
  470.  
  471. pascal Boolean SharedScriptCancelled (event, reply) AppleEvent *event, *reply;{
  472.     
  473.     /*
  474.     call this routine in each Apple event message handler that could conceivably 
  475.     be used in a script being run by the menu server. if we return false continue
  476.     processing the message as you normally would. if we return true, that means
  477.     that the script that's running has been cancelled by the user; you should 
  478.     return noErr from your Apple event handler when we return true.
  479.     
  480.     before we return true, we reply to the message on behalf of the message
  481.     handler. we send a specific error code of 6, this should be interpreted by
  482.     the scripting system as "stop running the script, but don't display an
  483.     error dialog.
  484.     
  485.     we admit this mechanism is somewhat klunky, but it proved too difficult to have
  486.     Frontier be ready to respond to a "Cancel Script" Apple event while running
  487.     the script and also giving time slices to agents.
  488.     
  489.     10/21/91 DW: thanks to Kevin Calhoun (Apple) we can tell who sent the message.
  490.     so we only reply with an error if the message arrived from the shared menu
  491.     server. it's nice to close this loop!
  492.     */
  493.  
  494.     OSType sender;
  495.     Str255 s;
  496.     
  497.     if (MSglobals.flscriptcancelled && MSglobals.flscriptrunning) {
  498.         
  499.         IACglobals.event = event;
  500.         
  501.         if (IACgetsender () == MSglobals.serverid) { /*sender is shared menu server*/
  502.         
  503.             MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
  504.             
  505.             s [0] = (char) 0; /*set length to 0*/
  506.             
  507.             IACglobals.reply = reply;
  508.         
  509.             IACreturnerror (6, s); /*server watches for this special error code*/
  510.             
  511.             return (true);
  512.             }
  513.         }
  514.         
  515.     return (false); /*script not cancelled, keep processing message*/
  516.     } /*SharedScriptCancelled*/
  517.     
  518.     
  519. static pascal OSErr HandleMenuDirty (event, reply, refcon) AppleEvent *event, *reply; long refcon; {
  520.     
  521.     /*
  522.     this Apple event handler is called when the application's menu bar has been 
  523.     edited by the script writer in the menu server's menu editor.
  524.     
  525.     we just record the dirty-ness of the menus in a boolean, we'll actually re-
  526.     load the menus when we become the foreground process.
  527.     */
  528.     
  529.     MSglobals.fldirtysharedmenus = true;
  530.     
  531.     return (noErr);
  532.     } /*HandleMenuDirty*/
  533.     
  534.     
  535. static pascal OSErr HandleScriptComplete (event, reply, refcon) AppleEvent *event, *reply; long refcon; {
  536.     
  537.     /*
  538.     this Apple event handler is called when a menu script has completed running.
  539.     
  540.     we update a couple of menu-sharing globals and re-enable the shared menus.
  541.     
  542.     10/8/91 DW: added callback to support Applet Manager.
  543.     */
  544.     
  545.     MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
  546.     
  547.     EnableSharedMenus (true);
  548.     
  549.     if (MSglobals.scriptcompletedcallback != nil)
  550.         (*MSglobals.scriptcompletedcallback) ();
  551.     
  552.     return (noErr);
  553.     } /*HandleScriptComplete*/
  554.     
  555.     
  556. pascal Boolean InitSharedMenus () {
  557.  
  558.     /*
  559.     sets the program up for menu sharing. we initialize the fields of MSglobals. 
  560.     
  561.     then we get the creator id of the application we're running inside of. the menu
  562.     sharing server will need this information to be passed in an IAC message when
  563.     we're requesting our menus. 
  564.     
  565.     next, we check to see if we're running on a version of the Mac OS that supports
  566.     Apple events. if not, we return false. otherwise we install two Apple event
  567.     message handlers -- one to catch the "menu needs update" message, and another
  568.     to handle the "script has completed" message.
  569.     */
  570.     
  571.     MSglobals.serverid = 'LAND'; /*Frontier's creator id*/
  572.     
  573.     MSglobals.clientid = 0;
  574.     
  575.     MSglobals.hsharedmenus = nil; /*haven't loaded shared menus yet*/
  576.     
  577.     MSglobals.fldirtysharedmenus = true; /*force update 1st time thru event loop*/
  578.     
  579.     MSglobals.flscriptcancelled = false; /*script hasn't been cancelled*/
  580.     
  581.     MSglobals.flscriptrunning = false; /*no menu script running*/
  582.     
  583.     MSglobals.clientid = GetProcessCreator ();
  584.     
  585.     MSglobals.scriptcompletedcallback = nil;
  586.     
  587.     if (!IACinit ()) /*Apple events aren't present, or otherwise couldn't init*/
  588.         return (false);
  589.     
  590.     if (!IACinstallhandler (MSglobals.clientid, 'updm', (ProcPtr) &HandleMenuDirty))
  591.         return (false);
  592.     
  593.     if (!IACinstallhandler (MSglobals.clientid, 'done', (ProcPtr) &HandleScriptComplete))
  594.         return (false);
  595.     
  596.     return (true);
  597.     } /*InitSharedMenus*/
  598.  
  599.  
  600.