menubar.c

Go to the documentation of this file.
00001 
00002 /*  $Id: menubar.c 1200 2006-04-05 22:19:55Z karstenw $    */
00003 
00004 /******************************************************************************
00005 
00006     UserLand Frontier(tm) -- High performance Web content management,
00007     object database, system-level and Internet scripting environment,
00008     including source code editing and debugging.
00009 
00010     Copyright (C) 1992-2004 UserLand Software, Inc.
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025 
00026 ******************************************************************************/
00027 
00028 #include "frontier.h"
00029 #include "standard.h"
00030 
00031 #ifdef MACVERSION
00032     #include <uisharing.h>
00033     #include "langipc.h"
00034 #endif
00035 
00036 #include "cursor.h"
00037 #include "memory.h"
00038 #include "kb.h"
00039 #include "launch.h"
00040 #include "menu.h"
00041 #include "ops.h"
00042 #include "strings.h"
00043 #include "shellmenu.h"
00044 #include "menubar.h"
00045 #include "process.h"
00046 #include "meprograms.h"
00047 /*
00048 12/27/96 dmb: windows port. use menu.c routines exclusively.
00049 */
00050 
00051 
00052 /*
00053 id of menu at stays to right of all custom menus.  set to zero if no main 
00054 menu stays to the right
00055 */
00056 #ifdef MACVERSION
00057     #define rightmainmenu windowsmenu
00058 #endif
00059 
00060 #ifdef WIN95VERSION
00061     static long rightmainmenu = -2;
00062 #endif
00063 
00064 /*
00065 rules for resource numbers -- all menu ids generated here must be no greater 
00066 than 255 -- since the hierarchic links in the Mac menu manager are stored as
00067 a character.  Actaully, the range is further limited to 0-235; the rest are 
00068 reserved for desk accessories. Plus, Frontier uses 128 - 133 or so. So we'll 
00069 us 136 - 235. For menu sharing, a different base menu id can be pass in.
00070 */
00071 #ifdef MACVERSION
00072     #define defaultbasemenuid (lasthiermenu + hiermenuincrement)
00073 #endif
00074 
00075 #ifdef WIN95VERSION
00076     /*
00077     2006-02-25 aradke: on windows, the menu with the highest id can be
00078         a main menu or a hierarchic (sub)menu. deal with it.
00079     */
00080     #define defaultbasemenuid ((max(lastmainmenu, lasthiermenu) / hiermenuincrement) + 1)
00081 #endif
00082 
00083 hdlmenubarlist menubarlist = nil;
00084 
00085 tymenubarcallbacks menubarcallbacks = {nil, nil};
00086 
00087 
00088 static hdlmenubarstack menubardata = nil;
00089 
00090 static boolean fldirtymenubar = false;
00091 
00092 
00093 #define ctmenubarglobalsstack 3 /*we can remember menubar contexts up to 3 levels deep*/
00094 
00095 static short topmenubarglobals = 0;
00096 
00097 static hdlmenubarstack menubarglobalsstack [ctmenubarglobalsstack];
00098 
00099 
00100 
00101 
00102 #ifdef WIN95VERSION
00103 
00104     static boolean BitTst (char *x, long n) {
00105 
00106         x += n / 8;
00107 
00108         return ((*x & (0x0080 >> (n % 8))) != 0);
00109         } /*BitTst*/
00110 
00111 
00112     static void BitSet (char *x, long n) {
00113 
00114         x += n / 8;
00115 
00116         *x |= (0x0080 >> (n % 8));
00117         } /*BitTst*/
00118 
00119 
00120     static void BitClr (char *x, long n) {
00121 
00122         x += n / 8;
00123 
00124         *x &= ~(0x0080 >> (n % 8));
00125         } /*BitTst*/
00126 
00127 #endif
00128 
00129 
00130 boolean pushmenubarglobals (hdlmenubarstack hstack) {
00131     
00132     /*
00133     4/22/91 dmb: this routine replaces the old mesetglobals calls; it 
00134     establishes the indicated menubar stack as the current one, and 
00135     sets up the corresponding outline globals.
00136     
00137     with the addition of menubaroutline to the menubarstack structure, and 
00138     the use of this routine, we are now reasonable ignorant of menudata
00139     
00140     4/21/93 dmb: two years later... make this a true push/pop, up to 3 levels
00141     */
00142     
00143     assert (topmenubarglobals < ctmenubarglobalsstack);
00144     
00145     menubarglobalsstack [topmenubarglobals++] = menubardata;
00146     
00147     menubardata = hstack;
00148     
00149     if (hstack != nil)
00150         oppushoutline ((**hstack).menubaroutline);
00151     
00152     return (true);
00153     } /*pushmenubarglobals*/
00154 
00155 
00156 boolean popmenubarglobals (void) {
00157     
00158     if (menubardata != nil)
00159         oppopoutline ();
00160     
00161     assert (topmenubarglobals > 0);
00162     
00163     menubardata = menubarglobalsstack [--topmenubarglobals];
00164     
00165     return (true);
00166     } /*popmenubarglobals*/
00167 
00168 
00169 static boolean pushmenubarlist (hdlmenubarstack hstack) {
00170     
00171     /*
00172     link the indicated menubar into the menubarlist
00173     */
00174     
00175     return (listlink ((hdllinkedlist) menubarlist, (hdllinkedlist) hstack));
00176     } /*pushmenubarlist*/
00177 
00178 
00179 static boolean popmenubarlist (hdlmenubarstack hstack) {
00180     
00181     /*
00182     unlink the indicated menubar from the menubarlist
00183     */
00184     
00185     return (listunlink ((hdllinkedlist) menubarlist, (hdllinkedlist) hstack));
00186     } /*popmenubarlist*/
00187 
00188 
00189 static boolean meallocmenuid (short *id) {
00190     
00191     /*
00192     12/27/96 dmb: windows port
00193     */
00194 
00195     register short i;
00196     register hdlmenubarlist hlist = menubarlist;
00197     register byte *pbitmap;
00198     boolean flFound = false;
00199     #ifdef MACVERSION
00200         //9/1/00 Timothy Paustian
00201         //got rid of nasty use of direct memory access.
00202         //not allowed in carbon
00203         #if TARGET_API_MAC_CARBON == 1
00204         MenuBarHandle MenuList = nil;
00205         MenuList = GetMenuBar();
00206         #else
00207         #define MenuList (*(Handle *)0xA1C)
00208         #endif      
00209     #endif
00210 
00211     if (hlist == nil)
00212         return (false);
00213     
00214     pbitmap = (**hlist).menubitmap;
00215     
00216     for (i = 0; i < maxmenus; i++) {
00217         
00218         if (!BitTst (pbitmap, i)) { /*found one not in use*/
00219             
00220             BitSet (pbitmap, i);
00221             
00222             *id = (**hlist).basemenuid + i;
00223             
00224             #ifdef MACVERSION
00225                 if ((MenuList != nil) && (GetMenuHandle (*id) != nil)) /*2.1a6 dmb: in use by someone!*/
00226                     continue;
00227             #endif
00228             
00229             #ifdef WIN95VERSION
00230                 *id *= 100; // 4.18.97 dmb: leave room for 99 items with their own, sequenced ids
00231             #endif
00232             
00233             flFound = true;
00234             break;
00235             }
00236         } /*for*/
00237     #if MACVERSION && TARGET_API_MAC_CARBON
00238         //Code change by Timothy Paustian Tuesday, September 5, 2000 9:27:35 PM
00239         //Only dispose of in carbon
00240         if(MenuList != nil)
00241             DisposeMenuBar(MenuList);
00242     #endif
00243     return (flFound); /*all menu ids are in use*/
00244     } /*meallocmenuid*/
00245 
00246 
00247 static void mefreemenuid (short id) {
00248     
00249     register hdlmenubarlist hlist = menubarlist;
00250     
00251     #ifdef WIN95VERSION
00252         id /= 100;
00253     #endif
00254 
00255     if ((hlist != nil) && (id > 0))
00256         BitClr ((**hlist).menubitmap, id - (**hlist).basemenuid);
00257     } /*mefreemenuid*/
00258 
00259 
00260 static void meremovemenu (const tymenubarstackelement *menuinfo) {
00261 
00262     if ((*menuinfo).flbuiltin)
00263         deleteallmenuitems ((*menuinfo).hmenu, (*menuinfo).ctbaseitems);
00264     
00265     else
00266         removemenu ((*menuinfo).idmenu);
00267     } /*meremovemenu*/
00268 
00269 
00270 static short medeletemenu (hdlmenubarstack hstack, short ix, boolean flactive) {
00271     
00272     /*
00273     delete the menubarstack element at index ix.
00274     
00275     xxx 2.1b5 dmb: for some reason, on my machine (IIfx, 7.1), the code for 
00276     DisposeMenu seems to be patched, event when booting w/extension disabled. 
00277     the patched code always calls ReleaseResource, while the ROM code makes 
00278     sure it's a resource first. The menus we dispose of here are never made 
00279     from resources, and this is resuling in a hang in ReleaseResource under 
00280     certain conditions. To easier way to avoid the problem is to just dispose 
00281     the handle instead of calling DisposeMenu.
00282     
00283     update: I think it's a Talking Moose conflict, and affects much more than 
00284     just this. bleah!
00285     */
00286     
00287     tymenubarstackelement *pitem = (**hstack).stack + ix;
00288     
00289     if ((*pitem).idmenu != -1) { /*a menu is allocated*/
00290 
00291         if (flactive)
00292             meremovemenu (pitem);
00293             
00294         if (!(*pitem).flbuiltin)
00295             disposemenu ((*pitem).hmenu);
00296         }
00297     
00298     return ((*pitem).idmenu);
00299     } /*medeletemenu*/
00300 
00301 
00302 static void medeletemenubarentry (short ix) {
00303     
00304     /*
00305     delete the menubarstack element at index ix.
00306     
00307     1/24/91 dmb: adjust ixdeletedmenu if it slides down
00308     */
00309     
00310     register hdlmenubarstack hs = menubardata;
00311     register short i;
00312     register short topstack;
00313     register short idmenu;
00314     
00315     idmenu = medeletemenu (hs, ix, true);
00316     
00317     topstack = --(**hs).topstack; /*one less item in the stack*/
00318     
00319     for (i = ix; i < topstack; i++) /*slide all elements to the right of ix down*/
00320         (**hs).stack [i] = (**hs).stack [i + 1];
00321     
00322     if ((**hs).ixdeletedmenu > ix)
00323         --(**hs).ixdeletedmenu;
00324     
00325     mefreemenuid (idmenu); /*allow the menu id to be re-used*/
00326     } /*medeletemenubarentry*/
00327 
00328 
00329 static boolean mepushmenubarstack (const tymenubarstackelement *pitem) {
00330     
00331     register hdlmenubarstack hs = menubardata;
00332     
00333     if ((**hs).topstack >= ctmenubarstack) /*too many menus*/
00334         return (false);
00335     
00336     (**hs).stack [(**hs).topstack++] = *pitem; /*assign and bump stack top*/
00337     
00338     return (true);
00339     } /*mepushmenubarstack*/
00340 
00341 
00342 void medirtymenubar (void) {
00343     
00344     fldirtymenubar = true;
00345     
00346     shellforcemenuadjust ();
00347     } /*medirtymenubar*/
00348 
00349 
00350 void meupdatemenubar (void) {
00351     
00352     drawmenubar ();
00353     
00354     fldirtymenubar = false;
00355     } /*meupdatemenubar*/
00356 
00357 
00358 void mecheckmenubar (void) {
00359     
00360     if (fldirtymenubar)
00361         meupdatemenubar ();
00362     } /*mecheckemenubar*/
00363 
00364 
00365 static boolean mefindinmenubar (hdlheadrecord hnode, boolean flfindtitle, short *ixstack, short *itemnumber) {
00366     
00367     /*
00368     search the menubar data structure for the indicated outline node.  effectively
00369     maps a node onto the machine's menubar data structure.
00370     
00371     return an index into the menubar stack, and the item number in that menu for
00372     the item.  if the item number is 0, then the node generated the entire menu.
00373     
00374     if flallowhierarchic is false then we return the menu item for a hierarchic
00375     menu, not the menu itself.  think about it -- when you're editing text you want
00376     to edit the menu item that stands for the hierarchic menu, not the title of
00377     the hierarchic menu (which isn't even displayed anywhere!)...
00378     
00379     this is necessary because hierarchic menus have dual lives -- they are menus
00380     but they also appear as menu items.
00381     
00382     6/25/90 dmb:  replaced flallowhierarchic with flfindtitle.  now, searching for 
00383     titles vs. items is explicit and mutually exclusive
00384     
00385     2.1b3 dmb: never traverse the outline structure of the deleted item
00386 
00387     7.0b30 PBS: check for nil handle -- the menu outline may have changed behind our back.
00388     */
00389     
00390     register short i, ct;
00391     register hdlheadrecord h, hnext;
00392     register short topstack;
00393     register hdlmenubarstack hs = menubardata;
00394     
00395     topstack = (**hs).topstack;
00396     
00397     for (i = 0; i < topstack; i++) {
00398         
00399         h = (**hs).stack [i].hnode;
00400 
00401         if (flfindtitle) {
00402         
00403             if (h == hnode) { /*found match -- it's a whole menu*/
00404 
00405                 *ixstack = i;
00406             
00407                 *itemnumber = 0; /*indicate the menu itself*/
00408             
00409                 return (true);
00410                 }
00411             }
00412         else {
00413             
00414             if (i == (**hs).ixdeletedmenu) /*2.1b3: deleted, outline structure isn't valid*/
00415                 continue;
00416             
00417             ct = 1; /*indicate the first item in the menu*/
00418             
00419             hnext = (**h).headlinkright; /*start with the first sub*/
00420             
00421             while (h != hnext) { /*haven't reached the end of the menu outline*/
00422                 
00423                 if (hnext == nil) /*7.0b30 PBS: defensive driving -- the menu outline may have changed behind our back*/
00424                     break;
00425 
00426                 h = hnext;
00427                 
00428                 if (h == hnode) { /*found match on one of the menu items*/
00429                     
00430                     *ixstack = i;
00431                     
00432                     *itemnumber = ct + (**hs).stack [i].ctbaseitems;
00433                     
00434                     return (true);
00435                     }
00436                 
00437                 ct++;
00438 
00439                 hnext = (**h).headlinkdown;
00440                 } /*while*/
00441             }
00442         } /*for*/
00443         
00444     return (false); /*search failed*/
00445     } /*mefindinmenubar*/
00446 
00447 
00448 static boolean mebuildmenu (hdlheadrecord, boolean, tymenubarstackelement *, boolean);
00449 
00450 static void meactivatemenus (hdlmenubarstack hstack, boolean flactivate) {
00451     
00452     /*
00453     5.0b9 dmb: for builtin menus, call meremovemenu to remove the items.
00454     when activating, rebuild the source node to recreate the main menu
00455     items. submenus are still in the stack, so we don't want to recurse.
00456     */
00457 
00458     register short i;
00459     register short topstack;
00460     register hdlmenubarstack hs = hstack;
00461     tymenubarstackelement item;
00462     hdlheadrecord hnode;
00463     short ixstack;
00464     short itemnumber;
00465     
00466     if (hs == nil)
00467         return;
00468     
00469     if ((**hs).flactive == flactivate)
00470         return;
00471     
00472     pushmenubarglobals (hs);
00473     
00474     if (flactivate) { /*insert main menus in outline order*/
00475         
00476         opoutermostsummit (&hnode);
00477         
00478         while (true) {
00479             
00480             if (mefindinmenubar (hnode, true, &ixstack, &itemnumber)) {
00481 
00482                 item = (**hs).stack [ixstack];
00483 
00484                 if (item.flbuiltin)
00485                     mebuildmenu (item.hnode, false, &item, false);
00486                 else
00487                     insertmenu (item.hmenu, rightmainmenu);
00488                 }
00489             
00490             if (opislastsubhead (hnode)) /*all the menus are loaded*/
00491                 break;
00492             
00493             hnode = (**hnode).headlinkdown; /*advance to next menu definition*/
00494             }
00495         }
00496     
00497     topstack = (**hs).topstack;
00498     
00499     for (i = 0; i < topstack; i++) {
00500         
00501         item = (**hs).stack [i];
00502         
00503     //  if (item.flbuiltin)
00504     //      continue;
00505 
00506         if (item.idmenu != -1)
00507         {
00508             if (flactivate) {
00509                 
00510                 if (item.flhierarchic)
00511                     inserthierarchicmenu (item.hmenu, item.idmenu);
00512                 }
00513             else
00514                 meremovemenu (&item);
00515         }
00516     }
00517 
00518     (**hs).flactive = flactivate;
00519     
00520     medirtymenubar ();
00521     
00522     popmenubarglobals ();
00523     } /*meactivatemenus*/
00524 
00525 
00526 static void medisposemenus (hdlmenubarstack hstack) {
00527     
00528     /*
00529     11/4/90 DW: save and restore flactive around call to clearhandle.  this was 
00530     breaking the menu.buildmenubar () verb.  this is the stupid way to do it,
00531     but the guy who put this in should have checked that the buildmenubar verb
00532     was still working.  (1/21/91 dmb: who, me?)
00533     
00534     1/21/91 dmb: use mefreemenuid instead of clearbytes, which can wipe 
00535     out menus that belong to another menubar stack
00536     */
00537     
00538     register short i;
00539     register short topstack;
00540     register hdlmenubarstack hs;
00541     register boolean flactive;
00542     
00543     hs = hstack; /*move into register*/
00544     
00545     if (hs == nil)
00546         return;
00547     
00548     flactive = (**hs).flactive;
00549     
00550     topstack = (**hs).topstack;
00551     
00552     for (i = 0; i < topstack; i++)
00553         mefreemenuid (medeletemenu (hs, i, flactive));
00554     
00555     (**hs).topstack = 0;
00556     
00557     (**hs).ixdeletedmenu = -1;
00558     
00559     if (flactive)
00560         medirtymenubar ();
00561     } /*medisposemenus*/
00562 
00563 
00564 static boolean memainmenunode (hdlheadrecord hnode) {
00565 
00566     /*
00567     return true if hnode correspondes to a main (as opposed to 
00568     hierarchical) menu title; that is, if it is among the first level 
00569     of subheads below the menubar layer's summit.
00570 
00571     7/14/90 DW to DMB: add commentary, use parens in tests, no buried assignments,
00572     one symbol defined per line, why not use registers?
00573     
00574     7/19/90 dmb to DW:  gotcha.  however, can't use register for hmenubar since 
00575     its address is taken, and using a register for hleftlink would increase code 
00576     size since it's only referenced twice and no other registers are needed.
00577     
00578     10/23/90 dmb: now that layers are gone, this is quite simple
00579     */
00580     
00581     return ((**hnode).headlinkleft == hnode);
00582     } /*memainmenunode*/
00583 
00584 
00585 static byte mecmdkey (hdlheadrecord hnode) {
00586     
00587     return ((*menubarcallbacks.getcmdkeyroutine) (hnode));
00588     } /*mecmdkey*/
00589 
00590 
00591 static boolean melinkparentitem (hdlheadrecord hnode, hdlmenu hsubmenu, short idsubmenu) {
00592     
00593     /*
00594     set the item mark in the parent menu of hnode's hierarchical menu
00595     
00596     5.0a4 dmb: don't set the command key if we just set a hierarchical menu item
00597     */
00598     
00599     register hdlmenu hmenu;
00600     short ixstack, itemnumber;
00601     
00602     if (!mefindinmenubar (hnode, false, &ixstack, &itemnumber))
00603         return (false);
00604     
00605     hmenu = (**menubardata).stack [ixstack].hmenu; /*move into register*/
00606     
00607     sethierarchicalmenuitem (hmenu, itemnumber, hsubmenu, idsubmenu);
00608     
00609     if (hsubmenu == nil)
00610         setmenuitemcommandkey (hmenu, itemnumber, mecmdkey (hnode));
00611     
00612     return (true);
00613     } /*melinkparentitem*/
00614     
00615     
00616 static boolean meshouldhavemenu (hdlheadrecord hnode) {
00617     
00618     return (ophassubheads (hnode) || memainmenunode (hnode));
00619     } /*meshouldhavemenu*/
00620 
00621 
00622 static boolean megetmenuinfo (hdlheadrecord hnode, tymenubarstackelement *menuinfo) {
00623     
00624     /*
00625     hnode should be the title of a menu.  get the id of that menu.
00626     
00627     return false if the menu isn't found
00628     */
00629     
00630     short ixstack;
00631     short titlenumber;
00632     
00633     if (!mefindinmenubar (hnode, true, &ixstack, &titlenumber))
00634         return (false);
00635     
00636     *menuinfo = (**menubardata).stack [ixstack];
00637     
00638     return (true);
00639     } /*megetmenuinfo*/
00640 
00641 
00642 void mereducemenucodes (bigstring bs, boolean *flenabled, boolean *flchecked) {
00643 
00644     /*
00645     4.1b8 dmb: common code for mebuildmenu, memenuitemchanged, and mecheckformulas
00646     
00647     handles item disabling with '(', and checkmark with '!'
00648     
00649     7.0b23 PBS: no longer static -- used in oppopup.c for right-click menus.
00650     */
00651     
00652     *flenabled = (stringlength (bs) > 1) || (getstringcharacter (bs, 0) != '-');
00653         // !equalstrings (bs, (ptrstring) "\p-"); /*all dotted lines are disabled*/
00654     
00655     if (getstringcharacter (bs, 0) == '(' && lastchar (bs) != ')') { /*4.1b6 dmb*/
00656     
00657         deletestring (bs, 1, 1);
00658         
00659         *flenabled = false;
00660         }
00661     
00662     *flchecked = false;
00663     
00664     if ((stringlength (bs) > 1) && (getstringcharacter (bs, 0) == '!')) { /*4.1b8 dmb*/
00665     
00666         deletestring (bs, 1, 1);
00667         
00668         *flchecked = true;
00669         }
00670     } /*mereducemenucodes*/
00671 
00672 
00673 boolean mereduceformula (bigstring bs) {
00674     
00675     /*
00676     5.0a2 dmb: must preserve outlinedata in case a formual messes with it. 
00677     this can happen if the globals of an outline window are push/popped
00678     
00679     7.0b12 PBS: no longer static: used by oppopup.c for right-click menus.
00680     */
00681     
00682     boolean fl;
00683     hdloutlinerecord ho = outlinedata;
00684     
00685     fl = langreduceformula (bs);
00686     
00687     opsetoutline (ho);
00688     
00689     return (fl);
00690     } /*mereduceformula*/
00691 
00692 
00693 static boolean meinsertmenuitem (hdlmenu hmenu, short itemnumber, hdlheadrecord h, boolean flrecurse) {
00694 
00695     boolean flitemenabled, flitemchecked;
00696     char cmdchar;
00697     bigstring bs;
00698     tymenubarstackelement submenuinfo;
00699     
00700     cmdchar = 0;
00701     
00702     submenuinfo.idmenu = -1; /*force a menu id to be allocated, if we recurse*/
00703 
00704     if (ophassubheads (h)) { /*a hierarchic menu is called for*/
00705         
00706         if (flrecurse) {
00707         
00708             if (!mebuildmenu (h, true, &submenuinfo, true)) /*recurse*/
00709                 return (false);
00710             
00711             if (!mepushmenubarstack (&submenuinfo))
00712                 return (false);
00713             
00714             if ((**menubardata).flactive)
00715                 insertmenu (submenuinfo.hmenu, insertsubmenu); /*insert it as a submenu*/
00716             }
00717         else {
00718             
00719             if (!megetmenuinfo (h, &submenuinfo)) /*didn't find as title of hierarchical menu*/
00720                 return (false);
00721             }
00722         } /*has a submenu*/
00723         
00724     else { /*a terminal menu item*/
00725         
00726         cmdchar = mecmdkey (h);
00727         
00728         if (cmdchar == (char) ' ') /*a space is equal to nothing*/
00729             cmdchar = (char) 0;
00730         }
00731     
00732     getheadstring (h, bs);
00733     
00734     mereduceformula (bs); /*filter formulas*/
00735     
00736     mereducemenucodes (bs, &flitemenabled, &flitemchecked); /*4.1b8 dmb*/
00737     
00738     //pushmenuitem (hmenu, id, bs);
00739 
00740     Insertmenuitem (hmenu, itemnumber, bs);
00741     
00742     if (!flitemenabled)
00743         disablemenuitem (hmenu, itemnumber);
00744     
00745     if (submenuinfo.idmenu != -1)
00746         sethierarchicalmenuitem (hmenu, itemnumber, submenuinfo.hmenu, submenuinfo.idmenu);
00747     else
00748         if (flitemchecked)
00749             checkmenuitem (hmenu, itemnumber, true); /*4.1b8 dmb*/
00750 
00751     if (cmdchar != 0)
00752         setmenuitemcommandkey (hmenu, itemnumber, cmdchar);
00753     
00754     return (true);
00755     } /*meinsertmenuitem*/
00756 
00757 
00758 static boolean getmenutobuild (bigstring bsmenu, boolean flhierarchic, short *id, hdlmenu *hmenu, boolean *flbuiltin) {
00759     
00760     /*
00761     5.0a24 dmb: before allocating a new menu, see if we want to 
00762     build onto a builtin menu
00763     */
00764     
00765     boolean flinfrontier;
00766 
00767     #ifdef flcomponent
00768         THz savezone;
00769         #if TARGET_API_MAC_CARBON == 1
00770         savezone = LMGetApplZone();
00771         #else
00772          savezone = GetZone ();
00773          #endif
00774         
00775         #endif
00776     
00777     #ifdef MACVERSION
00778         flinfrontier = iscurrentapplication (langipcself);
00779     #else
00780         flinfrontier = true;
00781     #endif
00782     
00783     if (flinfrontier && !flhierarchic && shelltgetmainmenu (bsmenu, hmenu, id)) {
00784         
00785         *flbuiltin = true;
00786         
00787         #ifdef WIN95VERSION
00788             // about needs to be last, but resource compiler doesn't allow empty menus
00789             if (*id == helpmenu)
00790                 deletemenuitem (*hmenu, aboutitem);
00791         #endif
00792     
00793         return (true);
00794         }
00795     
00796     *flbuiltin = false;
00797 
00798     if (*id <= 0) { /*allocate a new menu id*/
00799         
00800         if (!meallocmenuid (id))
00801             return (false);
00802         }
00803     
00804     #ifdef flcomponent
00805         #if TARGET_API_MAC_CARBON == 1
00806         //Code change by Timothy Paustian Monday, June 26, 2000 9:29:46 PM
00807         //This code makes no sense to me.
00808         LMSetApplZone(LMGetApplZone());
00809         #else       
00810         SetZone (ApplicationZone ());
00811         #endif
00812         
00813     #endif
00814     
00815     *hmenu = Newmenu (*id, bsmenu);
00816     
00817     #ifdef flcomponent
00818         #if TARGET_API_MAC_CARBON == 1
00819         LMSetApplZone(savezone);
00820         #else
00821         SetZone (savezone);
00822         #endif
00823         
00824         
00825     #endif
00826     
00827     return (hmenu != nil);
00828     } /*getmenutobuild*/
00829 
00830 
00831 static boolean mebuildmenu (hdlheadrecord hnode, boolean flhierarchic, tymenubarstackelement *menuinfo, boolean flrecurse) {
00832     
00833     /*
00834     load a menu from the outline pointed to by hnode.  we return a handle to
00835     the menu data structure and the menu id.
00836     
00837     we recurse to handle a menu that has a submenu.
00838     
00839     4.1b2 dmb: call Newmenu in the (client) application zone
00840     
00841     4.1b6 dmb: if item begins with a paren, and doesn't end with one, disabled it
00842     */
00843     
00844     hdlmenu hmenu;
00845     short itemnumber;
00846     short id;
00847     bigstring bs;
00848     boolean flbuiltin;
00849 
00850     rollbeachball (); /*if operative, roll it*/
00851     
00852     if (!meshouldhavemenu (hnode))
00853         return (false);
00854     
00855     getheadstring (hnode, bs); /*get the menu title*/
00856     
00857     mereduceformula (bs); /*filter formulas*/
00858     
00859     id = (*menuinfo).idmenu;
00860     
00861     if (!getmenutobuild (bs, flhierarchic, &id, &hmenu, &flbuiltin))
00862         return (false);
00863 
00864     clearbytes (menuinfo, sizeof (tymenubarstackelement)); // set all field to zero
00865 
00866     (*menuinfo).hnode = hnode;
00867     
00868     (*menuinfo).idmenu = id; /*caller gets this returned value*/
00869     
00870     (*menuinfo).hmenu = hmenu; /*and this one too*/
00871     
00872     (*menuinfo).flenabled = true;
00873     
00874     (*menuinfo).flhierarchic = flhierarchic;
00875     
00876     (*menuinfo).flbuiltin = flbuiltin;
00877     
00878     (*menuinfo).ctbaseitems = countmenuitems (hmenu);
00879     
00880     if (opnosubheads (hnode))
00881         return (true);
00882     
00883     hnode = (**hnode).headlinkright; /*move to first subhead*/
00884     
00885     for (itemnumber = (*menuinfo).ctbaseitems + 1; ; itemnumber++) {
00886         
00887         if (!meinsertmenuitem (hmenu, itemnumber, hnode, flrecurse))
00888             return (false);
00889         
00890         if (opislastsubhead (hnode)) /*done with this menu*/
00891             return (true);
00892         
00893         hnode = (**hnode).headlinkdown; /*advance to next item*/
00894         } /*while*/
00895     } /*mebuildmenu*/
00896 
00897 
00898 boolean newmenubarlist (hdlmenubarlist *hlist) {
00899         
00900     if (!newclearhandle (longsizeof (tymenubarlist), (Handle *) hlist))
00901         return (false);
00902     
00903     #ifdef MACVERSION
00904         assert (defaultbasemenuid + maxmenus < 236);
00905     #endif
00906     
00907     (***hlist).basemenuid = defaultbasemenuid;
00908     
00909     return (true);
00910     } /*newmenubarlist*/
00911 
00912 
00913 void setcurrentmenubarlist (hdlmenubarlist hlist) {
00914     
00915     menubarlist = hlist;
00916     } /*setcurrentmenubarlist*/
00917 
00918 
00919 boolean activatemenubarlist (hdlmenubarlist hlist, boolean flactivate) {
00920     
00921     register hdlmenubarstack hstack;
00922     
00923     if (hlist == nil)
00924         return (true);
00925     
00926     hstack = (**hlist).hfirst;
00927     
00928     while (hstack != nil) {
00929         
00930         meactivatemenus (hstack, flactivate); /*checks for no change*/
00931         
00932         hstack = (**hstack).hnext;
00933         }
00934     
00935     (**hlist).flactive = flactivate;
00936     
00937     return (true);
00938     } /*activatemenubarlist*/
00939 
00940 
00941 boolean disposemenubarlist (hdlmenubarlist hmenubarlist) {
00942     
00943     register hdlmenubarlist hlist = hmenubarlist;
00944     register hdlmenubarstack h;
00945     register hdlmenubarstack hnext;
00946     
00947     if (hlist == nil) /*empty list*/
00948         return (true);
00949     
00950     h = (**hlist).hfirst;
00951     
00952     while (h != nil) {
00953         
00954         hnext = (**h).hnext;
00955         
00956         medisposemenubar (h);
00957         
00958         h = hnext; /*advance to next node*/
00959         } /*while*/
00960     
00961     disposehandle ((Handle) hlist);
00962     
00963     if (hlist == menubarlist)
00964         menubarlist = nil;
00965     
00966     return (true);
00967     } /*disposemenubarlist*/
00968 
00969 
00970 boolean medisposemenubar (hdlmenubarstack hstack) {
00971     
00972     register hdlmenubarstack hs = hstack;
00973     
00974     if ((hs != nil) && !(**hs).flclientowned)
00975         medisposemenus (hstack);
00976     
00977     popmenubarlist (hstack);
00978     
00979     disposehandle ((Handle) hstack);
00980     
00981     return (true);
00982     } /*medisposemenubar*/
00983 
00984 
00985 boolean menewmenubar (hdloutlinerecord houtline, hdlmenubarstack *hstack) {
00986     
00987     /*
00988     create a new, empty menubar data structure, linked into menubarlist.
00989 
00990     4.1b2 dmb: xxx - create stack in the (client) application zone
00991     */
00992     
00993     register hdlmenubarstack hs;
00994     
00995     #if 0
00996     
00997         THz savezone = GetZone ();
00998         
00999         SetZone (ApplicationZone ());
01000         
01001         *hstack = (hdlmenubarstack) NewHandleClear (sizeof (tymenubarstack));
01002         
01003         SetZone (savezone);
01004         
01005         hs = *hstack; /*move into register*/
01006         
01007         if (hs == nil) {
01008         
01009             memoryerror ();
01010             
01011             return (false);
01012             }
01013         
01014     #else
01015         
01016         if (!newclearhandle (sizeof (tymenubarstack), (Handle *) hstack))
01017             return (false);
01018     
01019         hs = *hstack; /*move into register*/
01020         
01021     #endif
01022     
01023     (**hs).menubaroutline = houtline;
01024     
01025     (**hs).ixdeletedmenu = -1; /*no halfway deleted menu*/
01026     
01027     /*
01028     if (pushmenubarlist (hs)) /%add it to the end of our list%/
01029         
01030         (**hs).flactive = (**menubarlist).flactive;
01031     */
01032     
01033     return (true);
01034     } /*menewmenubar*/
01035 
01036 
01037 boolean mebuildmenubar (hdlmenubarstack hstack) {
01038     
01039     /*
01040     build a menubar out of the summits in the menu outline structure.  each summit
01041     represents a menu, each sub under each summit is a first-level menu item.
01042     
01043     the menubar is a hierarchic structure, we map the outline hierarchy onto a 
01044     hierarchy in the menubar.
01045     
01046     7/14/90 DW: redraw the menubar after disposing of it.  better staging for
01047     the user when it's being called from the menu.buildmenubar verb.
01048     
01049     3/31/91 DW: added param to firstmenuid param.
01050     
01051     4/26/91 dmb: removed firstmenuid param; now covered by menubarlist field
01052     */
01053     
01054     register hdlheadrecord h; 
01055     hdlheadrecord hnode;
01056     tymenubarstackelement menuinfo;
01057     boolean fl = false;
01058     
01059     #ifdef WIN95VERSION
01060 
01061     hdlmenu hwindowmenu;
01062     MENUITEMINFO info;
01063 
01064     hwindowmenu = shellmenuhandle (windowsmenu);
01065 
01066     info.cbSize = sizeof (info);
01067     info.fMask = MIIM_ID;
01068     
01069     GetMenuItemInfo (hwindowmenu, 0, true, &info); // get the actual popup and all of it's info
01070 
01071     rightmainmenu = info.wID; //GetMenuItemID (hmenu, 0);
01072 
01073     #endif
01074 
01075     pushmenubarglobals (hstack); /*make sure menubardata, outlinedata are set up*/
01076     
01077     medisposemenus (hstack); /*get rid of any menus in the stack*/
01078     
01079     opoutermostsummit (&hnode);
01080     
01081     h = hnode; /*copy into register*/
01082     
01083     while (true) {
01084         
01085         menuinfo.idmenu = -1; /*allocate a new id*/
01086         
01087         if (mebuildmenu (h, false, &menuinfo, true)) { /*no error building the menu*/
01088             
01089             if (!mepushmenubarstack (&menuinfo)) 
01090                 break;
01091         
01092             if ((**menubardata).flactive)
01093                 if (!menuinfo.flbuiltin)
01094                     insertmenu (menuinfo.hmenu, rightmainmenu); /*add to menubar, after all others*/
01095             }
01096         
01097         if (opislastsubhead (h)) { /*all the menus are loaded*/
01098             
01099             medirtymenubar ();
01100             
01101             fl = true;
01102             
01103             break;
01104             }
01105         
01106         h = (**h).headlinkdown; /*advance to next menu definition*/
01107         } /*while*/
01108     
01109     popmenubarglobals ();
01110     
01111     return (fl);
01112     } /*mebuildmenubar*/
01113 
01114 
01115 static boolean meinsertmenu (const tymenubarstackelement *menuinfo) {
01116     
01117     hdlheadrecord hnode = (*menuinfo).hnode;
01118     hdlheadrecord hnext;
01119     tymenubarstackelement nextinfo;
01120     hdlmenubarstack hnextstack;
01121     
01122     if ((*menuinfo).flbuiltin)
01123         return (true);
01124 
01125     if ((*menuinfo).flhierarchic) 
01126         nextinfo.idmenu = -1;
01127     
01128     else {
01129         
01130         hnext = (**hnode).headlinkdown;
01131         
01132         if (hnext == hnode) { /*last menu in this menubarstack*/
01133             
01134             hnextstack = (**menubardata).hnext;
01135             
01136             if (hnextstack == nil) /*it's the last user-defined menu, insert at end of list*/
01137                 nextinfo.idmenu = (short) rightmainmenu;
01138             
01139             else {
01140                 
01141                 pushmenubarglobals (hnextstack);
01142                 
01143                 opoutermostsummit (&hnext);
01144                 
01145                 megetmenuinfo (hnext, &nextinfo);
01146                 
01147                 popmenubarglobals ();
01148                 }
01149             }
01150         else {
01151             
01152             megetmenuinfo (hnext, &nextinfo);
01153             }
01154         }
01155     
01156     return (insertmenu ((*menuinfo).hmenu, nextinfo.idmenu)); /*add to menubar, insert before idnext*/
01157     } /*meinsertmenu*/
01158 
01159 /*
01160 static void menubarchanged (hdlmenubarstack hstack) {
01161     
01162     (*menubarcallbacks.menubarchangedroutine) (hstack);
01163     } /%menubarchanged%/
01164 */
01165 
01166 boolean memenuitemchanged (hdlmenubarstack hstack, hdlheadrecord hnode) {
01167     
01168     /*
01169     called when the text or command key of hnode has changed.  it saves code
01170     to have one routine that does both, although usually only on or the 
01171     other has changed.
01172     
01173     returns true if we successfully changed the text of the indicated item.
01174     */
01175     
01176     register hdlmenubarstack hs = hstack;
01177     tymenubarstackelement menuinfo;
01178     bigstring bs;
01179     boolean flitemenabled, flitemchecked;
01180     short ixstack, itemnumber;
01181     hdlmenu hmenu;
01182     boolean fltitle;
01183     register boolean fl = false;
01184     
01185     if (hs == nil) //nothing to do
01186         return (true);
01187     
01188     pushmenubarglobals (hs);
01189     
01190     /*first locate as the title of a menu*/
01191 
01192     fltitle = mefindinmenubar (hnode, true, &ixstack, &itemnumber);
01193 
01194     if (fltitle) {
01195         
01196         /*
01197         since the menu manager doesn't let us change the title of a menu, we 
01198         need to recreate the menu from scratch.  however, we want to reuse the 
01199         same id so that our parent (if we have one) will still point to us.
01200         */
01201         
01202         short idmenu;
01203     //  boolean flhierarchic;
01204         
01205         menuinfo = (**hs).stack [ixstack];
01206 
01207         idmenu = medeletemenu (hs, ixstack, true);
01208         
01209         assert (idmenu == menuinfo.idmenu);
01210 
01211         if (!mebuildmenu (hnode, menuinfo.flhierarchic, &menuinfo, false)) { /*error building the menu*/
01212             
01213             mefreemenuid (idmenu); /*allow it to be reused*/
01214             
01215             goto exit;
01216             }
01217         
01218         (**hs).stack [ixstack] = menuinfo; /*update to new menu*/
01219         
01220         meinsertmenu (&menuinfo); /*add to menubar, in correct place*/
01221         
01222         if (!menuinfo.flhierarchic) { /*its name doesn't appear in a menu*/
01223             
01224             meupdatemenubar ();
01225 
01226             fl = true;
01227             
01228             goto exit;
01229             }
01230         }
01231 
01232     /*now locate the node as a menu item*/
01233 
01234     if (!mefindinmenubar (hnode, false, &ixstack, &itemnumber))
01235         goto exit;
01236 
01237     getheadstring (hnode, bs); 
01238     
01239     mereduceformula (bs); /*filter formulas*/
01240 
01241     mereducemenucodes (bs, &flitemenabled, &flitemchecked); /*4.1b8 dmb*/
01242     
01243     hmenu = (**hs).stack [ixstack].hmenu;
01244     
01245     setmenuitem (hmenu, itemnumber, bs);
01246     
01247     setmenuitemenable (hmenu, itemnumber, flitemenabled);
01248     // setmenuitemenable (hmenu, itemnumber, !equalstrings (bs, (ptrstring) "\p-"));
01249     
01250     if (!fltitle) { /*4.1b11 dmb: don't set check if we're a title*/
01251     
01252         checkmenuitem (hmenu, itemnumber, flitemchecked); /*4.1b8 dmb*/
01253         
01254         setmenuitemcommandkey (hmenu, itemnumber, mecmdkey (hnode));
01255         }
01256     
01257     fl = true;
01258     
01259     exit:
01260     
01261     /*
01262     menubarchanged (hs);
01263     */
01264     
01265     popmenubarglobals ();
01266     
01267     return (fl);
01268     } /*memenuitemchanged*/
01269 
01270 
01271 static short megetmenuindex (hdlmenu hmenu /*short id*/) {
01272     
01273     /*
01274     search the menubar data structure for the indicated menu id.
01275     
01276     return an index into the menubar stack, or -1 in not found.
01277     */
01278     
01279     register hdlmenubarstack hs = menubardata;
01280     register short i;
01281     register short topstack;
01282     
01283     topstack = (**hs).topstack;
01284     
01285     for (i = 0; i < topstack; i++) {
01286         
01287         //if ((**hs).stack [i].idmenu == id) /*found match -- it's a whole menu*/
01288         if ((**hs).stack [i].hmenu == hmenu)
01289             return (i);
01290         } /*for*/
01291     
01292     return (-1); /*search failed*/
01293     } /*megetmenuindex*/
01294 
01295 
01296 static void medeleteallmenubarentries (short ixstack) {
01297     
01298     /*
01299     delete the indicated entry from the menubarstack, as well as the entries 
01300     for any heirarchical menus subordinate to the menu of this entry.
01301     */
01302     
01303     register hdlmenubarstack hs = menubardata;
01304     register short ixmenu;
01305     register hdlmenu hmenu;
01306     register short ctitems;
01307     hdlmenu hsubmenu;
01308     /*
01309     short cmdchar;
01310     short idsub;
01311     */
01312 
01313     if (ixstack < 0) /*defensive driving*/
01314         return;
01315     
01316     hmenu = (**hs).stack [ixstack].hmenu; /*move into register*/
01317     
01318     ctitems = countmenuitems (hmenu);
01319     
01320     for (ixmenu = 1; ixmenu <= ctitems; ++ixmenu) {
01321         
01322         /*
01323         GetItemCmd (hmenu, ixmenu, &cmdchar);
01324         
01325         if (cmdchar == hMenuCmd) {
01326             
01327             GetItemMark (hmenu, ixmenu, &idsub);
01328             
01329             medeleteallmenubarentries (megetmenuindex (idsub));
01330             }
01331         */
01332         
01333         if (gethierarchicalmenuitem (hmenu, ixmenu, &hsubmenu))
01334             medeleteallmenubarentries (megetmenuindex (hsubmenu));
01335         }
01336     
01337     medeletemenubarentry (megetmenuindex (hmenu)); // was (**hmenu).menuID
01338     } /*medeleteallmenubarentries*/
01339 
01340 
01341 short mecheckdeletedmenu (short ixstack, boolean fldrawmenubar) {
01342 
01343     /*
01344     if ixstack is the deletedmenu, it is being reused.  otherwise, it needs to 
01345     be discarded.  return ixstack, adjusted for any deletion
01346     
01347     12/21/91 dmb: use new medeleteallmenubarentries to make sure that we don't 
01348     leave bogus entries in the stack for submenus of the deleted one.
01349     */
01350     
01351     register hdlmenubarstack hs = menubardata;
01352     register short ixdeletedmenu;
01353     
01354     if (hs == nil)
01355         return (ixstack);
01356     
01357     ixdeletedmenu = (**hs).ixdeletedmenu;
01358     
01359     if (ixdeletedmenu >= 0) {
01360         
01361         if (ixdeletedmenu != ixstack) { /*menu is not being re-inserted now*/
01362             
01363             fldrawmenubar = (fldrawmenubar && !(**hs).stack [ixdeletedmenu].flhierarchic);
01364             
01365             (**hs).ixdeletedmenu = ixstack; /*temp -- medeletemenubarentry will maintain position*/
01366             
01367             medeleteallmenubarentries (ixdeletedmenu); 
01368             
01369             ixstack = (**hs).ixdeletedmenu; /*grab adjusted value*/
01370             
01371             if (fldrawmenubar)
01372                 meupdatemenubar ();
01373             }
01374         
01375         (**hs).ixdeletedmenu = -1; /*no pending deletion*/
01376         }
01377     
01378     return (ixstack);
01379     } /*mecheckdeletedmenu*/
01380 
01381 
01382 static boolean mefindvisit (hdlheadrecord h, ptrvoid refcon) {
01383 
01384     return (h != (hdlheadrecord) refcon);
01385     } /*mefindvisit*/
01386 
01387 
01388 boolean memenuitemadded (hdlmenubarstack hstack, hdlheadrecord hnode) {
01389     
01390     /*
01391     called when something has been added in the menubar structure.
01392     */
01393     
01394     register hdlmenubarstack hs = hstack;
01395     short ixstack, itemnumber;
01396     tymenubarstackelement menuinfo;
01397     boolean flhierarchic, flwashierarchic;
01398     hdlheadrecord hmenubar;
01399     register boolean fl = false;
01400     
01401     if (hs == nil) //nothing to do
01402         return (true);
01403     
01404     pushmenubarglobals (hs);
01405     
01406     flhierarchic = !memainmenunode (hnode);
01407 
01408     flwashierarchic = true;
01409     
01410     /*
01411     look for hnode as the title of a menu.  if it is found, then this is the 
01412     second half of a move operation -- an unlink left it in the menu structure, 
01413     with ixdeletedmenu set accordingly to its index.
01414     */
01415     if (mefindinmenubar (hnode, true, &ixstack, &itemnumber)) { /*found as title?*/
01416         
01417         /*
01418         menu probably moved in the menu structure.  it may have even changed 
01419         from being a main menu to a heirarchical, or vice versa
01420         */
01421         register tymenubarstackelement *pitem;
01422         
01423         assert (ixstack == (**hs).ixdeletedmenu);
01424         
01425         ixstack = mecheckdeletedmenu (ixstack, false); /*should match*/
01426         
01427         pitem = (**hs).stack + ixstack;
01428         
01429         flwashierarchic = (*pitem).flhierarchic;
01430         
01431         /*
01432         if hnode should still have a menu, we'll need to remove it from the 
01433         menu manager's menubar structure, so we can re-insert it according to 
01434         its new status (i.e. hierarchical or not) below.  if hnode shouldn't have
01435         a menu, dispose of the menu and its related data
01436         */
01437         if (flhierarchic  &&  opnosubheads (hnode)) { /*shouldn't be a menu title anymore*/
01438             
01439             medeletemenubarentry (ixstack); /*dispose completely*/
01440             
01441             menuinfo.idmenu = -1;
01442             }
01443         else {
01444             (*pitem).flhierarchic = flhierarchic; /*update menubardata to new status*/
01445 
01446             menuinfo = (*pitem); /*this is the menu we'll re-insert below...*/
01447             
01448             meremovemenu (&menuinfo); /*remove from menu manager's structure*/
01449             }
01450         
01451         /*
01452         now look for hnode as a menu item
01453         */
01454         if (!mefindinmenubar (hnode, false, &ixstack, &itemnumber)) /*found as item?*/
01455             itemnumber = -1;
01456         }
01457     else {
01458         
01459         if (!mefindinmenubar (hnode, false, &ixstack, &itemnumber)) { /*found as item?*/
01460             
01461             /*
01462             didn't find under existing titles; see if this node belongs in the 
01463             menu bar at all
01464             */
01465             opoutermostsummit (&hmenubar);
01466             
01467             if (opsiblingvisiter (hmenubar, false, mefindvisit, (ptrvoid) hnode)) { /*not found in menubar outline*/
01468                 
01469                 mecheckdeletedmenu (-1, true); /*no match, draw menu bar*/
01470                 
01471                 fl = true;
01472                 
01473                 goto exit;
01474                 }
01475             
01476             itemnumber = -1;
01477             }
01478         
01479         ixstack = mecheckdeletedmenu (ixstack, false); /*no match*/
01480         
01481         /*
01482         we didn't find hnode as the title of a menu.  see if we need to build 
01483         a new hierarchy of menus for the suboutline
01484         */
01485         
01486         menuinfo.idmenu = -1; /*allocate a new id, if a menu is built*/
01487         
01488         if (meshouldhavemenu (hnode)) {
01489             
01490             if (!mebuildmenu (hnode, flhierarchic, &menuinfo, true)) /*error building the menu*/
01491                 goto exit;
01492             
01493             if (!mepushmenubarstack (&menuinfo)) /*error inserting*/
01494                 goto exit;
01495             }
01496         }
01497     
01498     /*
01499     if hnode has a menu, it should be available for insertion at this point.  if 
01500     idmenu is non-negative, it's ready to go
01501     */
01502     assert ((menuinfo.idmenu != -1) == (ophassubheads (hnode) || !flhierarchic));
01503     
01504     if (menuinfo.idmenu != -1)
01505         meinsertmenu (&menuinfo);
01506     
01507     /*if a main menu was moved or created, redraw the menu bar*/
01508     
01509     if (!flhierarchic  ||  !flwashierarchic)
01510         meupdatemenubar ();
01511     
01512     /*if hnode is a main menu, we're done!*/
01513     
01514     if (!flhierarchic) {
01515         
01516         fl = true;
01517         
01518         goto exit;
01519         }
01520     
01521     /*now deal with the parent menu, which may or may not already exist*/
01522     
01523     if (itemnumber > 0) { /*appears as an item in existing menu*/
01524         
01525         assert ((**hs).stack [ixstack].hnode == (**hnode).headlinkleft);
01526     
01527         fl = meinsertmenuitem ((**hs).stack [ixstack].hmenu, itemnumber, hnode, false);
01528         
01529         goto exit;
01530         }
01531     else
01532         flhierarchic = true; /*if it was a main menu, it would already exist*/
01533     
01534     hnode = (**hnode).headlinkleft;
01535     
01536     menuinfo.idmenu = -1;
01537     
01538     if (mebuildmenu (hnode, flhierarchic, &menuinfo, false)) { /*no error building the menu*/
01539         
01540         if (!mepushmenubarstack (&menuinfo)) 
01541             goto exit;
01542         
01543         meinsertmenu (&menuinfo); /*add to menubar, in correct place*/
01544         
01545         if (flhierarchic)
01546             melinkparentitem (hnode, menuinfo.hmenu, menuinfo.idmenu);
01547         }
01548     
01549     fl = true;
01550     
01551     exit:
01552     
01553     /*
01554     menubarchanged (hs);
01555     */
01556     
01557     popmenubarglobals ();
01558     
01559     return (fl);
01560     } /*memenuitemadded*/
01561 
01562 
01563 boolean memenuitemdeleted (hdlmenubarstack hstack, hdlheadrecord hnode) {
01564     
01565     /*
01566     called when something has been deleted in the menubar structure.
01567     
01568     2.1b3: since this is a deletion, it can't be the second helf of a 
01569     move, and any previosly-deleted menu should be flushed now.
01570 
01571     5.0a24 dmb: fixed bug when emptying a hierarchical menu; must 
01572     delete item before tossing menu [Win]
01573     */
01574     
01575     register hdlmenubarstack hs = hstack;
01576     short ixstack, itemnumber;
01577     hdlmenu hmenu;
01578     
01579     if (hs == nil) //nothing to do
01580         return (true);
01581     
01582     pushmenubarglobals (hs);
01583     
01584     mecheckdeletedmenu (-1, true); /*2.1b3 dmb: flush deleted menu unconditionally*/
01585     
01586     if (mefindinmenubar (hnode, true, &ixstack, &itemnumber)) { /*deleting a whole menu*/
01587         
01588         //2.1b3 mecheckdeletedmenu (ixstack, false); /*note match or flush previous deletion*/
01589         
01590         (**hs).ixdeletedmenu = ixstack; /*save for later, if not reinserted*/
01591         
01592         /*
01593         medeletemenubarentry (ixstack); 
01594         
01595         drawmenubar ();
01596         */
01597         }
01598     
01599     if (mefindinmenubar (hnode, false, &ixstack, &itemnumber)) { /*deleting a menu item, not a whole menu*/
01600         
01601         hmenu = (**hs).stack [ixstack].hmenu;
01602         
01603         deletemenuitem (hmenu, itemnumber);
01604         
01605         if ((**hs).stack [ixstack].flhierarchic  &&  countmenuitems (hmenu) == 0) {
01606             
01607             melinkparentitem ((**hs).stack [ixstack].hnode, nil, -1);
01608             
01609             medeletemenubarentry (ixstack);
01610             }
01611         }
01612     
01613     /*
01614     menubarchanged (hs);
01615     */
01616     
01617     popmenubarglobals ();
01618     
01619     return (true);
01620     } /*memenuitemdeleted*/ 
01621 
01622 
01623 boolean meinsertmenubar (hdlmenubarstack hstack) {
01624     
01625     /*
01626     add the indicated menubar stack to the menubarlist.
01627     */
01628     
01629     if (!pushmenubarlist (hstack))
01630         return (false);
01631     
01632     meactivatemenus (hstack, (**menubarlist).flactive);
01633     
01634     return (true);
01635     } /*meinsertmenubar*/
01636 
01637 
01638 boolean medeletemenubar (hdlmenubarstack hstack) {
01639     
01640     /*
01641     remove the indicated menubar stack from the menubarlist.
01642     */
01643     
01644     if (!popmenubarlist (hstack))
01645         return (false);
01646     
01647     meactivatemenus (hstack, false);
01648     
01649     return (true);
01650     } /*medeletemenubar*/
01651 
01652 
01653 boolean purgefrommenubarlist (long refcon) {
01654     
01655     /*
01656     5.1.5 dmb: remove all menubar stacks associated with the given refcon
01657     */
01658     
01659     register hdlmenubarlist hlist = menubarlist;
01660     register hdlmenubarstack hstack, hnext;
01661     
01662     if (hlist == nil)
01663         return (true);
01664     
01665     hstack = (**hlist).hfirst;
01666     
01667     while (hstack != nil) {
01668         
01669         hnext = (**hstack).hnext;
01670         
01671         if ((**hstack).refcon == refcon)
01672             medeletemenubar (hstack);
01673         
01674         hstack = hnext;
01675         }
01676     
01677     return (true);
01678     } /*purgefrommenubarlist*/
01679 
01680 
01681 boolean rebuildmenubarlist (void) {
01682     
01683     /*
01684     traverse the menubarlist, re-building all menubars from scratch.
01685     
01686     normally shouldn't need to be called, but we offer a verb that calls 
01687     this to force a refresh in case of bugs.
01688     */
01689     
01690     register hdlmenubarlist hlist = menubarlist;
01691     register hdlmenubarstack hstack;
01692     boolean fl = true;
01693     
01694     if (hlist == nil)
01695         return (true);
01696     
01697     hstack = (**hlist).hfirst;
01698     
01699     while (hstack != nil) {
01700         
01701         if (!mebuildmenubar (hstack))
01702             fl = false;
01703         else
01704             meactivatemenus (hstack, (**hlist).flactive); /*checks for no change*/
01705         
01706         hstack = (**hstack).hnext;
01707         }
01708     
01709     return (fl);
01710     } /*rebuildmenubarlist*/
01711 
01712 
01713 boolean melocatemenubarnode (hdlheadrecord hnode, hdloutlinerecord *houtline) {
01714     
01715     /*
01716     traverse the menubarlist, looking for the menu that contains hnode.
01717     
01718     set houtline to the outline associated with that menu's menubar.
01719     
01720     return true if successful, false if no menu was found containing hnode
01721     */
01722     
01723     register hdlmenubarlist hlist = menubarlist;
01724     register hdlmenubarstack hstack;
01725     short ixstack, itemnumber;
01726     
01727     if (hlist == nil)
01728         return (false);
01729     
01730     hstack = (**hlist).hfirst;
01731     
01732     while (hstack != nil) {
01733         
01734         pushmenubarglobals (hstack);
01735         
01736         if (mefindinmenubar (hnode, false, &ixstack, &itemnumber)) { /*found as item*/
01737             
01738             *houtline = outlinedata;
01739             
01740             popmenubarglobals ();
01741             
01742             return (true);
01743             }
01744         
01745         popmenubarglobals ();
01746         
01747         hstack = (**hstack).hnext;
01748         }
01749     
01750     return (false);
01751     } /*melocatemenubarnode*/
01752 
01753 
01754 boolean mecheckformulas (short ixstack) {
01755     
01756     /*
01757     search the menubar data structure for formula items.
01758     
01759     whenever a formula is encountered, update the item text.
01760     
01761     4.1b6 dmb: if item begins with a paren, and doesn't end with one, disabled it
01762     */
01763     
01764     register hdlmenubarstack hs = menubardata;
01765     short i = ixstack;
01766     hdlheadrecord hnode;
01767     short ixmenu;
01768     bigstring bs;
01769     short ctitems;
01770     boolean flitemenabled, flitemchecked;
01771     tymenubarstackelement info;
01772     
01773     info = (**hs).stack [i];
01774     
01775     ctitems = countmenuitems (info.hmenu);
01776     
01777     hnode = (**info.hnode).headlinkright;
01778     
01779     for (ixmenu = info.ctbaseitems + 1; ixmenu <= ctitems; ++ixmenu) {
01780         
01781         getheadstring (hnode, bs); 
01782         
01783         if (mereduceformula (bs))  { /*item was a formula*/
01784             
01785             mereducemenucodes (bs, &flitemenabled, &flitemchecked); /*4.1b8 dmb*/
01786             
01787             setmenuitem (info.hmenu, ixmenu, bs);
01788             
01789             setmenuitemenable (info.hmenu, ixmenu, flitemenabled); /*4.1b6 dmb*/
01790             
01791             if (!ophassubheads (hnode))
01792                 checkmenuitem (info.hmenu, ixmenu, flitemchecked); /*4.1b8 dmb*/
01793             }
01794         
01795         hnode = (**hnode).headlinkdown;
01796         }
01797     
01798     return (true);
01799     } /*mecheckformulas*/   
01800 
01801 
01802 /*
01803 boolean memenuupdate (void) {
01804     
01805     /%
01806     respond to a menubarlist menu selection
01807     %/
01808     
01809     register hdlmenubarlist hlist = menubarlist;
01810     register hdlmenubarstack h;
01811     
01812     if (hlist != nil) {
01813         
01814         h = (**hlist).hfirst;
01815         
01816         while (h != nil) {
01817             
01818             mecheckformulas (h);
01819             
01820             h = (**h).hnext;
01821             } /%while%/
01822         }
01823     
01824     return (false); /%didn't handle the menu%/
01825     } /%memenuupdate%/
01826 */
01827 
01828 
01829 boolean memenuhit (short idmenu, short ixmenu, hdlheadrecord *hnode) {
01830     
01831     /*
01832     search the menubar data structure for a menu with the indicated id.
01833     
01834     locate the node that it came from in the menu and run its script, or 
01835     display the headline if the option key is down.
01836     
01837     12/2/91 dmb: don't call medirtymenubar from here, since we're called to 
01838     clear them up; set fldirtymenubar directly to force menubar redraw.
01839     
01840     5.1.4 dmb: don't dim menus when processbusy
01841     */
01842     
01843     register short i;
01844     register short topstack;
01845     
01846     mecheckdeletedmenu (-1, true); /*8/13/92 dmb: flush deleted menu*/
01847     
01848     topstack = (**menubardata).topstack;
01849     
01850     for (i = 0; i < topstack; i++) { /*search for the menu*/
01851         
01852         tymenubarstackelement mi = (**menubardata).stack [i];
01853 
01854         if (idmenu == 0) { /*enable/disable all menus*/
01855             boolean flold, flnew;
01856             
01857             flold = getmenutitleenable (mi.hmenu, mi.idmenu);
01858             
01859             flnew = true; 
01860             
01861             if (flnew != flold) {
01862                 
01863                 setmenutitleenable (mi.hmenu, mi.idmenu, flnew);
01864                 
01865                 fldirtymenubar = true;
01866                 }
01867             
01868             if (flnew)
01869                 mecheckformulas (i);
01870             }
01871         else {
01872             
01873             if (mi.idmenu == idmenu) {
01874                 
01875                 register hdlheadrecord h = mi.hnode;
01876                 
01877                 ixmenu -= mi.ctbaseitems;
01878 
01879                 if (h == nil || ixmenu <= 0)
01880                     return (false);
01881                 
01882                 h = opnthsubhead (h, (short) (ixmenu));
01883                 
01884                 if (h == nil) 
01885                     return (false);
01886                 
01887                 *hnode = h;
01888                 
01889                 return (true);
01890                 }
01891             }
01892         } /*for*/
01893     
01894     return (false); /*failed to find the id in our structure*/
01895     } /*memenuhit*/ 
01896 
01897 
01898 boolean memenu (short idmenu, short ixmenu) {
01899     
01900     /*
01901     respond to a menubarlist menu selection
01902     
01903     11/20/91 dmb: handle disabled (negative) items
01904     */
01905     
01906     register hdlmenubarlist hlist = menubarlist;
01907     register hdlmenubarstack h;
01908     boolean fljustshownode;
01909     hdlheadrecord hnode;
01910     
01911     fljustshownode = keyboardstatus.floptionkey || optionkeydown ();
01912     
01913     if (ixmenu < 0) { /*disabled item*/
01914         
01915         if (!fljustshownode)
01916             return (false);
01917         
01918         ixmenu = -ixmenu;
01919         }
01920     
01921     if (hlist != nil) {
01922         
01923         h = (**hlist).hfirst;
01924         
01925         while (h != nil) {
01926             
01927             pushmenubarglobals (h);
01928             
01929             if (memenuhit (idmenu, ixmenu, &hnode)) {
01930                 
01931                 if (fljustshownode)
01932                     meshownode (hnode);
01933                 else
01934                     meuserselected (hnode);
01935                 
01936                 popmenubarglobals ();
01937                 
01938                 return (true);
01939                 }
01940             
01941             popmenubarglobals ();
01942             
01943             h = (**h).hnext;
01944             } /*while*/
01945         }
01946     
01947     if (idmenu == 0) /*updating menus; see if menubar needs to be redrawn*/
01948         mecheckmenubar ();
01949     
01950     return (false); /*didn't handle the menu*/
01951     } /*memenu*/    
01952 
01953 
01954 static unsigned char menullchar (hdlheadrecord hn) {
01955 #pragma unused (hn)
01956 
01957     return (chnul);
01958     } /*menullchar*/
01959 
01960 
01961 void menubarinit (void) {
01962     
01963     if (menubarcallbacks.menubarchangedroutine == nil) /*no one has set is so far*/
01964         menubarcallbacks.menubarchangedroutine = (menubarchangedcallback) &truenoop;
01965     
01966     if (menubarcallbacks.getcmdkeyroutine == nil)
01967         menubarcallbacks.getcmdkeyroutine = &menullchar;
01968     } /*menubarinit*/
01969 
01970 
01971 
01972 

Generated on Wed May 31 18:19:55 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6