зеркало из https://github.com/mozilla/pjs.git
Change keyboard command event propagation in Cocoa widgets. Allow normal propagation through the view system when there is a window present regardless of a native menu item's enabled status. Also get rid of native menu command hash table because it is no longer necessary. Fixes bugs 382138 (key commands not working due to lazy menu item enabled status updates), 413681 (can't copy/paste in google spreadsheets), and 418334 (Flash unable to intercept meta key events). Also includes a crash fix from Steven Michaud. b=398514 r=smichaud sr=vlad
This commit is contained in:
Родитель
fd35132d02
Коммит
36af0234a2
|
@ -174,23 +174,6 @@ nsIWidget * gRollupWidget = nsnull;
|
|||
@end
|
||||
|
||||
|
||||
// Used to retain an NSView for the remainder of a method's execution.
|
||||
class nsAutoRetainView {
|
||||
public:
|
||||
nsAutoRetainView(NSView *aView)
|
||||
{
|
||||
mView = NS_OBJC_TRY_EXPR_ABORT([aView retain]);
|
||||
}
|
||||
~nsAutoRetainView()
|
||||
{
|
||||
NS_OBJC_TRY_ABORT([mView release]);
|
||||
}
|
||||
|
||||
private:
|
||||
NSView *mView; // [STRONG]
|
||||
};
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
|
||||
|
@ -838,7 +821,7 @@ NS_IMETHODIMP nsChildView::SetFocus(PRBool aRaise)
|
|||
mInSetFocus = PR_TRUE;
|
||||
NSWindow* window = [mView window];
|
||||
if (window) {
|
||||
nsAutoRetainView kungFuDeathGrip(mView);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(mView);
|
||||
// For reasons that aren't yet clear, focus changes within a window (as
|
||||
// opposed to those between windows or between apps) should only trigger
|
||||
// NS_LOSTFOCUS and NS_GOTFOCUS events (sent to Gecko) in the context of
|
||||
|
@ -2557,7 +2540,7 @@ NSEvent* gLastDragEvent = nil;
|
|||
paintEvent.rect = &fullRect;
|
||||
paintEvent.region = rgn;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
mGeckoChild->DispatchWindowEvent(paintEvent);
|
||||
if (!mGeckoChild)
|
||||
return;
|
||||
|
@ -2814,7 +2797,7 @@ NSEvent* gLastDragEvent = nil;
|
|||
if (![self ensureCorrectMouseEventTarget:theEvent])
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
if ([self maybeRollup:theEvent])
|
||||
return;
|
||||
|
@ -3003,7 +2986,7 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
|
|||
if (!mGeckoChild)
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
if (sLastViewEntered != self) {
|
||||
if (sLastViewEntered) {
|
||||
NSPoint exitEventLocation = [sLastViewEntered convertPoint:windowEventLocation fromView:nil];
|
||||
|
@ -3107,7 +3090,7 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
|
|||
if (![self ensureCorrectMouseEventTarget:theEvent])
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
[self maybeRollup:theEvent];
|
||||
if (!mGeckoChild)
|
||||
|
@ -3163,7 +3146,7 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
|
|||
macEvent.modifiers = controlKey; // fake a context menu click
|
||||
geckoEvent.nativeMsg = &macEvent;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
PRBool handled = mGeckoChild->DispatchMouseEvent(geckoEvent);
|
||||
if (!mGeckoChild)
|
||||
return;
|
||||
|
@ -3200,7 +3183,7 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
|
|||
if (![self ensureCorrectMouseEventTarget:theEvent])
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
if ([self maybeRollup:theEvent])
|
||||
return;
|
||||
|
@ -3281,7 +3264,7 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
|
|||
else
|
||||
geckoEvent.delta = (PRInt32)ceilf(scrollDelta);
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
||||
if (!mGeckoChild)
|
||||
return;
|
||||
|
@ -3336,7 +3319,7 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
|
|||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
if ([self maybeRollup:theEvent])
|
||||
return;
|
||||
|
@ -3364,7 +3347,7 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
|
|||
if (!mGeckoChild || [self isPluginView])
|
||||
return nil;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
[self maybeRollup:theEvent];
|
||||
if (!mGeckoChild)
|
||||
|
@ -3982,7 +3965,7 @@ static PRBool IsNormalCharInputtingEvent(const nsKeyEvent& aEvent)
|
|||
if (!mGeckoChild)
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
id arp = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if (![insertString isKindOfClass:[NSAttributedString class]])
|
||||
|
@ -4111,7 +4094,7 @@ static PRBool IsNormalCharInputtingEvent(const nsKeyEvent& aEvent)
|
|||
NSLog(@" aString = '%@'", aString);
|
||||
#endif
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
id arp = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if (![aString isKindOfClass:[NSAttributedString class]])
|
||||
|
@ -4402,7 +4385,7 @@ static PRBool IsNormalCharInputtingEvent(const nsKeyEvent& aEvent)
|
|||
if (!mGeckoChild)
|
||||
return NO;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
mCurKeyEvent = theEvent;
|
||||
|
||||
BOOL nonDeadKeyPress = [[theEvent characters] length] > 0;
|
||||
|
@ -4536,7 +4519,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
if (!mGeckoChild || [[theEvent characters] length] == 0)
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
// Cocoa doesn't send an NSKeyDown event for control-tab on 10.4, so if this
|
||||
// is an NSKeyUp event for control-tab, send a down event to gecko first.
|
||||
|
@ -4613,46 +4596,32 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
if (!mGeckoChild)
|
||||
return NO;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
// if we aren't the first responder, pass the event on
|
||||
if ([[self window] firstResponder] != self)
|
||||
return [super performKeyEquivalent:theEvent];
|
||||
id firstResponder = [[self window] firstResponder];
|
||||
if (firstResponder != self) {
|
||||
if ([firstResponder isKindOfClass:[ChildView class]])
|
||||
return [(ChildView *)firstResponder performKeyEquivalent:theEvent];
|
||||
else
|
||||
return [super performKeyEquivalent:theEvent];
|
||||
}
|
||||
|
||||
// don't process if we're composing, but don't consume the event
|
||||
if (nsTSMManager::IsComposing())
|
||||
return NO;
|
||||
|
||||
unsigned int modifierFlags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
|
||||
|
||||
// see if the menu system will handle the event
|
||||
if ([[NSApp mainMenu] performKeyEquivalent:theEvent]) {
|
||||
return YES;
|
||||
}
|
||||
else {
|
||||
// On Mac OS X 10.5 NSMenu's performKeyEquivalent: method returns NO for disabled menu
|
||||
// items that have a matching key equiv. We need to know if that was the case so we can
|
||||
// stop here like we would on 10.4 (it returns YES in that case). Since we want to eat
|
||||
// the event if that happens the system won't give the disabled command beep, do it here
|
||||
// manually.
|
||||
if (nsToolkit::OnLeopardOrLater()) {
|
||||
id delegate = [[self window] delegate];
|
||||
if (delegate && [delegate isKindOfClass:[WindowDelegate class]]) {
|
||||
nsCocoaWindow* toplevelWindow = [delegate geckoWidget];
|
||||
if (toplevelWindow) {
|
||||
nsMenuBarX* menuBar = static_cast<nsMenuBarX*>(toplevelWindow->GetMenuBar());
|
||||
if (menuBar && menuBar->ContainsKeyEquiv(modifierFlags, [theEvent characters])) {
|
||||
NSBeep();
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
// By checking the class for the main menu we ensure that we don't do any of this for embedders.
|
||||
NSMenu* mainMenu = [NSApp mainMenu];
|
||||
if ([mainMenu isKindOfClass:[GeckoNSMenu class]])
|
||||
[(GeckoNSMenu*)mainMenu performMenuUserInterfaceEffectsForEvent:theEvent];
|
||||
|
||||
// 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
|
||||
unsigned int modifierFlags = [theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask;
|
||||
if ((modifierFlags & NSFunctionKeyMask) || (modifierFlags & NSNumericPadKeyMask))
|
||||
return NO;
|
||||
|
||||
|
@ -4677,7 +4646,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
if (!mGeckoChild)
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
// Fire key up/down events for the modifier keys (shift, alt, ctrl, command).
|
||||
if ([theEvent type] == NSFlagsChanged) {
|
||||
|
@ -4745,7 +4714,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
if (!mGeckoChild)
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
// check to see if the window implements the mozWindow protocol. This
|
||||
// allows embedders to avoid re-entrant calls to -makeKeyAndOrderFront,
|
||||
|
@ -4770,7 +4739,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
if (!mGeckoChild)
|
||||
return;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
|
||||
[self sendFocusEvent:NS_DEACTIVATE];
|
||||
[self sendFocusEvent:NS_LOSTFOCUS];
|
||||
|
@ -4866,7 +4835,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
geckoEvent.refPoint.x = static_cast<nscoord>(localPoint.x);
|
||||
geckoEvent.refPoint.y = static_cast<nscoord>(localPoint.y);
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
mGeckoChild->DispatchWindowEvent(geckoEvent);
|
||||
if (!mGeckoChild)
|
||||
return YES;
|
||||
|
@ -4925,7 +4894,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
{
|
||||
PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingExited: entered\n"));
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
[self doDragAction:NS_DRAGDROP_EXIT sender:sender];
|
||||
NS_IF_RELEASE(mDragService);
|
||||
}
|
||||
|
@ -4933,7 +4902,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
|
||||
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
BOOL handled = [self doDragAction:NS_DRAGDROP_DROP sender:sender];
|
||||
NS_IF_RELEASE(mDragService);
|
||||
return handled;
|
||||
|
@ -5053,7 +5022,7 @@ static BOOL keyUpAlreadySentKeyDown = NO;
|
|||
|
||||
id<mozAccessible> nativeAccessible = nil;
|
||||
|
||||
nsAutoRetainView kungFuDeathGrip(self);
|
||||
nsAutoRetainCocoaObject kungFuDeathGrip(self);
|
||||
nsCOMPtr<nsIWidget> kungFuDeathGrip2(mGeckoChild);
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
mGeckoChild->GetDocumentAccessible(getter_AddRefs(accessible));
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "nsRect.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
// "Borrowed" in part from the QTKit framework's QTKitDefines.h. This is
|
||||
// needed when building on OS X Tiger (10.4.X) or with a 10.4 SDK. It won't
|
||||
|
@ -67,6 +68,23 @@ typedef unsigned int NSUInteger;
|
|||
|
||||
#endif /* NSINTEGER_DEFINED */
|
||||
|
||||
|
||||
// Used to retain a Cocoa object for the remainder of a method's execution.
|
||||
class nsAutoRetainCocoaObject {
|
||||
public:
|
||||
nsAutoRetainCocoaObject(id anObject)
|
||||
{
|
||||
mObject = NS_OBJC_TRY_EXPR_ABORT([anObject retain]);
|
||||
}
|
||||
~nsAutoRetainCocoaObject()
|
||||
{
|
||||
NS_OBJC_TRY_ABORT([mObject release]);
|
||||
}
|
||||
private:
|
||||
id mObject; // [STRONG]
|
||||
};
|
||||
|
||||
|
||||
@interface NSApplication (Undocumented)
|
||||
|
||||
// Present in all versions of OS X from (at least) 10.2.8 through 10.5.
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
#include "nsMenuBarX.h"
|
||||
#include "nsCocoaWindow.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
|
|
@ -1396,8 +1396,10 @@ NS_IMETHODIMP nsCocoaWindow::EndSecureKeyboardInput()
|
|||
NSMenu* mainMenu = [NSApp mainMenu];
|
||||
NS_ASSERTION([mainMenu numberOfItems] > 0, "Main menu does not have any items, something is terribly wrong!");
|
||||
|
||||
// create a new menu bar
|
||||
NSMenu* newMenuBar = [[NSMenu alloc] initWithTitle:@"MainMenuBar"];
|
||||
// Create a new menu bar.
|
||||
// We create a GeckoNSMenu because all menu bar NSMenu objects should use that subclass for
|
||||
// key handling reasons.
|
||||
GeckoNSMenu* newMenuBar = [[GeckoNSMenu alloc] initWithTitle:@"MainMenuBar"];
|
||||
|
||||
// move the application menu from the existing menu bar to the new one
|
||||
NSMenuItem* firstMenuItem = [[mainMenu itemAtIndex:0] retain];
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include "nsIMutationObserver.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIContent.h"
|
||||
|
||||
|
@ -71,6 +70,17 @@ namespace MenuHelpersX
|
|||
}
|
||||
|
||||
|
||||
// Objective-C class used to allow us to have keyboard commands
|
||||
// look like they are doing something but actually do nothing.
|
||||
// We allow mouse actions to work normally.
|
||||
@interface GeckoNSMenu : NSMenu
|
||||
{
|
||||
}
|
||||
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent;
|
||||
- (void)performMenuUserInterfaceEffectsForEvent:(NSEvent*)theEvent;
|
||||
@end
|
||||
|
||||
|
||||
// Objective-C class used as action target for menu items
|
||||
@interface NativeMenuItemTarget : NSObject
|
||||
{
|
||||
|
@ -79,84 +89,6 @@ namespace MenuHelpersX
|
|||
@end
|
||||
|
||||
|
||||
struct CocoaKeyEquivContainer {
|
||||
CocoaKeyEquivContainer(const unsigned int modifiers, const NSString* string)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
mModifiers = modifiers;
|
||||
mString = [string retain];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
~CocoaKeyEquivContainer()
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
[mString release];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
CocoaKeyEquivContainer(const CocoaKeyEquivContainer& other)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
mModifiers = other.mModifiers;
|
||||
mString = [other.mString retain];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
CocoaKeyEquivContainer& operator=(CocoaKeyEquivContainer& other)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
mModifiers = other.mModifiers;
|
||||
if (mString)
|
||||
[mString release];
|
||||
mString = [other.mString retain];
|
||||
return *this;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(*this);
|
||||
}
|
||||
|
||||
unsigned int mModifiers;
|
||||
NSString* mString;
|
||||
};
|
||||
|
||||
|
||||
struct CocoaKeyEquivKey : public PLDHashEntryHdr {
|
||||
typedef const CocoaKeyEquivContainer& KeyType;
|
||||
typedef const CocoaKeyEquivContainer* KeyTypePointer;
|
||||
|
||||
CocoaKeyEquivKey(KeyTypePointer aObj) : mObj(*aObj) { }
|
||||
CocoaKeyEquivKey(const CocoaKeyEquivKey& other) : mObj(other.mObj) { }
|
||||
~CocoaKeyEquivKey() { }
|
||||
|
||||
KeyType GetKey() const { return mObj; }
|
||||
|
||||
PRBool KeyEquals(KeyTypePointer aKey) const {
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
return aKey->mModifiers == mObj.mModifiers &&
|
||||
[aKey->mString isEqualToString:mObj.mString];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(PR_FALSE);
|
||||
}
|
||||
|
||||
static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
|
||||
static PLDHashNumber HashKey(KeyTypePointer aKey) {
|
||||
return [aKey->mString hash] ^ aKey->mModifiers;
|
||||
}
|
||||
enum { ALLOW_MEMMOVE = PR_FALSE };
|
||||
private:
|
||||
const CocoaKeyEquivContainer mObj;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Native menu bar wrapper
|
||||
//
|
||||
|
@ -193,7 +125,6 @@ public:
|
|||
NS_IMETHOD Paint();
|
||||
NS_IMETHOD SetNativeData(void* aData);
|
||||
NS_IMETHOD MenuConstruct(const nsMenuEvent & aMenuEvent, nsIWidget * aParentWindow, void * aMenuNode);
|
||||
PRBool ContainsKeyEquiv(unsigned int modifiers, NSString* string);
|
||||
|
||||
PRUint32 RegisterForCommand(nsIMenuItem* aItem);
|
||||
void UnregisterCommand(PRUint32 aCommandID);
|
||||
|
@ -203,9 +134,6 @@ public:
|
|||
void UnregisterForContentChanges(nsIContent* aContent);
|
||||
nsChangeObserver* LookupContentChangeObserver(nsIContent* aContent);
|
||||
|
||||
void RegisterKeyEquivalent(unsigned int modifiers, NSString* string);
|
||||
void UnregisterKeyEquivalent(unsigned int modifiers, NSString* string);
|
||||
|
||||
nsCOMPtr<nsIContent> mAboutItemContent; // holds the content node for the about item that has
|
||||
// been removed from the menubar
|
||||
nsCOMPtr<nsIContent> mPrefItemContent; // as above, but for prefs
|
||||
|
@ -226,9 +154,8 @@ protected:
|
|||
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
|
||||
GeckoNSMenu* mRootMenu; // root menu, representing entire menu bar
|
||||
nsHashtable mObserverTable; // stores observers for content change notification
|
||||
nsTHashtable<CocoaKeyEquivKey> mKeyEquivTable;
|
||||
};
|
||||
|
||||
#endif // nsMenuBarX_h_
|
||||
|
|
|
@ -109,7 +109,7 @@ nsMenuBarX::nsMenuBarX()
|
|||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
mRootMenu = [[NSMenu alloc] initWithTitle:@"MainMenuBar"];
|
||||
mRootMenu = [[GeckoNSMenu alloc] initWithTitle:@"MainMenuBar"];
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
@ -246,8 +246,6 @@ nsMenuBarX::MenuConstruct(const nsMenuEvent & aMenuEvent, nsIWidget* aParentWind
|
|||
NS_IMETHODIMP nsMenuBarX::Create(nsIWidget *aParent)
|
||||
{
|
||||
SetParent(aParent);
|
||||
if (!mKeyEquivTable.Init())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -753,27 +751,6 @@ nsMenuBarX::LookupContentChangeObserver(nsIContent* aContent)
|
|||
}
|
||||
|
||||
|
||||
void nsMenuBarX::RegisterKeyEquivalent(unsigned int modifiers, NSString* string)
|
||||
{
|
||||
const CocoaKeyEquivContainer keyEquiv(modifiers, string);
|
||||
mKeyEquivTable.PutEntry(keyEquiv);
|
||||
}
|
||||
|
||||
|
||||
void nsMenuBarX::UnregisterKeyEquivalent(unsigned int modifiers, NSString* string)
|
||||
{
|
||||
CocoaKeyEquivContainer keyEquiv(modifiers, string);
|
||||
mKeyEquivTable.RemoveEntry(keyEquiv);
|
||||
}
|
||||
|
||||
|
||||
PRBool nsMenuBarX::ContainsKeyEquiv(unsigned int modifiers, NSString* string)
|
||||
{
|
||||
const CocoaKeyEquivContainer keyEquiv(modifiers, string);
|
||||
return (mKeyEquivTable.GetEntry(keyEquiv) != nsnull);
|
||||
}
|
||||
|
||||
|
||||
// Given a menu item, creates a unique 4-character command ID and
|
||||
// maps it to the item. Returns the id for use by the client.
|
||||
PRUint32
|
||||
|
@ -958,6 +935,54 @@ NSMenuItem* MenuHelpersX::GetStandardEditMenuItem()
|
|||
}
|
||||
|
||||
|
||||
//
|
||||
// Objective-C class used to allow us to have keyboard commands
|
||||
// look like they are doing something but actually do nothing.
|
||||
// We allow mouse actions to work normally.
|
||||
//
|
||||
|
||||
|
||||
// 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;
|
||||
// When this variable is set to YES, don't do special command processing.
|
||||
static BOOL gMenuEffectsOnly = NO;
|
||||
|
||||
@implementation GeckoNSMenu
|
||||
|
||||
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
|
||||
|
||||
NS_ASSERTION(gPerformKeyEquivOnStack != self, "GeckoNSMenu pKE re-entering for the same object!");
|
||||
|
||||
// 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;
|
||||
|
||||
if (!gPerformKeyEquivOnStack)
|
||||
gPerformKeyEquivOnStack = self;
|
||||
BOOL rv = [super performKeyEquivalent:theEvent];
|
||||
if (gPerformKeyEquivOnStack == self)
|
||||
gPerformKeyEquivOnStack = nil;
|
||||
return rv;
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
|
||||
}
|
||||
|
||||
|
||||
- (void)performMenuUserInterfaceEffectsForEvent:(NSEvent*)theEvent
|
||||
{
|
||||
gMenuEffectsOnly = YES;
|
||||
[self performKeyEquivalent:theEvent];
|
||||
gMenuEffectsOnly = NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//
|
||||
// Objective-C class used as action target for menu items
|
||||
//
|
||||
|
@ -970,57 +995,60 @@ NSMenuItem* MenuHelpersX::GetStandardEditMenuItem()
|
|||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
nsMenuBarX* menuBar = nsMenuBarX::sLastGeckoMenuBarPainted;
|
||||
int tag = [sender tag];
|
||||
switch (tag) {
|
||||
case eCommand_ID_About:
|
||||
{
|
||||
nsMenuBarX* menuBar = nsMenuBarX::sLastGeckoMenuBarPainted;
|
||||
|
||||
// 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 (!gMenuEffectsOnly) {
|
||||
// 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;
|
||||
MenuHelpersX::DispatchCommandTo(mostSpecificContent);
|
||||
break;
|
||||
}
|
||||
|
||||
case eCommand_ID_Prefs:
|
||||
{
|
||||
else if (tag == eCommand_ID_Prefs) {
|
||||
nsIContent* mostSpecificContent = sPrefItemContent;
|
||||
if (menuBar && menuBar->mPrefItemContent)
|
||||
mostSpecificContent = menuBar->mPrefItemContent;
|
||||
MenuHelpersX::DispatchCommandTo(mostSpecificContent);
|
||||
break;
|
||||
}
|
||||
|
||||
case eCommand_ID_Quit:
|
||||
{
|
||||
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)
|
||||
if (mostSpecificContent) {
|
||||
MenuHelpersX::DispatchCommandTo(mostSpecificContent);
|
||||
else
|
||||
}
|
||||
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<PRUint32>(tag));
|
||||
if (content)
|
||||
content->DoCommand();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 && [NSApp mainWindow])
|
||||
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.
|
||||
if (menuBar) {
|
||||
nsIMenuItem* content = menuBar->GetMenuItemForCommandID(static_cast<PRUint32>(tag));
|
||||
if (content)
|
||||
content->DoCommand();
|
||||
}
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
|
|
|
@ -349,8 +349,6 @@ void nsMenuItemX::SetKeyEquiv(PRUint8 aModifiers, const nsString &aText)
|
|||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
|
||||
|
||||
mMenuBar->UnregisterKeyEquivalent([mNativeMenuItem keyEquivalentModifierMask], [mNativeMenuItem keyEquivalent]);
|
||||
|
||||
mModifiers = aModifiers;
|
||||
unsigned int macModifiers = MenuHelpersX::MacModifiersForGeckoModifiers(mModifiers);
|
||||
[mNativeMenuItem setKeyEquivalentModifierMask:macModifiers];
|
||||
|
@ -363,8 +361,6 @@ void nsMenuItemX::SetKeyEquiv(PRUint8 aModifiers, const nsString &aText)
|
|||
else
|
||||
[mNativeMenuItem setKeyEquivalent:keyEquivalent];
|
||||
|
||||
mMenuBar->RegisterKeyEquivalent([mNativeMenuItem keyEquivalentModifierMask], [mNativeMenuItem keyEquivalent]);
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK;
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ protected:
|
|||
void LoadMenuItem(nsIContent* inMenuItemContent);
|
||||
void LoadSubMenu(nsIContent* inMenuContent);
|
||||
|
||||
NSMenu* CreateMenuWithGeckoString(nsString& menuTitle);
|
||||
GeckoNSMenu* CreateMenuWithGeckoString(nsString& menuTitle);
|
||||
|
||||
protected:
|
||||
nsString mLabel;
|
||||
|
@ -145,7 +145,7 @@ protected:
|
|||
|
||||
// Mac specific
|
||||
PRInt16 mMacMenuID;
|
||||
NSMenu* mMacMenu; // strong ref, we own it
|
||||
GeckoNSMenu* mMacMenu; // strong ref, we own it
|
||||
MenuDelegate* mMenuDelegate; // strong ref, we keep this around to get events for us
|
||||
NSMenuItem* mNativeMenuItem; // strong ref, we own
|
||||
PRPackedBool mIsEnabled;
|
||||
|
|
|
@ -631,12 +631,12 @@ NS_IMETHODIMP nsMenuX::GetMenuContent(nsIContent ** aMenuContent)
|
|||
}
|
||||
|
||||
|
||||
NSMenu* nsMenuX::CreateMenuWithGeckoString(nsString& menuTitle)
|
||||
GeckoNSMenu* nsMenuX::CreateMenuWithGeckoString(nsString& menuTitle)
|
||||
{
|
||||
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
|
||||
|
||||
NSString* title = [NSString stringWithCharacters:(UniChar*)menuTitle.get() length:menuTitle.Length()];
|
||||
NSMenu* myMenu = [[NSMenu alloc] initWithTitle:title];
|
||||
GeckoNSMenu* myMenu = [[GeckoNSMenu alloc] initWithTitle:title];
|
||||
[myMenu setDelegate:mMenuDelegate];
|
||||
|
||||
// We don't want this menu to auto-enable menu items because then Cocoa
|
||||
|
|
Загрузка…
Ссылка в новой задаче