Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/MacVim/MMCoreTextView.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
NSTextInput
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
, NSFontChanging
, NSMenuItemValidation
#endif
>
{
Expand Down Expand Up @@ -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
//
Expand Down
17 changes: 17 additions & 0 deletions src/MacVim/MMCoreTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,23 @@ - (void)changeFont:(id)sender
}
}

/// 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
Expand Down
5 changes: 5 additions & 0 deletions src/MacVim/MMFullScreenWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 6 additions & 3 deletions src/MacVim/MMFullScreenWindow.m
Original file line number Diff line number Diff line change
Expand Up @@ -444,13 +444,16 @@ - (void)performClose:(id)sender
[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
Expand Down
2 changes: 1 addition & 1 deletion src/MacVim/MMTextView.m
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ - (BOOL)validateMenuItem:(NSMenuItem *)item
|| [item action] == @selector(selectAll:))
return [item tag];

return YES;
return [super validateMenuItem:item];
}

@end // MMTextView
Expand Down
13 changes: 9 additions & 4 deletions src/MacVim/MMVimController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1447,10 +1447,15 @@ - (void)enableMenuItemWithDescriptor:(NSArray *)desc state:(BOOL)on
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];
Expand Down
4 changes: 4 additions & 0 deletions src/MacVim/MMWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
10 changes: 7 additions & 3 deletions src/MacVim/MMWindow.m
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,17 @@ - (void)performClose:(id)sender
[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
Expand Down
13 changes: 12 additions & 1 deletion src/MacVim/MMWindowController.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 4 additions & 5 deletions src/MacVim/MMWindowController.m
Original file line number Diff line number Diff line change
Expand Up @@ -1181,11 +1181,10 @@ - (IBAction)findAndReplace:(id)sender

- (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 ------------------------------------------------------
Expand Down