diff options
Diffstat (limited to 'carbon/tkMacOSXMenus.c')
-rw-r--r-- | carbon/tkMacOSXMenus.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/carbon/tkMacOSXMenus.c b/carbon/tkMacOSXMenus.c new file mode 100644 index 0000000..8509f8c --- /dev/null +++ b/carbon/tkMacOSXMenus.c @@ -0,0 +1,406 @@ +/* + * tkMacOSXMenus.c -- + * + * These calls set up and manage the menubar for the Macintosh version of + * Tk. + * + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * Copyright (c) 2001, Apple Computer, Inc. + * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net> + * + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. + */ + +#include "tkMacOSXPrivate.h" + +#define kAppleMenu 256 +#define kAppleAboutItem 1 +#define kFileMenu 2 +#define kEditMenu 3 + +#define kSourceItem 1 +#define kDemoItem 2 +#define kCloseItem 3 + +#define EDIT_CUT 1 +#define EDIT_COPY 2 +#define EDIT_PASTE 3 +#define EDIT_CLEAR 4 + +MenuRef tkAppleMenu; +MenuRef tkFileMenu; +MenuRef tkEditMenu; + +static Tcl_Interp *gInterp = NULL; /* Standard menu interpreter. */ +static EventHandlerRef menuEventHandlerRef = NULL; + +static void GenerateEditEvent(int flag); +static Tcl_Obj * GetWidgetDemoPath(Tcl_Interp *interp); +static OSStatus MenuEventHandlerProc(EventHandlerCallRef callRef, + EventRef event, void *userData); + +/* + *---------------------------------------------------------------------- + * + * GetWidgetDemoPath -- + * + * Get path to the widget demo. + * + * Results: + * pathObj with ref count 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Tcl_Obj * +GetWidgetDemoPath( + Tcl_Interp *interp) +{ + Tcl_Obj *libpath, *result = NULL; + + libpath = Tcl_GetVar2Ex(gInterp, "tk_library", NULL, TCL_GLOBAL_ONLY); + if (libpath) { + Tcl_Obj *demo[2] = { Tcl_NewStringObj("demos", 5), + Tcl_NewStringObj("widget", 6) }; + + Tcl_IncrRefCount(libpath); + result = Tcl_FSJoinToPath(libpath, 2, demo); + Tcl_DecrRefCount(libpath); + } + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXHandleMenuSelect -- + * + * Handles events that occur in the Menu bar. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXHandleMenuSelect( + MenuID theMenu, + MenuItemIndex theItem, + int optionKeyPressed) +{ + Tk_Window tkwin; + Window window; + TkDisplay *dispPtr; + Tcl_CmdInfo dummy; + int code; + + if (theItem == 0) { + TkMacOSXClearMenubarActive(); + return; + } + + switch (theMenu) { + case kAppleMenu: + switch (theItem) { + case kAppleAboutItem: + if (optionKeyPressed || gInterp == NULL || + Tcl_GetCommandInfo(gInterp, "tkAboutDialog", &dummy) == 0) { + TkAboutDlg(); + } else { + code = Tcl_EvalEx(gInterp, "tkAboutDialog", -1, + TCL_EVAL_GLOBAL); + if (code != TCL_OK) { + Tcl_BackgroundException(gInterp, code); + } + Tcl_ResetResult(gInterp); + } + break; + } + break; + case kFileMenu: + switch (theItem) { + case kSourceItem: + if (gInterp) { + if (Tcl_EvalEx(gInterp, "tk_getOpenFile -filetypes {" + "{{TCL Scripts} {.tcl} TEXT} {{Text Files} {} TEXT}}", + -1, TCL_EVAL_GLOBAL) == TCL_OK) { + Tcl_Obj *path = Tcl_GetObjResult(gInterp); + int len; + + Tcl_GetStringFromObj(path, &len); + if (len) { + Tcl_IncrRefCount(path); + code = Tcl_FSEvalFile(gInterp, path); + if (code != TCL_OK) { + Tcl_BackgroundException(gInterp, code); + } + Tcl_DecrRefCount(path); + } + } + Tcl_ResetResult(gInterp); + } + break; + case kDemoItem: + if (gInterp) { + Tcl_Obj *path = GetWidgetDemoPath(gInterp); + + if (path) { + Tcl_IncrRefCount(path); + code = Tcl_FSEvalFile(gInterp, path); + if (code != TCL_OK) { + Tcl_BackgroundException(gInterp, code); + } + Tcl_DecrRefCount(path); + Tcl_ResetResult(gInterp); + } + } + break; + case kCloseItem: + /* Send close event */ + window = TkMacOSXGetXWindow(ActiveNonFloatingWindow()); + dispPtr = TkGetDisplayList(); + tkwin = Tk_IdToWindow(dispPtr->display, window); + TkGenWMDestroyEvent(tkwin); + break; + } + break; + case kEditMenu: + /* + * This implementation just send the keysyms Tk thinks are associated + * with function keys that do Cut, Copy & Paste on a Sun keyboard. + */ + + GenerateEditEvent(theItem); + break; + default: + TkMacOSXDispatchMenuEvent(theMenu, theItem); + break; + } + + /* + * Finally we unhighlight the menu. + */ + + HiliteMenu(0); +} + +/* + *---------------------------------------------------------------------- + * + * MenuEventHandlerProc -- + * + * One-time handler of kEventMenuEnableItems for the edit menu. + * + * Results: + * OS status code. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static OSStatus +MenuEventHandlerProc( + EventHandlerCallRef callRef, + EventRef event, + void *userData) +{ + OSStatus result = eventNotHandledErr, err; + int menuContext; + + err = ChkErr(GetEventParameter, event, kEventParamMenuContext, typeUInt32, + NULL, sizeof(menuContext), NULL, &menuContext); + if (err == noErr && (menuContext & kMenuContextMenuBarTracking)) { + if (gInterp) { + Tcl_Obj *path = GetWidgetDemoPath(gInterp); + + if (path) { + Tcl_IncrRefCount(path); + if (Tcl_FSAccess(path, R_OK) == 0) { + EnableMenuItem(tkFileMenu, kDemoItem); + } + Tcl_DecrRefCount(path); + } + } + ChkErr(RemoveEventHandler, menuEventHandlerRef); + menuEventHandlerRef = NULL; + result = noErr; + } + + return result; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXInitMenus -- + * + * This procedure initializes the Macintosh menu bar. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXInitMenus( + Tcl_Interp *interp) +{ + OSStatus err; + EventHandlerUPP menuEventHandlerUPP; + const EventTypeSpec menuEventTypes[] = { + {kEventClassMenu, kEventMenuEnableItems}, + }; + + gInterp = interp; + if (TkMacOSXUseMenuID(kAppleMenu) != TCL_OK) { + Tcl_Panic("Menu ID %d is already in use!", kAppleMenu); + } + err = ChkErr(CreateNewMenu, kAppleMenu, kMenuAttrDoNotUseUserCommandKeys, + &tkAppleMenu); + if (err != noErr) { + Tcl_Panic("CreateNewMenu failed !"); + } + SetMenuTitle(tkAppleMenu, "\p\024"); + InsertMenu(tkAppleMenu, 0); + AppendMenu(tkAppleMenu, "\pAbout Tcl & Tk\xc9"); + AppendMenu(tkAppleMenu, "\p(-"); + + if (TkMacOSXUseMenuID(kFileMenu) != TCL_OK) { + Tcl_Panic("Menu ID %d is already in use!", kFileMenu); + } + err = ChkErr(CreateNewMenu, kFileMenu, kMenuAttrDoNotUseUserCommandKeys, + &tkFileMenu); + if (err != noErr) { + Tcl_Panic("CreateNewMenu failed !"); + } + SetMenuTitle(tkFileMenu, "\pFile"); + InsertMenu(tkFileMenu, 0); + InsertMenuItem(tkFileMenu, "\pSource\xc9", kSourceItem - 1); + InsertMenuItem(tkFileMenu, "\pRun Widget Demo", kDemoItem - 1); + InsertMenuItem(tkFileMenu, "\pClose/W", kCloseItem - 1); + DisableMenuItem(tkFileMenu, kDemoItem); + menuEventHandlerUPP = NewEventHandlerUPP(MenuEventHandlerProc); + ChkErr(InstallEventHandler, GetMenuEventTarget(tkFileMenu), + menuEventHandlerUPP, GetEventTypeCount(menuEventTypes), + menuEventTypes, NULL, &menuEventHandlerRef); + DisposeEventHandlerUPP(menuEventHandlerUPP); + + if (TkMacOSXUseMenuID(kEditMenu) != TCL_OK) { + Tcl_Panic("Menu ID %d is already in use!", kEditMenu); + } + err = ChkErr(CreateNewMenu, kEditMenu, kMenuAttrDoNotUseUserCommandKeys, + &tkEditMenu); + if (err != noErr) { + Tcl_Panic("CreateNewMenu failed !"); + } + SetMenuTitle(tkEditMenu, "\pEdit"); + InsertMenu(tkEditMenu, 0); + AppendMenu(tkEditMenu, "\pCut/X"); + AppendMenu(tkEditMenu, "\pCopy/C"); + AppendMenu(tkEditMenu, "\pPaste/V"); + AppendMenu(tkEditMenu, "\pClear"); + if (TkMacOSXUseMenuID(kHMHelpMenuID) != TCL_OK) { + Tcl_Panic("Help menu ID %s is already in use!", kHMHelpMenuID); + } + + /* + * Workaround a Carbon bug with kHICommandPreferences: the first call to + * IsMenuKeyEvent returns false for the preferences menu item key shorcut + * event (even if the corresponding menu item is dynamically enabled by a + * kEventCommandUpdateStatus handler), unless the kHICommandPreferences + * menu item has previously been enabled manually. [Bug 1481503] + */ + + EnableMenuCommand(NULL, kHICommandPreferences); + + DrawMenuBar(); + return; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateEditEvent -- + * + * Takes an edit menu item and posts the corasponding a virtual event to + * Tk's event queue. + * + * Results: + * None. + * + * Side effects: + * May place events of queue. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateEditEvent( + int flag) +{ + XVirtualEvent event; + int x, y; + Tk_Window tkwin; + Window window; + TkDisplay *dispPtr; + + window = TkMacOSXGetXWindow(ActiveNonFloatingWindow()); + dispPtr = TkGetDisplayList(); + tkwin = Tk_IdToWindow(dispPtr->display, window); + tkwin = (Tk_Window) ((TkWindow *) tkwin)->dispPtr->focusPtr; + if (tkwin == NULL) { + return; + } + + bzero(&event, sizeof(XVirtualEvent)); + event.type = VirtualEvent; + event.serial = Tk_Display(tkwin)->request; + event.send_event = false; + event.display = Tk_Display(tkwin); + event.event = Tk_WindowId(tkwin); + event.root = XRootWindow(Tk_Display(tkwin), 0); + event.subwindow = None; + event.time = TkpGetMS(); + + XQueryPointer(NULL, None, NULL, NULL, + &event.x_root, &event.y_root, &x, &y, &event.state); + Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y); + event.same_screen = true; + + switch (flag) { + case EDIT_CUT: + event.name = Tk_GetUid("Cut"); + break; + case EDIT_COPY: + event.name = Tk_GetUid("Copy"); + break; + case EDIT_PASTE: + event.name = Tk_GetUid("Paste"); + break; + case EDIT_CLEAR: + event.name = Tk_GetUid("Clear"); + break; + } + Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); +} + +/* + * Local Variables: + * fill-column: 78 + * c-basic-offset: 4 + * End: + */ |