summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorPatrick Luby <guibmacdev@gmail.com>2024-02-19 15:11:56 -0500
committerAndras Timar <andras.timar@collabora.com>2024-02-21 18:08:10 +0100
commitfeb680acb5dc25d6789289ce52812b11fa69e0c2 (patch)
tree827f92a50ada9ad297d6090b07316c21faef391d /vcl
parentfe35a9b83e7d3cc8a7a59f88a0c8d9eee742697e (diff)
tdf#126638 dispatch key shortcut events to modal windows
Some modal windows, such as the native Open and Save dialogs, return NO from -[NSWindow performKeyEquivalent:]. Fortunately, the main menu's -[NSMenu performKeyEquivalent:] is then called so we can catch and redirect any modal window's key shortcut events without triggering the modal window's "disallowed action" beep. Change-Id: Ib1fff68ab159361ceb847881e3a4da4736a33f51 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163605 Tested-by: Jenkins Reviewed-by: Patrick Luby <guibomacdev@gmail.com> (cherry picked from commit 64ca3756416f0355b2008f39120e68ac42269784) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163618 Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/osx/salnsmenu.h10
-rw-r--r--vcl/osx/salmenu.cxx13
-rw-r--r--vcl/osx/salnsmenu.mm80
-rw-r--r--vcl/osx/vclnsapp.mm49
4 files changed, 111 insertions, 41 deletions
diff --git a/vcl/inc/osx/salnsmenu.h b/vcl/inc/osx/salnsmenu.h
index 696abca2fc0b..9e0f9acf68ed 100644
--- a/vcl/inc/osx/salnsmenu.h
+++ b/vcl/inc/osx/salnsmenu.h
@@ -35,17 +35,25 @@ 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 SalNSMainMenu : NSMenu
+{
+}
+- (BOOL)performKeyEquivalent:(NSEvent*)pEvent;
@end
#endif // INCLUDED_VCL_INC_OSX_SALNSMENU_H
diff --git a/vcl/osx/salmenu.cxx b/vcl/osx/salmenu.cxx
index b3d02587f46b..6ea16a6588ae 100644
--- a/vcl/osx/salmenu.cxx
+++ b/vcl/osx/salmenu.cxx
@@ -125,7 +125,9 @@ static void initAppMenu()
NSMenu* pAppMenu = nil;
NSMenuItem* pNewItem = nil;
- NSMenu* pMainMenu = [[[NSMenu alloc] initWithTitle: @"Main Menu"] autorelease];
+ // Related: tdf#126638 use NSMenu subclass to catch and redirect key
+ // shortcuts when a modal window is displayed
+ SalNSMainMenu* pMainMenu = [[[SalNSMainMenu alloc] initWithTitle: @"Main Menu"] autorelease];
pNewItem = [pMainMenu addItemWithTitle: @"Application"
action: nil
keyEquivalent: @""];
@@ -230,12 +232,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..31627a35ea87 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,25 @@ SAL_WNODEPRECATED_DECLARATIONS_POP
}
@end
+@implementation SalNSMainMenu
+
+- (BOOL)performKeyEquivalent:(NSEvent*)pEvent
+{
+ BOOL bRet = [super performKeyEquivalent: pEvent];
+
+ // tdf#126638 dispatch key shortcut events to modal windows
+ // Some modal windows, such as the native Open and Save dialogs,
+ // return NO from -[NSWindow performKeyEquivalent:]. Fortunately,
+ // the main menu's -[NSMenu performKeyEquivalent:] is then called
+ // so we can catch and redirect any modal window's key shortcut
+ // events without triggering the modal window's "disallowed
+ // action" beep.
+ if( !bRet && [NSApp modalWindow] )
+ bRet = [SalNSMenu dispatchSpecialKeyEquivalents: pEvent];
+
+ return bRet;
+}
+
+@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;