From abb4fbbd9a9892b450d6dd6449c7d3c6b9285d82 Mon Sep 17 00:00:00 2001 From: "joshmoz%gmail.com" Date: Fri, 20 Jan 2006 05:01:20 +0000 Subject: [PATCH] Cocoa menu work. This code is only built when Cocoa widgets are built (only Camino at the moment, and Camino doesn't actually use the code). This is most of the Application menu implementation. It lacks support for key equivs in the Application menu, that will be in the next patch. b=316076 sr=sparky --- widget/src/cocoa/nsMenuBarX.h | 16 ++ widget/src/cocoa/nsMenuBarX.mm | 266 ++++++++++++++++++++++++++++---- widget/src/cocoa/nsMenuItemX.mm | 10 +- widget/src/cocoa/nsMenuX.h | 4 +- widget/src/cocoa/nsMenuX.mm | 98 ++---------- 5 files changed, 272 insertions(+), 122 deletions(-) diff --git a/widget/src/cocoa/nsMenuBarX.h b/widget/src/cocoa/nsMenuBarX.h index f14ce78f81db..2b22b96d1571 100644 --- a/widget/src/cocoa/nsMenuBarX.h +++ b/widget/src/cocoa/nsMenuBarX.h @@ -57,6 +57,8 @@ class nsIWidget; class nsIDocument; class nsIDOMNode; +extern "C" MenuRef _NSGetCarbonMenu(NSMenu* aMenu); + namespace MenuHelpersX { // utility routine for getting a PresContext out of a docShell @@ -64,9 +66,18 @@ namespace MenuHelpersX nsEventStatus DispatchCommandTo(nsIWeakReference* aDocShellWeakRef, nsIContent* aTargetContent); NSString* CreateTruncatedCocoaLabel(nsString itemLabel); + PRUint8 GeckoModifiersForNodeAttribute(char* modifiersAttribute); + unsigned int MacModifiersForGeckoModifiers(PRUint8 geckoModifiers); } +// Objective-C class used as action target for menu items +@interface NativeMenuItemTarget : NSObject +{ +} +-(IBAction)menuItemHit:(id)sender; +@end + // // Native Mac menu bar wrapper // @@ -84,6 +95,9 @@ public: enum {kApplicationMenuID = 1}; + // |NSMenuItem|s target Objective-C objects + static NativeMenuItemTarget* sNativeEventTarget; + NS_DECL_ISUPPORTS NS_DECL_NSICHANGEMANAGER NS_DECL_NSIMENUCOMMANDDISPATCHER @@ -132,6 +146,8 @@ protected: nsEventStatus ExecuteCommand(nsIContent* inDispatchTo); // build the Application menu shared by all menu bars. + NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsIMenu* inMenu, const nsAString& nodeID, SEL action, + int tag, NativeMenuItemTarget* target); nsresult CreateApplicationMenu(nsIMenu* inMenu); nsHashtable mObserverTable; // stores observers for content change notification diff --git a/widget/src/cocoa/nsMenuBarX.mm b/widget/src/cocoa/nsMenuBarX.mm index e74ed6e05141..c924311db09c 100644 --- a/widget/src/cocoa/nsMenuBarX.mm +++ b/widget/src/cocoa/nsMenuBarX.mm @@ -73,6 +73,7 @@ NS_IMPL_ISUPPORTS6(nsMenuBarX, nsIMenuBar, nsIMenuListener, nsIDocumentObserver, NSMenu* nsMenuBarX::sApplicationMenu = nsnull; EventHandlerUPP nsMenuBarX::sCommandEventHandler = nsnull; +NativeMenuItemTarget* nsMenuBarX::sNativeEventTarget = nil; nsMenuBarX::nsMenuBarX() @@ -530,6 +531,52 @@ NS_IMETHODIMP nsMenuBarX::AddMenu(nsIMenu * aMenu) } +// for creating menu items destined for the Application menu +NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsIMenu* inMenu, const nsAString& nodeID, SEL action, + int tag, NativeMenuItemTarget* target) +{ + nsCOMPtr menu; + inMenu->GetMenuContent(getter_AddRefs(menu)); + if (!menu) + return nil; + + nsCOMPtr doc = menu->GetDocument(); + if (!doc) + return nil; + + nsCOMPtr domdoc(do_QueryInterface(doc)); + if (!domdoc) + return nil; + + // Get menu item label and access key + nsAutoString label; + nsAutoString modifiers; + nsCOMPtr menuItem; + domdoc->GetElementById(nodeID, getter_AddRefs(menuItem)); + if (menuItem) { + menuItem->GetAttribute(NS_LITERAL_STRING("label"), label); + menuItem->GetAttribute(NS_LITERAL_STRING("modifiers"), modifiers); + } + else { + return nil; + } + + NSString* labelString = (NSString*)::CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)label.get(), + label.Length()); + if (!labelString) + labelString = [@"" retain]; + + NSMenuItem* newMenuItem = [[NSMenuItem alloc] initWithTitle:labelString action:action keyEquivalent:@""]; + + [labelString release]; + + [newMenuItem setTag:tag]; + [newMenuItem setTarget:target]; + + return newMenuItem; +} + + // // CreateApplicationMenu // @@ -543,35 +590,126 @@ nsMenuBarX::CreateApplicationMenu(nsIMenu* inMenu) // menu manually, so we grab the one from the nib and use that. sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain]; +/* + We support the following menu items here: + + Menu Item DOM Node ID Notes + + ================== + = About This App = <- aboutName + ================== + = Preferences... = <- menu_preferences + ================== + = Services > = <- menu_mac_services <- (do not define access key, has submenu) + ================== + = Hide App = <- menu_mac_hide_app + = Hide Others = <- menu_mac_hide_others + = Show All = <- menu_mac_show_all + ================== + = Quit = <- menu_FileQuitItem + ================== + + If any of them are ommitted from the application's DOM, we just don't add + them. We always add a "Quit" item, but if an app developer does not provide a + DOM node with the right ID for the Quit item, we add it in English. App + developers need only add each node with a label and an accesskey (if they want + one). Other attributes are optional. Like so: + + + + We need to use this system for localization purposes, until we have a better way + to define the Application menu to be used on Mac OS X. +*/ + if (sApplicationMenu) { - // this code reads the "label" attribute from the with - // id="aboutName" and puts its label in the Application Menu - nsAutoString label; - nsCOMPtr menu; - inMenu->GetMenuContent(getter_AddRefs(menu)); - if (menu) { - nsCOMPtr doc = menu->GetDocument(); - if (doc) { - nsCOMPtr domdoc (do_QueryInterface(doc)); - if (domdoc) { - nsCOMPtr aboutMenuItem; - domdoc->GetElementById(NS_LITERAL_STRING("aboutName"), getter_AddRefs(aboutMenuItem)); - if (aboutMenuItem) - aboutMenuItem->GetAttribute(NS_LITERAL_STRING("label"), label); - } - } - } - CFStringRef labelRef = ::CFStringCreateWithCharacters(kCFAllocatorDefault, (UniChar*)label.get(), label.Length()); - if (labelRef) { - [sApplicationMenu insertItemWithTitle:(NSString*)labelRef action:nil keyEquivalent:@"" atIndex:0]; - ::CFRelease(labelRef); + // This code reads attributes we are going to care about from the DOM elements + + NSMenuItem *itemBeingAdded = nil; + + // Add the About menu item + itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("aboutName"), @selector(menuItemHit:), + kHICommandAbout, nsMenuBarX::sNativeEventTarget); + if (itemBeingAdded) { + [sApplicationMenu addItem:itemBeingAdded]; + [itemBeingAdded release]; + // Add separator after About menu + [sApplicationMenu addItem:[NSMenuItem separatorItem]]; } - //XXXJOSH we need to get this event, maybe convert to a MenuRef, do later - //::SetMenuItemCommandID(sApplicationMenu, 1, kHICommandAbout); + // Add the Preferences menu item + itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_preferences"), @selector(menuItemHit:), + kHICommandPreferences, nsMenuBarX::sNativeEventTarget); + if (itemBeingAdded) { + [sApplicationMenu addItem:itemBeingAdded]; + [itemBeingAdded release]; + // Add separator after Preferences menu + [sApplicationMenu addItem:[NSMenuItem separatorItem]]; + } + + // Add Services menu item + itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_mac_services"), nil, + 0, nil); + if (itemBeingAdded) { + [sApplicationMenu addItem:itemBeingAdded]; + + // set this menu item up as the Mac OS X Services menu + NSMenu* servicesMenu = [[NSMenu alloc] initWithTitle:@""]; + [itemBeingAdded setSubmenu:servicesMenu]; + [NSApp setServicesMenu:servicesMenu]; + + [itemBeingAdded release]; + + // Add separator after Services menu + [sApplicationMenu addItem:[NSMenuItem separatorItem]]; + } - // add separator after About menu - [sApplicationMenu addItem:[NSMenuItem separatorItem]]; + BOOL addHideShowSeparator = FALSE; + + // Add menu item to hide this application + itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_mac_hide_app"), @selector(hide:), + 0, NSApp); + if (itemBeingAdded) { + [sApplicationMenu addItem:itemBeingAdded]; + [itemBeingAdded release]; + addHideShowSeparator = TRUE; + } + + // Add menu item to hide other applications + itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_mac_hide_others"), @selector(hideOtherApplications:), + 0, NSApp); + if (itemBeingAdded) { + [sApplicationMenu addItem:itemBeingAdded]; + [itemBeingAdded release]; + addHideShowSeparator = TRUE; + } + + // Add menu item to show all applications + itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_mac_show_all"), @selector(unhideAllApplications:), + 0, NSApp); + if (itemBeingAdded) { + [sApplicationMenu addItem:itemBeingAdded]; + [itemBeingAdded release]; + addHideShowSeparator = TRUE; + } + + // Add a separator after the hide/show menus if at least one exists + if (addHideShowSeparator) + [sApplicationMenu addItem:[NSMenuItem separatorItem]]; + + // Add quit menu item + itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_FileQuitItem"), @selector(menuItemHit:), + kHICommandQuit, nsMenuBarX::sNativeEventTarget); + if (itemBeingAdded) { + [sApplicationMenu addItem:itemBeingAdded]; + [itemBeingAdded release]; + } + else { + // the current application does not have a DOM node for "Quit". Add one + // anyway, in English. + ; + } } return (sApplicationMenu) ? NS_OK : NS_ERROR_FAILURE; @@ -762,7 +900,6 @@ nsMenuBarX::ContentInserted(nsIDocument * aDocument, nsIContent * aContainer, } } -#pragma mark - // // nsIChangeManager @@ -931,3 +1068,80 @@ NSString* MenuHelpersX::CreateTruncatedCocoaLabel(nsString itemLabel) ::TruncateThemeText(labelRef, kThemeMenuItemFont, kThemeStateActive, kMaxItemPixelWidth, truncMiddle, NULL); return (NSString*)labelRef; // caller releases } + +PRUint8 MenuHelpersX::GeckoModifiersForNodeAttribute(char* modifiersAttribute) +{ + PRUint8 modifiers = knsMenuItemNoModifier; + char* newStr; + char* token = nsCRT::strtok(modifiersAttribute, ", \t", &newStr); + while (token != NULL) { + if (PL_strcmp(token, "shift") == 0) + modifiers |= knsMenuItemShiftModifier; + else if (PL_strcmp(token, "alt") == 0) + modifiers |= knsMenuItemAltModifier; + else if (PL_strcmp(token, "control") == 0) + modifiers |= knsMenuItemControlModifier; + else if ((PL_strcmp(token, "accel") == 0) || + (PL_strcmp(token, "meta") == 0)) { + modifiers |= knsMenuItemCommandModifier; + } + token = nsCRT::strtok(newStr, ", \t", &newStr); + } + + return modifiers; +} + +unsigned int MenuHelpersX::MacModifiersForGeckoModifiers(PRUint8 geckoModifiers) +{ + unsigned int macModifiers = 0; + + if (geckoModifiers & knsMenuItemShiftModifier) + macModifiers |= NSShiftKeyMask; + if (geckoModifiers & knsMenuItemAltModifier) + macModifiers |= NSAlternateKeyMask; + if (geckoModifiers & knsMenuItemControlModifier) + macModifiers |= NSControlKeyMask; + if (geckoModifiers & knsMenuItemCommandModifier) + macModifiers |= NSCommandKeyMask; + + return macModifiers; +} + +// Objective-C class used as action target for menu items + +@implementation NativeMenuItemTarget + +// called when some menu item in this menu gets hit +-(IBAction)menuItemHit:(id)sender +{ + MenuRef senderMenuRef = _NSGetCarbonMenu([sender menu]); + int senderCarbonMenuItemIndex = [[sender menu] indexOfItem:sender] + 1; + + // If this carbon menu item has never had a command ID assigned to it, give it + // one from the sender's tag + MenuCommand menuCommand; + ::GetMenuItemCommandID(senderMenuRef, senderCarbonMenuItemIndex, &menuCommand); + if (menuCommand == 0) { + menuCommand = (MenuCommand)[sender tag]; + ::SetMenuItemCommandID(senderMenuRef, senderCarbonMenuItemIndex, menuCommand); + } + + // set up an HICommand to send + HICommand menuHICommand; + menuHICommand.commandID = menuCommand; + menuHICommand.menu.menuRef = senderMenuRef; + menuHICommand.menu.menuItemIndex = senderCarbonMenuItemIndex; + + // send Carbon Event + EventRef newEvent; + OSErr err = ::CreateEvent(NULL, kEventClassCommand, kEventCommandProcess, 0, kEventAttributeUserEvent, &newEvent); + if (err == noErr) { + err = ::SetEventParameter(newEvent, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &menuHICommand); + if (err == noErr) { + err = ::SendEventToEventTarget(newEvent, GetWindowEventTarget((WindowRef)[[NSApp keyWindow] windowRef])); + NS_ASSERTION(err == noErr, "Carbon event for menu hit not sent!"); + } + } +} + +@end diff --git a/widget/src/cocoa/nsMenuItemX.mm b/widget/src/cocoa/nsMenuItemX.mm index 1dc8d3ab0502..61eef42460bf 100644 --- a/widget/src/cocoa/nsMenuItemX.mm +++ b/widget/src/cocoa/nsMenuItemX.mm @@ -297,15 +297,7 @@ NS_METHOD nsMenuItemX::SetModifiers(PRUint8 aModifiers) mModifiers = aModifiers; // set up shortcut key modifiers on native menu item - unsigned int macModifiers = 0; - if (mModifiers & knsMenuItemShiftModifier) - macModifiers |= NSShiftKeyMask; - if (mModifiers & knsMenuItemAltModifier) - macModifiers |= NSAlternateKeyMask; - if (mModifiers & knsMenuItemControlModifier) - macModifiers |= NSControlKeyMask; - if (mModifiers & knsMenuItemCommandModifier) - macModifiers |= NSCommandKeyMask; + unsigned int macModifiers = MenuHelpersX::MacModifiersForGeckoModifiers(mModifiers); [mNativeMenuItem setKeyEquivalentModifierMask:macModifiers]; return NS_OK; diff --git a/widget/src/cocoa/nsMenuX.h b/widget/src/cocoa/nsMenuX.h index 0c3d84af3bb5..c507715dcb31 100644 --- a/widget/src/cocoa/nsMenuX.h +++ b/widget/src/cocoa/nsMenuX.h @@ -45,6 +45,7 @@ #include "nsIMenuListener.h" #include "nsIChangeManager.h" #include "nsWeakReference.h" +#include "nsMenuBarX.h" #import #import @@ -55,7 +56,8 @@ class nsIMenuListener; class nsMenuX; -// This class simply receives events from menus as a proxy for a gecko menu +// MenuDelegate is used to receive Cocoa notifications for +// setting up carbon events @interface MenuDelegate : NSObject { nsMenuX* mGeckoMenu; // weak ref diff --git a/widget/src/cocoa/nsMenuX.mm b/widget/src/cocoa/nsMenuX.mm index bb5fd5ce69ff..8efd9497da88 100644 --- a/widget/src/cocoa/nsMenuX.mm +++ b/widget/src/cocoa/nsMenuX.mm @@ -47,7 +47,6 @@ #include "prinrval.h" #include "nsMenuX.h" -#include "nsMenuBarX.h" #include "nsIMenu.h" #include "nsIMenuBar.h" #include "nsIMenuItem.h" @@ -71,8 +70,6 @@ static PRBool gConstructingMenu = PR_FALSE; -static MenuRef GetCarbonMenuRef(NSMenu* aMenu); - // CIDs #include "nsWidgetsCID.h" static NS_DEFINE_CID(kMenuCID, NS_MENU_CID); @@ -103,7 +100,10 @@ nsMenuX::nsMenuX() mDestroyHandlerCalled(PR_FALSE), mNeedsRebuild(PR_TRUE), mConstructed(PR_FALSE), mVisible(PR_TRUE), mHandler(nsnull) { - mMenuDelegate = [[MenuDelegate alloc] initWithGeckoMenu:this]; + mMenuDelegate = [[MenuDelegate alloc] initWithGeckoMenu:this]; + + if (!nsMenuBarX::sNativeEventTarget) + nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init]; } @@ -229,7 +229,7 @@ NS_IMETHODIMP nsMenuX::AddMenuItem(nsIMenuItem * aMenuItem) [mMacMenu addItem:newNativeMenuItem]; // set up target/action - [newNativeMenuItem setTarget:mMenuDelegate]; + [newNativeMenuItem setTarget:nsMenuBarX::sNativeEventTarget]; [newNativeMenuItem setAction:@selector(menuItemHit:)]; // set its command. we get the unique command id from the menubar @@ -386,7 +386,7 @@ nsEventStatus nsMenuX::MenuSelected(const nsMenuEvent & aMenuEvent) // at this point, the carbon event handler was installed so there // must be a carbon MenuRef to be had - if (GetCarbonMenuRef(mMacMenu) == selectedMenuHandle) { + if (_NSGetCarbonMenu(mMacMenu) == selectedMenuHandle) { if (mIsHelpMenu && mConstructed) { RemoveAll(); mConstructed = false; @@ -637,16 +637,14 @@ void nsMenuX::LoadMenuItem(nsIMenu* inParentMenu, nsIContent* inMenuItemContent) nsAutoString checked; nsAutoString type; nsAutoString menuitemName; - nsAutoString menuitemCmd; inMenuItemContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::disabled, disabled); inMenuItemContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::checked, checked); inMenuItemContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::type, type); inMenuItemContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::label, menuitemName); - inMenuItemContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::command, menuitemCmd); // printf("menuitem %s \n", NS_LossyConvertUCS2toASCII(menuitemName).get()); - + PRBool enabled = !(disabled.EqualsLiteral("true")); nsIMenuItem::EMenuItemType itemType = nsIMenuItem::eRegular; @@ -683,29 +681,13 @@ void nsMenuX::LoadMenuItem(nsIMenu* inParentMenu, nsIContent* inMenuItemContent) keyContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::key, keyChar); if (!keyChar.EqualsLiteral(" ")) pnsMenuItem->SetShortcutChar(keyChar); - - PRUint8 modifiers = knsMenuItemNoModifier; + nsAutoString modifiersStr; keyContent->GetAttr(kNameSpaceID_None, nsWidgetAtoms::modifiers, modifiersStr); char* str = ToNewCString(modifiersStr); - char* newStr; - char* token = nsCRT::strtok(str, ", \t", &newStr); - while (token != NULL) { - if (PL_strcmp(token, "shift") == 0) - modifiers |= knsMenuItemShiftModifier; - else if (PL_strcmp(token, "alt") == 0) - modifiers |= knsMenuItemAltModifier; - else if (PL_strcmp(token, "control") == 0) - modifiers |= knsMenuItemControlModifier; - else if ((PL_strcmp(token, "accel") == 0) || - (PL_strcmp(token, "meta") == 0)) { - modifiers |= knsMenuItemCommandModifier; - } - - token = nsCRT::strtok(newStr, ", \t", &newStr); - } + PRUint8 modifiers = MenuHelpersX::GeckoModifiersForNodeAttribute(str); nsMemory::Free(str); - + pnsMenuItem->SetModifiers(modifiers); } @@ -1230,31 +1212,8 @@ static OSStatus InstallMyMenuEventHandler(MenuRef menuRef, void* userData, Event return status; } -// #include -extern "C" MenuRef _NSGetCarbonMenu(NSMenu* aMenu); -static MenuRef GetCarbonMenuRef(NSMenu* aMenu) -{ - // we use a private API, so check for its existence and cache it (no static linking) - //XXXJOSH I don't feel like debugging this now, so I'll leave it for later - /* - typedef MenuRef (*NSGetCarbonMenuPtr)(NSMenu* menu); - static NSGetCarbonMenuPtr NSGetCarbonMenu = NULL; - - if (!NSGetCarbonMenu && NSIsSymbolNameDefined("_NSGetCarbonMenu")) - NSGetCarbonMenu = (NSGetCarbonMenuPtr)NSAddressOfSymbol(NSLookupAndBindSymbol("_NSGetCarbonMenu")); - - if (NSGetCarbonMenu) - return NSGetCarbonMenu(aMenu); - else - return NULL; - */ - return _NSGetCarbonMenu(aMenu); -} - -// -// MenuDelegate Cocoa class, receives events for the gecko menus -// +// MenuDelegate Objective-C class, used to set up Carbon events @implementation MenuDelegate @@ -1278,7 +1237,7 @@ static MenuRef GetCarbonMenuRef(NSMenu* aMenu) - (void)menuNeedsUpdate:(NSMenu*)aMenu { if (!mHaveInstalledCarbonEvents) { - MenuRef myMenuRef = GetCarbonMenuRef(aMenu); + MenuRef myMenuRef = _NSGetCarbonMenu(aMenu); if (myMenuRef) { InstallMyMenuEventHandler(myMenuRef, mGeckoMenu, nil); // can't be nil because we need to clean up mHaveInstalledCarbonEvents = TRUE; @@ -1286,37 +1245,4 @@ static MenuRef GetCarbonMenuRef(NSMenu* aMenu) } } -// called when some menu item in this menu gets hit -- (IBAction)menuItemHit:(id)sender { - MenuRef senderMenuRef = GetCarbonMenuRef([sender menu]); - int senderCarbonMenuItemIndex = [[sender menu] indexOfItem:sender] + 1; - - // If this carbon menu item has never had a command ID assigned to it, give it - // one from the sender's tag - MenuCommand menuCommand; - ::GetMenuItemCommandID(senderMenuRef, senderCarbonMenuItemIndex, &menuCommand); - if (menuCommand == 0) { - menuCommand = (MenuCommand)[sender tag]; - ::SetMenuItemCommandID(senderMenuRef, senderCarbonMenuItemIndex, menuCommand); - } - - // set up an HICommand to send - HICommand menuHICommand; - menuHICommand.commandID = menuCommand; - menuHICommand.menu.menuRef = senderMenuRef; - menuHICommand.menu.menuItemIndex = senderCarbonMenuItemIndex; - - // send Carbon Event - EventRef newEvent; - OSErr err = ::CreateEvent(NULL, kEventClassCommand, kEventCommandProcess, 0, kEventAttributeUserEvent, &newEvent); - if (err == noErr) { - err = ::SetEventParameter(newEvent, kEventParamDirectObject, typeHICommand, sizeof(HICommand), &menuHICommand); - if (err == noErr) { - err = ::SendEventToEventTarget(newEvent, GetWindowEventTarget((WindowRef)[[NSApp keyWindow] windowRef])); - NS_ASSERTION(err == noErr, "Carbon event for menu hit not sent!"); - } - } -} - - @end