diff options
-rw-r--r-- | vcl/inc/osx/salnsmenu.h | 14 | ||||
-rw-r--r-- | vcl/osx/salmenu.cxx | 14 | ||||
-rw-r--r-- | vcl/osx/salnsmenu.mm | 84 | ||||
-rw-r--r-- | vcl/osx/vclnsapp.mm | 49 |
4 files changed, 121 insertions, 40 deletions
diff --git a/vcl/inc/osx/salnsmenu.h b/vcl/inc/osx/salnsmenu.h index 696abca2fc0b..64b65e2c95bd 100644 --- a/vcl/inc/osx/salnsmenu.h +++ b/vcl/inc/osx/salnsmenu.h @@ -35,17 +35,29 @@ class AquaSalMenuItem; { AquaSalMenu* mpMenu; } ++ (BOOL)dispatchSpecialKeyEquivalents:(NSEvent*)pEvent; - (id)initWithMenu:(AquaSalMenu*)pMenu; - (void)menuNeedsUpdate:(NSMenu*)pMenu; - (void)setSalMenu:(AquaSalMenu*)pMenu; @end -@interface SalNSMenuItem : NSMenuItem +@interface SalNSMenuItem : NSMenuItem <NSMenuItemValidation> { AquaSalMenuItem* mpMenuItem; } - (id)initWithMenuItem:(AquaSalMenuItem*)pMenuItem; - (void)menuItemTriggered:(id)aSender; +- (BOOL)validateMenuItem:(NSMenuItem*)pMenuItem; +@end + +@interface SalNSMainMenuDelegate : NSObject +{ +} +- (id)init; +- (BOOL)menuHasKeyEquivalent:(NSMenu*)pMenu + forEvent:(NSEvent*)pEvent + target:(id*)pTarget + action:(SEL*)pAction; @end #endif // INCLUDED_VCL_INC_OSX_SALNSMENU_H diff --git a/vcl/osx/salmenu.cxx b/vcl/osx/salmenu.cxx index b3d02587f46b..7685a1b9e1bc 100644 --- a/vcl/osx/salmenu.cxx +++ b/vcl/osx/salmenu.cxx @@ -113,6 +113,7 @@ const AquaSalMenu* AquaSalMenu::pCurrentMenuBar = nullptr; // FIXME: currently this is leaked static MainMenuSelector* pMainMenuSelector = nil; +static SalNSMainMenuDelegate* pMainMenuDelegate = nil; static void initAppMenu() { @@ -134,6 +135,10 @@ static void initAppMenu() [NSApp setMainMenu: pMainMenu]; pMainMenuSelector = [[MainMenuSelector alloc] init]; + pMainMenuDelegate = [[SalNSMainMenuDelegate alloc] init]; + + // tdf#126638 set a special delegate for the main menu + [pMainMenu setDelegate: reinterpret_cast< id<NSMenuDelegate> >(pMainMenuDelegate)]; // about NSString* pString = CreateNSString(VclResId(SV_STDTEXT_ABOUT)); @@ -230,12 +235,19 @@ AquaSalMenu::AquaSalMenu( bool bMenuBar ) : { mpMenu = [[SalNSMenu alloc] initWithMenu: this]; [mpMenu setDelegate: reinterpret_cast< id<NSMenuDelegate> >(mpMenu)]; + + // Related: tdf#126638 enable the menu's "autoenabledItems" property + // Enable the menu's "autoenabledItems" property so that + // -[SalNSMenuItem validateMenuItem:] will be called before handling + // a key shortcut and the menu item can be temporarily disabled if a + // modal window is displayed. + [mpMenu setAutoenablesItems: YES]; } else { mpMenu = [NSApp mainMenu]; + [mpMenu setAutoenablesItems: NO]; } - [mpMenu setAutoenablesItems: NO]; } AquaSalMenu::~AquaSalMenu() diff --git a/vcl/osx/salnsmenu.mm b/vcl/osx/salnsmenu.mm index b2df2da7e5f5..0659e412db1a 100644 --- a/vcl/osx/salnsmenu.mm +++ b/vcl/osx/salnsmenu.mm @@ -30,6 +30,53 @@ #include <osx/salnsmenu.h> @implementation SalNSMenu + ++(BOOL)dispatchSpecialKeyEquivalents: (NSEvent*)pEvent +{ + if( pEvent && [pEvent type] == NSEventTypeKeyDown ) + { + unsigned int nModMask = ([pEvent modifierFlags] & (NSEventModifierFlagShift|NSEventModifierFlagControl|NSEventModifierFlagOption|NSEventModifierFlagCommand)); + if( nModMask == NSEventModifierFlagCommand ) + { + if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"v"] ) + { + if( [NSApp sendAction: @selector(paste:) to: nil from: nil] ) + return YES; + } + else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"c"] ) + { + if( [NSApp sendAction: @selector(copy:) to: nil from: nil] ) + return YES; + } + else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"x"] ) + { + if( [NSApp sendAction: @selector(cut:) to: nil from: nil] ) + return YES; + } + else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"a"] ) + { + if( [NSApp sendAction: @selector(selectAll:) to: nil from: nil] ) + return YES; + } + else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"z"] ) + { + if( [NSApp sendAction: @selector(undo:) to: nil from: nil] ) + return YES; + } + } + else if( nModMask == (NSEventModifierFlagCommand|NSEventModifierFlagShift) ) + { + if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"Z"] ) + { + if( [NSApp sendAction: @selector(redo:) to: nil from: nil] ) + return YES; + } + } + } + + return NO; +} + -(id)initWithMenu: (AquaSalMenu*)pMenu { mpMenu = pMenu; @@ -167,6 +214,19 @@ OSL_FAIL( "menubar item without frame !" ); } } + +-(BOOL)validateMenuItem: (NSMenuItem *)pMenuItem +{ + // Related: tdf#126638 disable all menu items when displaying modal windows + // For some unknown reason, key shortcuts are dispatched to the LibreOffice + // menu items instead of the modal window so disable all LibreOffice menu + // items while a native modal dialog such as the native Open, Save, or + // Print dialog is displayed. + if (!pMenuItem || [NSApp modalWindow]) + return NO; + + return [pMenuItem isEnabled]; +} @end @implementation OOStatusItemView @@ -257,5 +317,29 @@ SAL_WNODEPRECATED_DECLARATIONS_POP } @end +@implementation SalNSMainMenuDelegate + +-(id)init +{ + return [super init]; +} + +-(BOOL)menuHasKeyEquivalent: (NSMenu*)pMenu forEvent: (NSEvent*)pEvent target: (id*)pTarget action: (SEL*)pAction +{ + assert( pMenu == [NSApp mainMenu] ); + + // tdf#126638 dispatch key shortcut events to modal windows + // Some modal windows, such as the native Open and Save dialogs, + // ignore any key shortcut events so use the same existing special + // dispatching code that -[VCL_NSApplication sendEvent:] uses to + // dispatch key shortcuts to non-modal, non-LibreOffice windows. + if( [NSApp modalWindow] ) + [SalNSMenu dispatchSpecialKeyEquivalents: pEvent]; + + // Always return NO since the target and action are not set + return NO; +} + +@end /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/osx/vclnsapp.mm b/vcl/osx/vclnsapp.mm index 5daf923ce105..cd60cb0b0cec 100644 --- a/vcl/osx/vclnsapp.mm +++ b/vcl/osx/vclnsapp.mm @@ -34,6 +34,7 @@ #include <osx/salframe.h> #include <osx/salframeview.h> #include <osx/salinst.h> +#include <osx/salnsmenu.h> #include <osx/vclnsapp.h> #include <quartz/utils.h> @@ -170,44 +171,8 @@ // precondition: this ONLY works because CMD-V (paste), CMD-C (copy) and CMD-X (cut) are // NOT localized, that is the same in all locales. Should this be // different in any locale, this hack will fail. - unsigned int nModMask = ([pEvent modifierFlags] & (NSEventModifierFlagShift|NSEventModifierFlagControl|NSEventModifierFlagOption|NSEventModifierFlagCommand)); - if( nModMask == NSEventModifierFlagCommand ) - { - - if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"v"] ) - { - if( [NSApp sendAction: @selector(paste:) to: nil from: nil] ) - return; - } - else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"c"] ) - { - if( [NSApp sendAction: @selector(copy:) to: nil from: nil] ) - return; - } - else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"x"] ) - { - if( [NSApp sendAction: @selector(cut:) to: nil from: nil] ) - return; - } - else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"a"] ) - { - if( [NSApp sendAction: @selector(selectAll:) to: nil from: nil] ) - return; - } - else if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"z"] ) - { - if( [NSApp sendAction: @selector(undo:) to: nil from: nil] ) - return; - } - } - else if( nModMask == (NSEventModifierFlagCommand|NSEventModifierFlagShift) ) - { - if( [[pEvent charactersIgnoringModifiers] isEqualToString: @"Z"] ) - { - if( [NSApp sendAction: @selector(redo:) to: nil from: nil] ) - return; - } - } + if( [SalNSMenu dispatchSpecialKeyEquivalents:pEvent] ) + return; } } [super sendEvent: pEvent]; @@ -315,6 +280,14 @@ -(NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *) app { (void)app; + + // Related: tdf#126638 disable all menu items when displaying modal windows + // Although -[SalNSMenuItem validateMenuItem:] disables almost all menu + // items when a modal window is displayed, the standard Quit menu item + // does not get disabled so disable it here. + if ([NSApp modalWindow]) + return NSTerminateCancel; + NSApplicationTerminateReply aReply = NSTerminateNow; { SolarMutexGuard aGuard; |