dockmenu.c

Go to the documentation of this file.
00001 
00002 /*  $Id: dockmenu.c 1254 2006-04-12 20:27:14Z sethdill $    */
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 /*
00029 Implement right-click menus in the system tray icon or dock menu.
00030 Broken out from FrontierWinMain.c
00031 7.1b22 11/08/01 PBS
00032 */
00033 
00034 #include "frontier.h"
00035 #include "standard.h"
00036 
00037 #include "menu.h"
00038 #include "strings.h"
00039 #include "cancoon.h"
00040 #include "launch.h"
00041 #include "tablestructure.h"
00042 #include "popup.h"
00043 #include "meprograms.h"
00044 #include "dockmenu.h"
00045 #include "opinternal.h"
00046 #include "menuverbs.h"
00047 
00048 #define idgetdockmenumenuaddresscallback 43
00049 
00050 #define kmaxcommands 100
00051 #define kbasecommandid 3000
00052 #define maxsubmenus 40
00053 
00054 
00055 #ifdef MACVERSION
00056     UInt32 menuid;
00057     short idsubmenu;
00058     hdlmenurecord hcurrmenurecord;
00059     boolean flstackneedsdisposing = false;
00060 #endif
00061 
00062 
00063 #ifdef WIN95VERSION
00064     short menuid;
00065 #endif
00066 
00067 
00068 #ifdef MACVERSION
00069 
00070     typedef struct typopupinfo {
00071 
00072         hdlmenu hmenu;
00073         
00074         short id;           
00075         } typopupinfo, *ptrpopupinfo, **hdlpopupinfo;
00076 
00077     typedef struct tydockmenustack {
00078         
00079         typopupinfo popupmenus [maxsubmenus];
00080         
00081         short currstackitem;
00082         } tydockmenustack, *ptrdockmenustack, **hdldockmenustack;
00083 
00084 
00085     tydockmenustack dockmenustack;
00086 
00087 #endif
00088 
00089 
00090 static boolean dockmenubuildpopupmenu (hdlheadrecord hnode, hdlmenu hmenu); /*forward*/
00091 
00092 static void dockmenudisposemenusinstack (void);
00093 
00094 
00095 static void dockmenuresetmenustack (void) {
00096     
00097     #ifdef MACVERSION
00098     
00099         dockmenudisposemenusinstack ();
00100 
00101         dockmenustack.currstackitem = -1;
00102         
00103         dockmenustack.popupmenus [0].hmenu = nil;
00104         
00105         dockmenustack.popupmenus [0].id = -1;
00106     
00107     #endif
00108     } /*dockmenuresetmenustack*/
00109 
00110 
00111 static void dockmenudisposemenusinstack (void) {
00112     
00113     /*
00114     Dispose and delete all menus in popup menu stack.
00115     */
00116     
00117     #ifdef MACVERSION
00118     
00119         short ix = dockmenustack.currstackitem;
00120         short i, id;
00121         hdlmenu hmenu;
00122         
00123         if (!flstackneedsdisposing)
00124             return;
00125         
00126         if (ix < 0)
00127             return;
00128         
00129         for (i = ix; i > -1; i--) {
00130             
00131             id = dockmenustack.popupmenus [i].id;
00132             
00133             if (id > -1)
00134             
00135                 DeleteMenu (id);
00136                 
00137             if (id != defaultpopupmenuid) { /*already disposed by system*/
00138             
00139                 hmenu = dockmenustack.popupmenus [i].hmenu;
00140             
00141                 if (hmenu != nil)
00142             
00143                     disposemenu (hmenu);
00144                 } /*if*/
00145             
00146             dockmenustack.popupmenus [i].hmenu = nil;
00147             
00148             dockmenustack.popupmenus [i].id = -1;
00149             
00150             } /*for*/
00151         
00152         flstackneedsdisposing = false;  
00153     #endif
00154     } /*dockmenudisposemenusinstack*/
00155 
00156 
00157 static boolean dockmenuaddtomenustack (hdlmenu hmenu, short id) {
00158 
00159     #ifdef MACVERSION
00160 
00161         short ix = dockmenustack.currstackitem + 1;
00162         
00163         if (ix > maxsubmenus)   
00164             return (false);
00165         
00166         dockmenustack.currstackitem = ix;
00167         
00168         dockmenustack.popupmenus [ix].hmenu = hmenu;
00169         
00170         dockmenustack.popupmenus [ix].id = id;
00171     
00172     #endif
00173 
00174     return (true);  
00175     } /*dockmenuaddtomenustack*/
00176 
00177 
00178 static void dockmenuinsertsubmenu (hdlmenu hmenu, short itemnumber, hdlheadrecord hnode) {
00179 
00180     /*
00181     7.1b23 PBS: build a sub-menu and attach it.
00182     */
00183 
00184     hdlmenu hsubmenu;
00185     short id = defaultpopupmenuid;
00186 
00187     #ifdef MACVERSION
00188         idsubmenu++;
00189         
00190         id = idsubmenu;
00191     #endif
00192     
00193     hsubmenu = Newmenu (id, BIGSTRING (""));
00194 
00195     #ifdef MACVERSION   
00196         InsertMenu (hsubmenu, -1);
00197     #endif
00198 
00199     dockmenubuildpopupmenu (hnode, hsubmenu);
00200 
00201     dockmenuaddtomenustack (hsubmenu, id);
00202 
00203     sethierarchicalmenuitem (hmenu, itemnumber, hsubmenu, id);
00204     } /*dockmenuinsertsubmenu*/
00205 
00206 
00207 static boolean dockmenugetaddresscallback (tyvaluerecord *val) {
00208 
00209     /*
00210     7.1b22 PBS: Run the callback script that returns the address
00211     of a menubar object to use.
00212     */
00213 
00214     Handle htext = 0;
00215     boolean fl = false;
00216     bigstring bsscript;
00217     short idscript = idgetdockmenumenuaddresscallback;
00218 
00219     if (getsystemtablescript (idscript, bsscript)) {
00220     
00221         if (!newtexthandle (bsscript, &htext))
00222         
00223             return (false);
00224 
00225         grabthreadglobals ();
00226         
00227         oppushoutline (outlinedata);
00228         
00229         fl = langrun (htext, val);
00230 
00231         oppopoutline ();
00232 
00233         releasethreadglobals ();
00234         }
00235 
00236     return (fl);
00237     } /*dockmenugetaddresscallback*/
00238 
00239 
00240 static boolean dockmenuinsertmenuitem (hdlmenu hmenu, short itemnumber, hdlheadrecord hnode) {
00241 
00242     /*
00243     Insert one menu item.
00244 
00245     7.1b42 PBS: check menu items that should be checked.
00246     */
00247     
00248     bigstring bsheadstring;
00249     boolean flenabled = true;
00250     boolean flchecked = false;
00251 
00252     getheadstring (hnode, bsheadstring);
00253 
00254     mereduceformula (bsheadstring);
00255     
00256     mereducemenucodes (bsheadstring, &flenabled, &flchecked); /*7.0b23 PBS: items can be disabled.*/
00257 
00258     pushpopupitem (hmenu, bsheadstring, flenabled, menuid);
00259 
00260     #if TARGET_API_MAC_CARBON == 1
00261     
00262         SetMenuItemCommandID (hmenu, countmenuitems (hmenu), menuid);
00263         
00264     #endif
00265 
00266     if (flchecked) /*7.1b42 PBS: support for checked menu items.*/
00267         checkmenuitem (hmenu, countmenuitems (hmenu), flchecked);
00268 
00269     if (!opnosubheads (hnode)) /*has subs?*/
00270         dockmenuinsertsubmenu (hmenu, itemnumber, hnode);
00271 
00272     #ifdef MACVERSION
00273         flstackneedsdisposing = true;
00274     #endif
00275 
00276     return (true);
00277     } /*dockmenuinsertmenuitem*/
00278 
00279 
00280 static boolean dockmenubuildpopupmenu (hdlheadrecord hnode, hdlmenu hmenu) {
00281     
00282     /*
00283     7.1b22 PBS: Build a popup menu from the outline pointed to by hnode.
00284     Recurse to handle a menu that has a submenu.
00285 
00286     Based on mebuildmenu, but different enough to need its own routine. 
00287     */
00288     
00289     short itemnumber;
00290     bigstring bs;
00291     
00292     getheadstring (hnode, bs); /*get the menu title*/
00293     
00294     if (opnosubheads (hnode))
00295         return (true);
00296     
00297     hnode = (**hnode).headlinkright; /*move to first subhead*/
00298     
00299     for (itemnumber = 1; ; itemnumber++) {
00300 
00301         menuid++;
00302         
00303         if (!dockmenuinsertmenuitem (hmenu, itemnumber, hnode))
00304             return (false);
00305         
00306         if (opislastsubhead (hnode)) /*done with this menu*/
00307             return (true);
00308         
00309         hnode = (**hnode).headlinkdown; /*advance to next item*/
00310         } /*while*/
00311     } /*dockmenubuildpopupmenu*/
00312 
00313 
00314 static boolean dockmenufillpopup (hdlmenu hmenu, hdlmenurecord *hmreturned) {
00315 
00316     /*
00317     7.1b44 PBS: call menuverbgetsize to make sure the menu is in memory.
00318     */
00319 
00320     hdlhashtable htable;
00321     hdlhashnode hnode;
00322     hdlmenurecord hm;
00323     tyvaluerecord valaddress, val;
00324     hdlexternalhandle h;
00325     hdlheadrecord hsummit;
00326     bigstring bsaddress;
00327     boolean fl = false;
00328     long menusize = 0;
00329 
00330     if (roottable == nil) /*9.1b1 JES: If there's no system root, don't crash.*/
00331         return (false);
00332     
00333     if (!dockmenugetaddresscallback (&valaddress))
00334         return (false);
00335     
00336     if (valaddress.valuetype != addressvaluetype)
00337         goto exit;
00338 
00339     if (!getaddressvalue (valaddress, &htable, bsaddress))
00340         goto exit;
00341 
00342     if (!langsymbolreference (htable, bsaddress, &val, &hnode))
00343         goto exit;
00344 
00345     if (val.valuetype != externalvaluetype)
00346         goto exit;
00347 
00348     h = (hdlexternalhandle) val.data.externalvalue;
00349 
00350     if (!menuverbgetsize (h, &menusize)) /*7.1b43 PBS: We don't care about the size. We just want to read it into memory.*/
00351         goto exit;
00352 
00353     if ((**h).id != idmenuprocessor) /*it must be a menu*/
00354         goto exit;
00355 
00356     hm = (hdlmenurecord) (**h).variabledata;
00357 
00358     hsummit = (**(**hm).menuoutline).hsummit;
00359 
00360     #if TARGET_API_MAC_CARBON == 1
00361         menuid = kbasecommandid;
00362         idsubmenu = 5;
00363     #endif
00364 
00365     dockmenudisposemenusinstack ();
00366     
00367     dockmenubuildpopupmenu (hsummit, hmenu);
00368     
00369     *hmreturned = hm;
00370 
00371     fl = true;
00372     
00373     exit:
00374 
00375     disposevaluerecord (valaddress, false);
00376 
00377     return (fl);
00378     } /*dockmenufillpopup*/
00379 
00380 
00381 static void dockmenuruncommand (hdlmenurecord hm, short itemhit) {
00382     
00383     hdlheadrecord hsummit;
00384     hdlheadrecord hmenuitem;
00385     bigstring bs;
00386 
00387     hsummit = (**(**hm).menuoutline).hsummit; /*Top level of the menu*/
00388 
00389     hmenuitem = oprepeatedbump (flatdown, itemhit, hsummit, false);
00390     
00391     oppushoutline ((**hm).menuoutline);
00392 
00393     getheadstring (hmenuitem, bs);
00394 
00395     meuserselected (hmenuitem);
00396     
00397     dockmenudisposemenusinstack ();
00398 
00399     oppopoutline ();
00400     } /*dockmenuruncommand*/
00401 
00402 
00403 #if TARGET_API_MAC_CARBON == 1
00404 
00405 pascal OSStatus dockcommandhandler (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) {
00406 #pragma unused(nextHandler, theEvent, userData) /*happy compiler*/
00407 
00408     HICommand commandstruct;
00409     UInt32 commandid;
00410     OSErr ec = eventNotHandledErr;
00411     
00412     GetEventParameter (theEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof (HICommand), NULL, &commandstruct);
00413     
00414     commandid = commandstruct.commandID;
00415     
00416     if ((commandid >= kbasecommandid) && (commandid <= kbasecommandid + kmaxcommands)) {
00417     
00418         dockmenuruncommand (hcurrmenurecord, commandid - kbasecommandid);
00419         
00420         ec = noErr; /*all's well*/
00421         } /*if*/
00422     
00423     dockmenudisposemenusinstack (); /*7.1b23 PBS: delete and dispose submenus*/
00424     
00425     return (ec);
00426     } /*dockcommandhandler*/
00427 
00428 
00429 static void dockmenuinstallhandler (void) {
00430     
00431     EventTypeSpec myevents = {kEventClassCommand, kEventCommandProcess};
00432     
00433     InstallApplicationEventHandler (NewEventHandlerUPP (dockcommandhandler), 1, &myevents, 0, NULL);
00434     
00435     } /*dockmenuinstallhandler*/
00436 
00437 
00438 pascal OSStatus dockmenuhandler (EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) {
00439     
00440     /*
00441     7.1b22 PBS: called from the system when the dock icon is right-clicked.
00442     Build a contextual menu and return it.
00443     */
00444     
00445     #pragma unused(nextHandler) /*happy compiler*/
00446     #pragma unused(theEvent)
00447     #pragma unused(userData)
00448     
00449     hdlmenu hmenu;
00450     hdlmenurecord hm;
00451     static boolean flinited = false;
00452     
00453     menuid = 0;
00454     
00455     dockmenuresetmenustack (); /*7.1b23 PBS: maintain a stack of submenus*/
00456     
00457     if (!flinited) { /*install command handler first time*/
00458         
00459         dockmenuinstallhandler ();
00460         
00461         flinited = true;
00462         } /*if*/
00463     
00464     hmenu = Newmenu (defaultpopupmenuid, BIGSTRING (""));
00465     
00466     if (!dockmenufillpopup (hmenu, &hm))
00467         goto exit;
00468     
00469     dockmenuaddtomenustack (hmenu, defaultpopupmenuid);
00470 
00471     hcurrmenurecord = hm;
00472     
00473     SetEventParameter (theEvent, kEventParamMenuRef, typeMenuRef, sizeof (MenuRef), &hmenu);
00474     
00475     exit:
00476 
00477     return (noErr); /*all's well in dock-menu-land*/
00478     } /*dockmenuhandler*/
00479 
00480 #endif
00481 
00482 #ifdef WIN95VERSION
00483 
00484 void rundockmenu (void) {
00485     
00486     /*
00487     The system tray icon or dock icon has been right-clicked.
00488     Display a menu and handle the user's choice.
00489     */
00490 
00491     hdlmenu hmenu;
00492     hdlmenurecord hm;
00493     POINT mousept;
00494     UINT flags = 0;
00495     
00496     hmenu = Newmenu (defaultpopupmenuid, "");
00497     
00498     menuid = 0;
00499 
00500     if (!dockmenufillpopup (hmenu, &hm))
00501         goto exit;
00502 
00503     SetMenuDefaultItem (GetSubMenu (hmenu, 0), 0, true); /*Top item is default*/
00504 
00505     GetCursorPos (&mousept); 
00506     
00507     SetForegroundWindow (shellframewindow); 
00508 
00509     if (TrackPopupMenuEx (GetSubMenu (hmenu, 0), flags, mousept.x, mousept.y, shellframewindow, NULL)) {
00510             
00511         MSG msg;
00512         short itemhit;
00513         hdlheadrecord hsummit;
00514         hdlheadrecord hmenuitem;
00515         bigstring bs;
00516         boolean flopencommand = false;
00517 
00518         if (PeekMessage (&msg, shellframewindow, WM_COMMAND, WM_COMMAND, PM_REMOVE)) {
00519 
00520             itemhit = LOWORD (msg.wParam) % 100;
00521 
00522             hsummit = (**(**hm).menuoutline).hsummit; /*Top level of the menu*/
00523 
00524             //hmenuitem = opnthsubhead (hsummit, itemhit);
00525 
00526             oppushoutline ((**hm).menuoutline);
00527     
00528             hmenuitem = oprepeatedbump (flatdown, itemhit, hsummit, false);
00529 
00530             getheadstring (hmenuitem, bs);
00531 
00532             if (equalidentifiers (bs, "\x0d" "Open Frontier"))
00533                 flopencommand = true;
00534 
00535             else if (equalidentifiers (bs, "\x0a" "Open Radio"))
00536                 flopencommand = true;
00537 
00538             if (flopencommand) { /*Intercept -- there's no script verb for this command.*/
00539 
00540                 ShowWindow (shellframewindow, SW_SHOW); /*Show the window.*/
00541 
00542                 activateapplication (NULL); /*bring to front*/
00543                 } /*if*/
00544             
00545             else /*run the script*/
00546                 meuserselected (hmenuitem);
00547 
00548             oppopoutline ();
00549             } /*if*/
00550         } /*if*/
00551     
00552     exit:
00553 
00554     disposemenu (hmenu);
00555     } /*rundockmenu*/
00556 
00557 #endif

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