NSMenuItem's not selectable after opening window - objective-c

I'm having an issue very similar to this thread.
I am programatically creating a NSMenu and adding my items. One selection of an item it shows a window. This works as intended. However, when I close the window I can no longer select any of the options in the menu.
AppDelegate.m
- (void)createMenu {
NSMenu *statusMenu = [[NSMenu alloc] initWithTitle:#""];
NSMenuItem *historyItem = [[NSMenuItem alloc] initWithTitle:#"History" action:#selector(onHistory:) keyEquivalent:#""];
[statusMenu addItem:historyItem];
NSImage *statusImage = [NSImage imageNamed:#"icon.png"];
[_item setImage:statusImage];
[_item setMenu:statusMenu];
}
- (void)onHistory:(id)sender {
OBHistoryWindowController *historyWindowController = [[OBHistoryWindowController alloc] initWithWindowNibName:#"OBHistoryWindowController"];
historyWindowController.managedContext = self.managedObjectContext;
[historyWindowController showWindow];
}
OBHistoryWindowController.m
- (void)showWindow {
[NSApp runModalForWindow:self.window];
}
I'm guessing I need to somehow on close of the window give focus back to the menu but I can't for the life of me figure out how.

It sounds like you haven't stopped the modal loop. As the docs for runModalForWindow: say, "You can exit the modal loop by calling the stopModal, stopModalWithCode:, or abortModal methods from your modal window code."

Related

NSMenu with views in a modal NSWindow

I have an issue with selectors not being performed for custom views inside an NSMenuItem when they are displayed from a button within a modal NSWindow.
This appears to be a reproducible issue and I've simplified the issue as much as I can.
Modal window is displayed via.
[NSApp runModalForWindow:_modalWindow];
The modal window only has a button, and the button is attached to the following selector.
- (IBAction)modalButtonClicked:(id)sender
{
NSMenu* aMenu = [[NSMenu alloc] initWithTitle:#"Menu"];
NSMenuItem* aItemA = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
NSMenuItem* aItemB = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
NSMenuItem* aItemC = [[NSMenuItem alloc] initWithTitle:#"" action:nil keyEquivalent:#""];
[aItemA setView:[NSButton buttonWithTitle:#"Item A" target:self action:#selector(menuButtonClicked:)]];
[aItemB setView:[NSButton buttonWithTitle:#"Item B" target:self action:#selector(menuButtonClicked:)]];
[aItemC setView:[NSButton buttonWithTitle:#"Item C" target:self action:#selector(menuButtonClicked:)]];
[aMenu addItem:aItemA];
[aMenu addItem:aItemB];
[aMenu addItem:aItemC];
[NSMenu popUpContextMenu:aMenu withEvent:[NSApp currentEvent] forView:sender];
}
and the menu click event with a breakpoint:
- (void)menuButtonClicked:(id)sender
{
NSLog(#"%#", sender);
}
Clicking on the button will display a menu with 3 buttons, however nothing happens when you click any of those buttons. #(menuButtonClicked:) is never called. This is only an issue with modal windows but there's no obvious reason why.
The documention https://developer.apple.com/documentation/appkit/nsmenuitem/1514843-target?language=objc states:
To ensure that a menu item’s target can receive commands while a modal
dialog is open, the target object should return YES in worksWhenModal.
And indeed if one adds:
- (BOOL)worksWhenModal {
return YES;
}
then it works and your method menuButtonClicked gives out something like:
2019-10-03 22:47:27.892005+0200 MenuTest[12876:454071] <NSButton: 0x600003505760>

NSMenuItem with custom view dose not respond after leaving application

My application resides in the status bar. When the application first starts my search field responds fine, and allows me to click and enter text and look like this.
But after clicking out of the application into another application like "xcode" and back into my menu the search field and the rest of the custom view appears dim and does not respond unless I click multiple times.
In my applicationDidFinishLaunching I set up the statusItem and the NSMenuItem with the custom view.
//set up hotkeys
[self registerHotKeys];
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
NSImage *menuIcon = [NSImage imageNamed:#"Menu Icon"];
NSImage *highlightIcon = [NSImage imageNamed:#"Menu Icon"];
[highlightIcon setTemplate:YES];
[[self statusItem] setImage:menuIcon];
[[self statusItem] setAlternateImage:highlightIcon];
[[self statusItem] setMenu:[self menu]];
[[self statusItem] setHighlightMode:YES];
// search menu item
NSMenuItem *searchMenuItem = [[NSMenuItem alloc] initWithTitle:#"search" action:nil keyEquivalent:#""];
self.searchMenuItemView = [[SearchMenuItemView alloc] initWithNibName:#"SearchMenuItemView" bundle:nil];
self.searchMenuItemView.delegate = self;
[searchMenuItem setView:self.searchMenuItemView.view];
[searchMenuItem setTarget:self];
[searchMenuItem setEnabled:YES];
[_menu insertItem:searchMenuItem atIndex:0];
The view is coming from an UIViewController, but I have tried setting the view from just an NSView with no luck using "this" from someone with a similar issue but this did not solve mine. Auto enable is on.
Is there a way to bring the NSMenuItem back to the state it was in when the application is first lunched?

Why is this NSMenuItem getting disabled when the window loses focus?

I am programmatically creating an NSMenu with a NSMenuItem. When the window of the application is active, the NSMenuItem is enabled:
However, as soon as the window loses focus the menu item becomes disabled:
Here's how I am creating the NSMenu:
- (void)_quit
{
[[NSApplication sharedApplication] terminate:nil];
}
- (NSMenu *)_setupMenu
{
NSMenu *statusMenu = [[NSMenu alloc] initWithTitle:#"Demo"];
NSMenuItem *quit = [[NSMenuItem alloc] initWithTitle:#"Quit" action:#selector(_quit) keyEquivalent:#""];
[statusMenu addItem:quit];
return statusMenu;
}
What is causing this issue? And how do I go about making it enabled regardless of whether the application is in focus or not?
Because menu items are enabled based on the responder chain.
In your case, you can use the terminate: selector instead of your own.
As this is declared in the NSApplication class, which is also part of the responder chain, the item will then be always active.
NSMenuItem *quit = [[NSMenuItem alloc] initWithTitle:#"Quit" action:#selector(terminate:) keyEquivalent:#""];
More on this here: Cocoa Event Handling Guide

Custom view in NSMenuItem disables the NSPopUpButton selection

I want to customize an an NSPopUpButton so I have implemented an CustomMenuItemView which right now only has the following code (for testing purposes):
- (void)drawRect:(NSRect)dirtyRect
{
[[NSColor redColor] set];
NSRectFill(dirtyRect);
}
Now, for every NSMenuItem i add to the NSMenu in myPopUpButton.menu I set the view to my custom view:
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:#"Some title" action:NULL keyEquivalent:#""];
menuItem.view = [[CustomMenuItemView alloc] initWithFrame:NSMakeRect(0, 0, 100, 25)];
When I run my program and open the popup button the menuitem selection seems disabled (i.e. nothing happens when I click on it).
I am guessing that it is not actually disabled; it just doesn't respond to events anymore. Do I need to add some event handling in my custom view? If so, how?
I solved the problem by adding the mouseUp method to my CustomMenuItemView:
- (void)mouseUp:(NSEvent*) event
{
NSMenu *menu = self.enclosingMenuItem.menu;
[menu cancelTracking];
[menu performActionForItemAtIndex:[menu indexOfItem:self.enclosingMenuItem]];
}

Create NSMenu for NSStatusBar.systemStatusBar programmatically

I'm trying to create a simple menu in the System Status Bar using code only. I'm not receiving any compilation or runtime errors but I see no effect at all.
- (void)awakeFromNib
{
NSMenu *stackMenu = [[NSMenu alloc] initWithTitle:#"Status Menu"];
NSMenuItem *soMenuItem =
[[NSMenuItem alloc] initWithTitle:#"Status Menu Item" action:nil keyEquivalent:#"S"];
[soMenuItem setEnabled:YES];
[stackMenu addItem:soMenuItem];
statusItem = [[[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength]
retain];
[statusItem setMenu:stackMenu];
}
I don't believe the NSStatusItem will implicitly take on the title of the NSMenu associated with it (which is what I am guessing you want to happen.) Try explicitly setting the NSStatusItem's title (and/or its image).
e.x.
[statusItem setTitle:[stackMenu title]];