Merge backout of bug 584965.

This commit is contained in:
Josh Aas 2010-08-13 15:48:00 -04:00
commit 80882b5e05
5 changed files with 240 additions and 106 deletions

View File

@ -225,8 +225,6 @@ extern "C" long TSMProcessRawKeyEvent(EventRef carbonEvent);
- (void)lockFocus;
- (void) _surfaceNeedsUpdate:(NSNotification*)notification;
- (BOOL)isPluginView;
// Simple gestures support
//
// XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,

View File

@ -179,6 +179,8 @@ PRUint32 nsChildView::sLastInputEventCount = 0;
- (void)processPendingRedraws;
- (PRBool)processKeyDownEvent:(NSEvent*)theEvent keyEquiv:(BOOL)isKeyEquiv;
- (void)maybeInitContextMenuTracking;
+ (NSEvent*)makeNewCocoaEventWithType:(NSEventType)type fromEvent:(NSEvent*)theEvent;
@ -5002,7 +5004,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
// We only send Carbon plugin events with NS_KEY_DOWN gecko events, and only send
// Cocoa plugin events with NS_KEY_PRESS gecko events. This is because we want to
// send repeat key down events to Cocoa plugins but not Carbon plugins.
- (PRBool)processKeyDownEvent:(NSEvent*)theEvent
- (PRBool)processKeyDownEvent:(NSEvent*)theEvent keyEquiv:(BOOL)isKeyEquiv
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
@ -5086,16 +5088,19 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
}
// Let Cocoa interpret the key events, caching IsIMEComposing first.
// We don't do it if this came from performKeyEquivalent because
// interpretKeyEvents isn't set up to handle those key combinations.
PRBool wasComposing = mGeckoChild->TextInputHandler()->IsIMEComposing();
PRBool interpretKeyEventsCalled = PR_FALSE;
if (mGeckoChild->TextInputHandler()->IsIMEEnabled() ||
mGeckoChild->TextInputHandler()->IsASCIICapableOnly()) {
if (!isKeyEquiv &&
(mGeckoChild->TextInputHandler()->IsIMEEnabled() ||
mGeckoChild->TextInputHandler()->IsASCIICapableOnly())) {
[super interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
interpretKeyEventsCalled = PR_TRUE;
}
if (!mGeckoChild)
return (mKeyDownHandled || mKeyPressHandled);
return (mKeyDownHandled || mKeyPressHandled);;
if (!mKeyPressSent && nonDeadKeyPress && !wasComposing &&
!mGeckoChild->TextInputHandler()->IsIMEComposing()) {
@ -5169,15 +5174,6 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
}
#endif // NP_NO_CARBON
// This is a private API that Cocoa uses.
// Cocoa will call this after the menu system returns "NO" for "performKeyEquivalent:".
// We want all they key events we can get so just return YES. In particular, this fixes
// ctrl-tab - we don't get a "keyDown:" call for that without this.
- (BOOL)_wantsKeyDownForEvent:(NSEvent*)event
{
return YES;
}
- (void)keyDown:(NSEvent*)theEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -5242,7 +5238,7 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
#endif
}
[self processKeyDownEvent:theEvent];
[self processKeyDownEvent:theEvent keyEquiv:NO];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
@ -5325,6 +5321,154 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (BOOL)performKeyEquivalent:(NSEvent*)theEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
// don't do anything if we don't have a gecko widget
if (!mGeckoChild)
return NO;
nsAutoRetainCocoaObject kungFuDeathGrip(self);
// If we're not the first responder and the first responder is an NSView
// object, pass the event on. Otherwise (if, for example, the first
// responder is an NSWindow object) we should trust the OS to have called
// us correctly.
id firstResponder = [[self window] firstResponder];
if (firstResponder != self) {
// Special handling if the other first responder is a ChildView.
if ([firstResponder isKindOfClass:[ChildView class]])
return [(ChildView *)firstResponder performKeyEquivalent:theEvent];
if ([firstResponder isKindOfClass:[NSView class]])
return [super performKeyEquivalent:theEvent];
}
// don't process if we're composing, but don't consume the event
if (mGeckoChild->TextInputHandler()->IsIMEComposing()) {
return NO;
}
UInt32 modifierFlags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
// Set to true if embedding menus handled the event when a plugin has focus.
// We give menus a crack at handling commands before Gecko in the plugin case.
BOOL handledByEmbedding = NO;
// Perform native menu UI feedback even if we stop the event from propagating to it normally.
// Recall that the menu system won't actually execute any commands for keyboard command invocations.
//
// If this is a plugin, we do actually perform the action on keyboard commands. See bug 428047.
// If the action on plugins here changes the first responder, don't continue.
NSMenu* mainMenu = [NSApp mainMenu];
if (mIsPluginView) {
if ([mainMenu isKindOfClass:[GeckoNSMenu class]]) {
// Maintain a list of cmd+key combinations that we never act on (in the
// browser) when the keyboard focus is in a plugin. What a particular
// cmd+key combo means here (to the browser) is governed by browser.dtd,
// which "contains the browser main menu items".
PRBool dontActOnKeyEquivalent = PR_FALSE;
if (modifierFlags == NSCommandKeyMask) {
NSString *unmodchars = [theEvent charactersIgnoringModifiers];
if ([unmodchars length] == 1) {
if ([unmodchars characterAtIndex:0] ==
nsMenuBarX::GetLocalizedAccelKey("key_selectAll"))
dontActOnKeyEquivalent = PR_TRUE;
}
}
if (dontActOnKeyEquivalent) {
[(GeckoNSMenu*)mainMenu performMenuUserInterfaceEffectsForEvent:theEvent];
} else {
[(GeckoNSMenu*)mainMenu actOnKeyEquivalent:theEvent];
}
}
else {
// This is probably an embedding situation. If the native menu handle the event
// then return YES from pKE no matter what Gecko or the plugin does.
handledByEmbedding = [mainMenu performKeyEquivalent:theEvent];
}
if ([[self window] firstResponder] != self)
return YES;
}
else {
if ([mainMenu isKindOfClass:[GeckoNSMenu class]])
[(GeckoNSMenu*)mainMenu performMenuUserInterfaceEffectsForEvent:theEvent];
}
// With Cmd key or Ctrl+Tab or Ctrl+Esc, keyDown will be never called.
// Therefore, we need to call processKeyDownEvent from performKeyEquivalent.
UInt32 keyCode = [theEvent keyCode];
PRBool keyDownNeverFiredEvent = (modifierFlags & NSCommandKeyMask) ||
((modifierFlags & NSControlKeyMask) &&
(keyCode == kEscapeKeyCode || keyCode == kTabKeyCode));
// don't handle this if certain modifiers are down - those should
// be sent as normal key up/down events and cocoa will do so automatically
// if we reject here
if (!keyDownNeverFiredEvent &&
(modifierFlags & (NSFunctionKeyMask| NSNumericPadKeyMask)))
return handledByEmbedding;
// Control and option modifiers are used when changing input sources in the
// input menu. We need to send such key events via "keyDown:", which will
// happen if we return NO here. This only applies to Mac OS X 10.5 and higher,
// previous OS versions just call "keyDown:" and not "performKeyEquivalent:"
// for such events.
if (!keyDownNeverFiredEvent &&
(modifierFlags & (NSControlKeyMask | NSAlternateKeyMask)))
return handledByEmbedding;
// At this point we're about to hand the event off to "processKeyDownEvent:keyEquiv:".
// Don't bother if this is a Cocoa plugin event, just handle it directly.
if (mGeckoChild && mIsPluginView && mPluginEventModel == NPEventModelCocoa) {
// Reset complex text input request.
mPluginComplexTextInputRequested = NO;
// Send key down event.
nsGUIEvent pluginEvent(PR_TRUE, NS_NON_RETARGETED_PLUGIN_EVENT, mGeckoChild);
NPCocoaEvent cocoaEvent;
ConvertCocoaKeyEventToNPCocoaEvent(theEvent, cocoaEvent);
pluginEvent.pluginEvent = &cocoaEvent;
mGeckoChild->DispatchWindowEvent(pluginEvent);
if (!mGeckoChild)
return YES;
if (!mPluginComplexTextInputRequested) {
// Ideally we'd cancel any TSM composition here.
return YES;
}
// We send these events to Carbon TSM but not to the ComplexTextInputPanel.
// We assume that events coming in through pKE: are only relevant to TSM.
#ifndef NP_NO_CARBON
[self activatePluginTSMDoc];
// We use the active TSM document to pass a pointer to ourselves (the
// currently focused ChildView) to PluginKeyEventsHandler(). Because this
// pointer is weak, we should retain and release ourselves around the call
// to TSMProcessRawKeyEvent().
nsAutoRetainCocoaObject kungFuDeathGrip(self);
::TSMSetDocumentProperty(mPluginTSMDoc, kFocusedChildViewTSMDocPropertyTag,
sizeof(ChildView *), &self);
::TSMProcessRawKeyEvent([theEvent _eventRef]);
::TSMRemoveDocumentProperty(mPluginTSMDoc, kFocusedChildViewTSMDocPropertyTag);
#endif
return YES;
}
if ([theEvent type] == NSKeyDown) {
// We trust the Gecko handled status for cmd key events. See bug 417466 for more info.
if (modifierFlags & NSCommandKeyMask)
return ([self processKeyDownEvent:theEvent keyEquiv:YES] || handledByEmbedding);
else
[self processKeyDownEvent:theEvent keyEquiv:YES];
}
return YES;
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
}
- (void)flagsChanged:(NSEvent*)theEvent
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;

View File

@ -2034,14 +2034,6 @@ static const NSString* kStateShowsToolbarButton = @"showsToolbarButton";
mScheduledShadowInvalidation = NO;
}
- (void) doCommandBySelector:(SEL)aSelector
{
// We override this so that it won't beep if it can't act.
// We want to control the beeping for missing or disabled
// commands ourselves.
[self tryToPerform:aSelector with:nil];
}
@end
// This class allows us to have a "unified toolbar" style window. It works like this:

View File

@ -69,6 +69,8 @@ public:
{
}
- (BOOL)performKeyEquivalent:(NSEvent*)theEvent;
- (void)actOnKeyEquivalent:(NSEvent*)theEvent;
- (void)performMenuUserInterfaceEffectsForEvent:(NSEvent*)theEvent;
@end
// Objective-C class used as action target for menu items

View File

@ -46,7 +46,6 @@
#include "nsCocoaUtils.h"
#include "nsCocoaWindow.h"
#include "nsToolkit.h"
#include "nsChildView.h"
#include "nsCOMPtr.h"
#include "nsString.h"
@ -730,60 +729,50 @@ void nsMenuBarX::SetParent(nsIWidget* aParent)
// We allow mouse actions to work normally.
//
// Controls whether or not native menu items should invoke their commands.
static BOOL gMenuItemsExecuteCommands = YES;
// This tells us whether or not pKE is on the stack from a GeckoNSMenu. If it
// is nil, it is not on the stack. The non-nil value is the object that put it
// on the stack first.
static GeckoNSMenu* gPerformKeyEquivOnStack = nil;
// If this is YES, act on key equivs.
static BOOL gActOnKeyEquiv = NO;
// When this variable is set to NO, don't do special command processing.
static BOOL gActOnSpecialCommands = YES;
@implementation GeckoNSMenu
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
{
// If there is no window open we will act on the menu item here.
if (![NSApp mainWindow]) {
// We've noticed that Mac OS X expects this check in subclasses.
// Do it before any actual interaction with this menu.
if ([self numberOfItems] <= 0) {
return YES;
}
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
return [super performKeyEquivalent:theEvent];
}
NS_ASSERTION(gPerformKeyEquivOnStack != self, "GeckoNSMenu pKE re-entering for the same object!");
BOOL invokeMenuItemCommand = NO;
// Don't bother doing this if we don't have any items. It appears as though
// the OS will sometimes expect this sort of check.
if ([self numberOfItems] <= 0)
return NO;
// Plugins normally eat all keyboard commands, this hack
// mitigates the problem.
NSResponder *firstResponder = [[NSApp keyWindow] firstResponder];
if (firstResponder &&
[firstResponder isKindOfClass:[ChildView class]] &&
[(ChildView*)firstResponder isPluginView]) {
invokeMenuItemCommand = YES;
// Maintain a list of cmd+key combinations that we never act on (in the
// browser) when the keyboard focus is in a plugin. What a particular
// cmd+key combo means here (to the browser) is governed by browser.dtd,
// which "contains the browser main menu items".
UInt32 modifierFlags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
if (modifierFlags == NSCommandKeyMask) {
NSString *unmodchars = [theEvent charactersIgnoringModifiers];
if ([unmodchars length] == 1) {
if ([unmodchars characterAtIndex:0] == nsMenuBarX::GetLocalizedAccelKey("key_selectAll")) {
invokeMenuItemCommand = NO;
}
}
}
}
if (!gPerformKeyEquivOnStack)
gPerformKeyEquivOnStack = self;
BOOL rv = [super performKeyEquivalent:theEvent];
if (gPerformKeyEquivOnStack == self)
gPerformKeyEquivOnStack = nil;
return rv;
if (invokeMenuItemCommand) {
[super performKeyEquivalent:theEvent];
} else {
// Show menu interface effects by invoking the native menu
// but not actually invoking the XUL command.
gMenuItemsExecuteCommands = NO;
[super performKeyEquivalent:theEvent];
gMenuItemsExecuteCommands = YES;
}
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
}
// Return NO so that we can handle the event via NSView's "keyDown:".
return NO;
-(void)actOnKeyEquivalent:(NSEvent *)theEvent
{
gActOnKeyEquiv = YES;
[self performKeyEquivalent:theEvent];
gActOnKeyEquiv = NO;
}
- (void)performMenuUserInterfaceEffectsForEvent:(NSEvent*)theEvent
{
gActOnSpecialCommands = NO;
[self performKeyEquivalent:theEvent];
gActOnSpecialCommands = YES;
}
@end
@ -799,10 +788,6 @@ static BOOL gMenuItemsExecuteCommands = YES;
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (!gMenuItemsExecuteCommands) {
return;
}
int tag = [sender tag];
MenuItemInfo* info = [sender representedObject];
@ -817,38 +802,51 @@ static BOOL gMenuItemsExecuteCommands = YES;
if (menuGroupOwner->MenuObjectType() == eMenuBarObjectType)
menuBar = static_cast<nsMenuBarX*>(menuGroupOwner);
// Do special processing if this is for an app-global command.
if (tag == eCommand_ID_About) {
nsIContent* mostSpecificContent = sAboutItemContent;
if (menuBar && menuBar->mAboutItemContent)
mostSpecificContent = menuBar->mAboutItemContent;
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
}
else if (tag == eCommand_ID_Prefs) {
nsIContent* mostSpecificContent = sPrefItemContent;
if (menuBar && menuBar->mPrefItemContent)
mostSpecificContent = menuBar->mPrefItemContent;
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
}
else if (tag == 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) {
// We want to avoid processing app-global commands when we are asked to
// perform native menu effects only. This avoids sending events twice,
// which can lead to major problems.
if (gActOnSpecialCommands) {
// Do special processing if this is for an app-global command.
if (tag == eCommand_ID_About) {
nsIContent* mostSpecificContent = sAboutItemContent;
if (menuBar && menuBar->mAboutItemContent)
mostSpecificContent = menuBar->mAboutItemContent;
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
}
else {
[NSApp terminate:nil];
return;
else if (tag == eCommand_ID_Prefs) {
nsIContent* mostSpecificContent = sPrefItemContent;
if (menuBar && menuBar->mPrefItemContent)
mostSpecificContent = menuBar->mPrefItemContent;
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
}
else if (tag == 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) {
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
}
else {
[NSApp terminate:nil];
return;
}
}
// Quit now if the "active" menu bar has changed (as the result of
// processing an app-global command above). This resolves bmo bug
// 430506.
if (menuBar != nsnull && menuBar != nsMenuBarX::sLastGeckoMenuBarPainted)
return;
}
// Quit now if the "active" menu bar has changed (as the result of
// processing an app-global command above). This resolves bmo bug
// 430506.
if (menuBar && menuBar != nsMenuBarX::sLastGeckoMenuBarPainted)
// Don't do anything unless this is not a keyboard command and
// this isn't for the hidden window menu. We assume that if there
// is no main window then the hidden window menu bar is up, even
// if that isn't true for some reason we better play it safe if
// there is no main window.
if (gPerformKeyEquivOnStack && !gActOnKeyEquiv && [NSApp mainWindow])
return;
// given the commandID, look it up in our hashtable and dispatch to
@ -866,7 +864,7 @@ static BOOL gMenuItemsExecuteCommands = YES;
// Objective-C class used for menu items on the Services menu to allow Gecko
// to override their standard behavior in order to stop key equivalents from
// firing in certain instances. When gMenuItemsExecuteCommands is NO, we return
// firing in certain instances. When gActOnSpecialCommands is NO, we return
// a dummy target and action instead of the actual target and action.
@implementation GeckoServicesNSMenuItem
@ -874,19 +872,19 @@ static BOOL gMenuItemsExecuteCommands = YES;
- (id) target
{
id realTarget = [super target];
if (gMenuItemsExecuteCommands)
if (gActOnSpecialCommands)
return realTarget;
else
return realTarget ? self : nil;
return realTarget != nil ? self : nil;
}
- (SEL) action
{
SEL realAction = [super action];
if (gMenuItemsExecuteCommands)
if (gActOnSpecialCommands)
return realAction;
else
return realAction ? @selector(_doNothing:) : NULL;
return realAction != NULL ? @selector(_doNothing:) : NULL;
}
- (void) _doNothing:(id)sender