diff --git a/mozilla/widget/src/cocoa/nsMenuBarX.h b/mozilla/widget/src/cocoa/nsMenuBarX.h index a75771aff06..896e2a0c333 100644 --- a/mozilla/widget/src/cocoa/nsMenuBarX.h +++ b/mozilla/widget/src/cocoa/nsMenuBarX.h @@ -172,7 +172,7 @@ public: // |NSMenuItem|s target Objective-C objects static NativeMenuItemTarget* sNativeEventTarget; - static NSWindow* sEventTargetWindow; + static nsMenuBarX* sLastGeckoMenuBarPainted; NS_DECL_ISUPPORTS @@ -197,6 +197,7 @@ public: PRUint32 RegisterForCommand(nsIMenuItem* aItem); void UnregisterCommand(PRUint32 aCommandID); + nsIMenuItem* GetMenuItemForCommandID(PRUint32 inCommandID); void RegisterForContentChanges(nsIContent* aContent, nsChangeObserver* aMenuObject); void UnregisterForContentChanges(nsIContent* aContent); @@ -204,41 +205,30 @@ public: void RegisterKeyEquivalent(unsigned int modifiers, NSString* string); void UnregisterKeyEquivalent(unsigned int modifiers, NSString* string); + + nsCOMPtr mAboutItemContent; // holds the content node for the about item that has + // been removed from the menubar + nsCOMPtr mPrefItemContent; // as above, but for prefs + nsCOMPtr mQuitItemContent; // as above, but for quit protected: // Make our menubar conform to Aqua UI guidelines void AquifyMenuBar(); void HideItem(nsIDOMDocument* inDoc, const nsAString & inID, nsIContent** outHiddenNode); - OSStatus InstallCommandEventHandler(); - // command handler for some special menu items (prefs/quit/etc) - pascal static OSStatus CommandEventHandler(EventHandlerCallRef inHandlerChain, - EventRef inEvent, void* userData); - nsEventStatus ExecuteCommand(nsIContent* inDispatchTo); - // build the Application menu shared by all menu bars. NSMenuItem* CreateNativeAppMenuItem(nsIMenu* inMenu, const nsAString& nodeID, SEL action, int tag, NativeMenuItemTarget* target); nsresult CreateApplicationMenu(nsIMenu* inMenu); - nsHashtable mObserverTable; // stores observers for content change notification - nsCOMArray mMenusArray; // holds refs nsCOMPtr mMenuBarContent; // menubar content node, strong ref - nsCOMPtr mAboutItemContent; // holds the content node for the about item that has - // been removed from the menubar - nsCOMPtr mPrefItemContent; // as above, but for prefs - nsCOMPtr mQuitItemContent; // as above, but for quit nsIWidget* mParent; // weak ref PRBool mIsMenuBarAdded; PRUint32 mCurrentCommandID; // unique command id (per menu-bar) to give to next item that asks - nsIDocument* mDocument; // pointer to document - NSMenu* mRootMenu; // root menu, representing entire menu bar - + nsHashtable mObserverTable; // stores observers for content change notification nsTHashtable mKeyEquivTable; - - static EventHandlerUPP sCommandEventHandler; // carbon event handler for commands, shared }; #endif // nsMenuBarX_h_ diff --git a/mozilla/widget/src/cocoa/nsMenuBarX.mm b/mozilla/widget/src/cocoa/nsMenuBarX.mm index c13763dcd1b..ba5f31f00a5 100644 --- a/mozilla/widget/src/cocoa/nsMenuBarX.mm +++ b/mozilla/widget/src/cocoa/nsMenuBarX.mm @@ -68,9 +68,8 @@ static NS_DEFINE_CID(kMenuCID, NS_MENU_CID); NS_IMPL_ISUPPORTS3(nsMenuBarX, nsIMenuBar, nsIMutationObserver, nsISupportsWeakReference) -EventHandlerUPP nsMenuBarX::sCommandEventHandler = nsnull; NativeMenuItemTarget* nsMenuBarX::sNativeEventTarget = nil; -NSWindow* nsMenuBarX::sEventTargetWindow = nil; +nsMenuBarX* nsMenuBarX::sLastGeckoMenuBarPainted = nsnull; NSMenu* sApplicationMenu = nil; BOOL gSomeMenuBarPainted = NO; @@ -111,10 +110,6 @@ nsMenuBarX::nsMenuBarX() NS_OBJC_BEGIN_TRY_ABORT_BLOCK; mRootMenu = [[NSMenu alloc] initWithTitle:@"MainMenuBar"]; - - // create our global carbon event command handler shared by all windows - if (!sCommandEventHandler) - sCommandEventHandler = ::NewEventHandlerUPP(CommandEventHandler); NS_OBJC_END_TRY_ABORT_BLOCK; } @@ -179,124 +174,6 @@ nsMenuBarX::AquifyMenuBar() } -// Grab our window and install an event handler to handle command events which are -// used to drive the action when the user chooses an item from a menu. We have to install -// it on the window because the menubar isn't in the event chain for a menu command event. -OSStatus -nsMenuBarX::InstallCommandEventHandler() -{ - NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; - - OSStatus err = noErr; - NSWindow* myWindow = reinterpret_cast(mParent->GetNativeData(NS_NATIVE_WINDOW)); - WindowRef myWindowRef = (WindowRef)[myWindow windowRef]; - NS_ASSERTION(myWindowRef, "Can't get WindowRef to install command handler!"); - if (myWindowRef && sCommandEventHandler) { - const EventTypeSpec commandEventList[] = {{kEventClassCommand, kEventCommandProcess}}; - err = ::InstallWindowEventHandler(myWindowRef, sCommandEventHandler, GetEventTypeCount(commandEventList), commandEventList, this, NULL); - NS_ASSERTION(err == noErr, "Uh oh, command handler not installed"); - } - return err; - - NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(noErr); -} - - -// Processes Command carbon events from enabling/selecting of items in the menu. -pascal OSStatus -nsMenuBarX::CommandEventHandler(EventHandlerCallRef inHandlerChain, EventRef inEvent, void* userData) -{ - NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; - - OSStatus handled = eventNotHandledErr; - - HICommand command; - OSErr err1 = ::GetEventParameter(inEvent, kEventParamDirectObject, typeHICommand, - NULL, sizeof(HICommand), NULL, &command); - if (err1) - return handled; - - nsMenuBarX* self = reinterpret_cast(userData); - - switch (command.commandID) { - case eCommand_ID_About: - { - nsIContent* mostSpecificContent = sAboutItemContent; - if (self->mAboutItemContent) - mostSpecificContent = self->mAboutItemContent; - - nsEventStatus status = self->ExecuteCommand(mostSpecificContent); - if (status == nsEventStatus_eConsumeNoDefault) // event handled, no other processing - handled = noErr; - break; - } - - case eCommand_ID_Prefs: - { - nsIContent* mostSpecificContent = sPrefItemContent; - if (self->mPrefItemContent) - mostSpecificContent = self->mPrefItemContent; - - nsEventStatus status = self->ExecuteCommand(mostSpecificContent); - if (status == nsEventStatus_eConsumeNoDefault) // event handled, no other processing - handled = noErr; - break; - } - - case eCommand_ID_Quit: - { - nsIContent* mostSpecificContent = sQuitItemContent; - if (self->mQuitItemContent) - mostSpecificContent = self->mQuitItemContent; - - // If we have some content for quit we execute it. Otherwise we send a native app terminate - // message. If you want to stop a quit from happening, provide quit content and return - // the event as unhandled. - if (mostSpecificContent) { - nsEventStatus status = self->ExecuteCommand(mostSpecificContent); - if (status == nsEventStatus_eConsumeNoDefault) // event handled, no other processing - handled = noErr; - } - else { - [NSApp terminate:nil]; - handled = noErr; - } - break; - } - - default: - { - // given the commandID, look it up in our hashtable and dispatch to - // that content node. Recall that we store weak pointers to the content - // nodes in the hash table. - nsPRUint32Key key(command.commandID); - nsIMenuItem* content = reinterpret_cast(self->mObserverTable.Get(&key)); - if (content) { - content->DoCommand(); - handled = noErr; - } - break; - } - } // switch on commandID - - return handled; - - NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(noErr); -} - - -// Execute the menu item by sending a command message to the -// DOM node specified in |inDispatchTo|. -nsEventStatus -nsMenuBarX::ExecuteCommand(nsIContent* inDispatchTo) -{ - if (!inDispatchTo) - return nsEventStatus_eIgnore; - - return MenuHelpersX::DispatchCommandTo(inDispatchTo); -} - - // Hide the item in the menu by setting the 'hidden' attribute. Returns it in |outHiddenNode| so // the caller can hang onto it if they so choose. It is acceptable to pass nsull // for |outHiddenNode| if the caller doesn't care about the hidden node. @@ -329,10 +206,6 @@ nsMenuBarX::MenuConstruct(const nsMenuEvent & aMenuEvent, nsIWidget* aParentWind AquifyMenuBar(); - OSStatus err = InstallCommandEventHandler(); - if (err) - return NS_ERROR_FAILURE; - nsCOMPtr domDoc; domNode->GetOwnerDocument(getter_AddRefs(domDoc)); nsCOMPtr doc(do_QueryInterface(domDoc)); @@ -733,7 +606,7 @@ NS_IMETHODIMP nsMenuBarX::Paint() // Set menu bar and event target. [NSApp setMainMenu:mRootMenu]; - nsMenuBarX::sEventTargetWindow = (NSWindow*)mParent->GetNativeData(NS_NATIVE_WINDOW); + nsMenuBarX::sLastGeckoMenuBarPainted = this; gSomeMenuBarPainted = YES; @@ -932,6 +805,14 @@ nsMenuBarX::UnregisterCommand(PRUint32 inCommandID) } +nsIMenuItem* +nsMenuBarX::GetMenuItemForCommandID(PRUint32 inCommandID) +{ + nsPRUint32Key key(inCommandID); + return reinterpret_cast(mObserverTable.Get(&key)); +} + + nsEventStatus MenuHelpersX::DispatchCommandTo(nsIContent* aTargetContent) { @@ -1089,40 +970,55 @@ NSMenuItem* MenuHelpersX::GetStandardEditMenuItem() { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; - // just abort if we don't have a target window for events - if (!nsMenuBarX::sEventTargetWindow) { - NS_WARNING("No target window for keyboard events!"); - return; - } - - 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)[nsMenuBarX::sEventTargetWindow windowRef])); - NS_ASSERTION(err == noErr, "Carbon event for menu hit either not sent or not handled!"); + nsMenuBarX* menuBar = nsMenuBarX::sLastGeckoMenuBarPainted; + int tag = [sender tag]; + switch (tag) { + case eCommand_ID_About: + { + nsIContent* mostSpecificContent = sAboutItemContent; + if (menuBar && menuBar->mAboutItemContent) + mostSpecificContent = menuBar->mAboutItemContent; + MenuHelpersX::DispatchCommandTo(mostSpecificContent); + break; + } + + case eCommand_ID_Prefs: + { + nsIContent* mostSpecificContent = sPrefItemContent; + if (menuBar && menuBar->mPrefItemContent) + mostSpecificContent = menuBar->mPrefItemContent; + MenuHelpersX::DispatchCommandTo(mostSpecificContent); + break; + } + + case eCommand_ID_Quit: + { + nsIContent* mostSpecificContent = sQuitItemContent; + if (menuBar && menuBar->mQuitItemContent) + mostSpecificContent = menuBar->mQuitItemContent; + // If we have some content for quit we execute it. Otherwise we send a native app terminate + // message. If you want to stop a quit from happening, provide quit content and return + // the event as unhandled. + if (mostSpecificContent) + MenuHelpersX::DispatchCommandTo(mostSpecificContent); + else + [NSApp terminate:nil]; + break; + } + + default: + { + // Can't do anything if we don't know the last painted menu bar. + if (!menuBar) + return; + // given the commandID, look it up in our hashtable and dispatch to + // that content node. Recall that we store weak pointers to the content + // nodes in the hash table. + nsIMenuItem* content = menuBar->GetMenuItemForCommandID(static_cast(tag)); + if (content) + content->DoCommand(); + break; } - ReleaseEvent(newEvent); } NS_OBJC_END_TRY_ABORT_BLOCK;