summaryrefslogtreecommitdiffstats
path: root/carbon/tkMacOSXMenus.c
diff options
context:
space:
mode:
authordas <das>2009-06-26 01:42:46 (GMT)
committerdas <das>2009-06-26 01:42:46 (GMT)
commit501fcd66876991e90384cad2039ec6ee83d3c485 (patch)
tree2adb96ca0ec47497841adacd8b08b680f66112e5 /carbon/tkMacOSXMenus.c
parent24a50e27f48ca6c20da7657f1369203445367099 (diff)
downloadtk-501fcd66876991e90384cad2039ec6ee83d3c485.zip
tk-501fcd66876991e90384cad2039ec6ee83d3c485.tar.gz
tk-501fcd66876991e90384cad2039ec6ee83d3c485.tar.bz2
* carbon/ (new directory): copy of current state of 'macosx'
source directory, to preserve legacy TkAqua implementation based on Carbon API (with support for Mac OS X releases older than 10.5).
Diffstat (limited to 'carbon/tkMacOSXMenus.c')
-rw-r--r--carbon/tkMacOSXMenus.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/carbon/tkMacOSXMenus.c b/carbon/tkMacOSXMenus.c
new file mode 100644
index 0000000..fcac0f4
--- /dev/null
+++ b/carbon/tkMacOSXMenus.c
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ *
+ * RCS: @(#) $Id: tkMacOSXMenus.c,v 1.1 2009/06/26 01:42:47 das Exp $
+ */
+
+#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:
+ */