Fix menu items like Edit.Cut/Copy not disabled in normal mode

We are using auto-enabling of menu items, which require each target of
macaction to implement validateMenuItem properly. It was done in
MMTextView, but not MMCoreTextView. Also, as part of fixing this up,
just add more comments, and make sure to call back to superclass etc to
make the code more robust.
This commit is contained in:
Yee Cheng Chin
2022-10-06 18:27:11 -07:00
parent 2fbd8bf2ce
commit 08a85b2b2b
10 changed files with 82 additions and 17 deletions
+17
View File
@@ -17,6 +17,7 @@
NSTextInput
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
, NSFontChanging
, NSMenuItemValidation
#endif
>
{
@@ -62,6 +63,22 @@
//
- (void)changeFont:(id)sender;
//
// NSMenuItemValidation
//
- (BOOL)validateMenuItem:(NSMenuItem *)item;
//
// Public macaction's
// Note: New items here need to be handled in validateMenuItem: as well.
//
- (IBAction)cut:(id)sender;
- (IBAction)copy:(id)sender;
- (IBAction)paste:(id)sender;
- (IBAction)undo:(id)sender;
- (IBAction)redo:(id)sender;
- (IBAction)selectAll:(id)sender;
//
// MMTextStorage methods
//
+17
View File
@@ -1140,6 +1140,23 @@ static void grid_free(Grid *grid) {
}
}
/// Specifies whether the menu item should be enabled/disabled.
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if ([item action] == @selector(cut:)
|| [item action] == @selector(copy:)
|| [item action] == @selector(paste:)
|| [item action] == @selector(undo:)
|| [item action] == @selector(redo:)
|| [item action] == @selector(selectAll:))
return [item tag];
// This class should not have any special macOS menu itmes, so theoretically
// all of them should just return item.tag, but just in case macOS decides
// to inject some menu items to the parent NSView class without us knowing,
// we let the superclass handle this.
return YES;
}
//
// NOTE: The menu items cut/copy/paste/undo/redo/select all/... must be bound
+5
View File
@@ -47,4 +47,9 @@
- (BOOL)canBecomeMainWindow;
- (void)applicationDidChangeScreenParameters:(NSNotification *)notification;
// Public macaction's.
// Note: New items here need to be handled in validateMenuItem: as well.
- (void)performClose:(id)sender;
@end
+6 -3
View File
@@ -444,13 +444,16 @@ enum {
[super performClose:sender];
}
/// Validates whether the menu item should be enabled or not.
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if ([item action] == @selector(vimMenuItemAction:)
|| [item action] == @selector(performClose:))
// This class only really have one action that's bound from Vim
if ([item action] == @selector(performClose:))
return [item tag];
return YES;
// Since this is a subclass of NSWindow, it has a bunch of auto-populated
// menu from the OS. Just pass it off to the superclass to let it handle it.
return [super validateMenuItem:item];
}
@end // MMFullScreenWindow
+1 -1
View File
@@ -906,7 +906,7 @@
|| [item action] == @selector(selectAll:))
return [item tag];
return YES;
return [super validateMenuItem:item];
}
@end // MMTextView
+9 -4
View File
@@ -1447,10 +1447,15 @@ static BOOL isUnsafeMessage(int msgid);
return;
}
// Use tag to set whether item is enabled or disabled instead of
// calling setEnabled:. This way the menus can autoenable themselves
// but at the same time Vim can set if a menu is enabled whenever it
// wants to.
// We are using auto-enabling of menu items, where instead of directly
// calling setEnabled:, we rely on validateMenuItem: callbacks in each
// target to handle whether they want each menu item to be enabled or not.
// This allows us to more easily control the enabled states of OS-injected
// menu items if we want to. To remember whether we want to enable/disable
// a Vim menu, we use item.tag to remember it. See each validateMenuItem:
// implementation for details.
//
// See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MenuList/Articles/EnablingMenuItems.html
[[self menuItemForDescriptor:desc] setTag:on];
const BOOL isPopup = [MMVimController hasPopupPrefix:rootName];
+4
View File
@@ -33,4 +33,8 @@
- (IBAction)toggleFullScreen:(id)sender;
- (IBAction)realToggleFullScreen:(id)sender;
// Public macaction's.
// Note: New items here need to be handled in validateMenuItem: as well.
- (void)performClose:(id)sender;
@end
+7 -3
View File
@@ -184,13 +184,17 @@ static CGSSetWindowBackgroundBlurRadiusFunction* GetCGSSetWindowBackgroundBlurRa
[super performClose:sender];
}
/// Validates whether the menu item should be enabled or not.
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if ([item action] == @selector(vimMenuItemAction:)
|| [item action] == @selector(performClose:))
// This class only really have one action that's bound from Vim
if ([item action] == @selector(performClose:)) {
return [item tag];
}
return YES;
// Since this is a subclass of NSWindow, it has a bunch of auto-populated
// menu from the OS. Just pass it off to the superclass to let it handle it.
return [super validateMenuItem:item];
}
- (IBAction)zoom:(id)sender
+12 -1
View File
@@ -17,7 +17,12 @@
@class MMVimController;
@class MMVimView;
@interface MMWindowController : NSWindowController<NSWindowDelegate>
@interface MMWindowController : NSWindowController<
NSWindowDelegate
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
, NSMenuItemValidation
#endif
>
{
MMVimController *vimController;
MMVimView *vimView;
@@ -104,6 +109,12 @@
- (BOOL)getDefaultTopLeft:(NSPoint*)pt;
- (void)runAfterWindowPresentedUsingBlock:(void (^)(void))block;
//
// NSMenuItemValidation
//
- (BOOL)validateMenuItem:(NSMenuItem *)item;
// Menu items / macactions
- (IBAction)addNewTab:(id)sender;
- (IBAction)toggleToolbar:(id)sender;
- (IBAction)performClose:(id)sender;
+4 -5
View File
@@ -1181,11 +1181,10 @@
- (BOOL)validateMenuItem:(NSMenuItem *)item
{
if ([item action] == @selector(vimMenuItemAction:)
|| [item action] == @selector(performClose:))
return [item tag];
return YES;
// This class is a responsder class and this should get called when we have
// a specific action that we implement exposed as a menu. As such just return
// [item tag] and no need to worry about macOS-injected menus.
return [item tag];
}
// -- NSWindow delegate ------------------------------------------------------