How do I make a Menu Bar (NSPopover) App active when clicking on the menu button?
Asked Answered
F

3

8

I have an app that sits in the menu bar, and when you click on the button it presents an NSPopover.

That all works fine, but I want an NSSearchField to become the first responder, so a user can then type straight in the box.

However, if the app was not already selected, it won't work. And although it looks like the search box is active, the keyboard input goes to the previous app that was open, because technically it is still the active window.

I've seen a few questions about things like this, but they all require objc methods like makekeyandorder, or just stuff that won't apply to an NSPopover.

So my question is - Is there a way that when the button is pressed, I can then force the application to become the active app?

I had a wild guess and tried NSApplication().sharedApplication().becomeFirstResponder(), but no luck.

If there's another way to do it, that I've just missed completely, then please let me know!

Firelock answered 15/6, 2016 at 23:28 Comment(4)
Hi, can you add a screenshot?Alroi
One better, here's a video - f.cl.ly/items/3L152r3F442G2L1P0y3w/Qwiki%20Bug.mov As you can see, when I first click the menu button, the app wasn't previously active, so the field doesn't become first responder. But after I click on the popover, when I close and open it, the search field can become first responder fine.Firelock
I knew it was a stupid question.Firelock
@ChristopherHannah not a stupid question at all.Ratline
F
14

I fixed it myself in the end, it turned out to be a very simple fix as expected.

All I needed to to was call NSApplication.sharedApplication().activateIgnoringOtherApps(true) in the ViewControllers viewDidAppear() method.

It fixes everything!

Firelock answered 16/6, 2016 at 23:8 Comment(5)
interestingly enough, it fails to work when i build and try using xcode 8. it seems fine when other apps have the focus. go figure...Coronary
Thanks! Works great. In Swift 4 the syntax has changed slightly: NSApplication.shared.activate(ignoringOtherApps: true)Corum
I wonder how Dropbox app does the similar thing but without activating the app. When I move mouse over the Dropbox icons in the Popover, the tooltips get displayed. However, in my own app, without activation it no tooltip pops up :(Invocation
@PavelLobodinský Did you find a solution for the thing you describe? I'm looking for the same behavior.Fabri
@MartinMihaylov No, I didn't :( Instead I designed my app's icons in a way they are understandable without any tooltips. But my humble guess is that they use a custom-made window.Invocation
P
5

Even though @Christopher_Hannah answer works, the documentation clearly says,

You don’t need to send this message to make one of the app’s NSWindows key. When you send a makeKey() message to an NSWindow object, you ensure that it is the key window when the app is active.

So assuming we're in a view controller, all you need to do is

override func viewDidAppear() {
    super.viewDidAppear()

    view.window?.makeKey()
}
Pastose answered 15/3, 2020 at 7:2 Comment(1)
This, rather than activateIgnoringOtherApps(true) works on modern macOS (Monterey and Ventura). The other, older approach does not.Kavita
P
0
final class HostingView<Content: View>: NSHostingView<Content> {
override func viewDidMoveToWindow() {
    window?.becomeKey()
}

}

And then use like so:

let item = NSMenuItem()
let contentView = ContentView()
let hv = HostingView(rootView: contentView)
hv.frame = NSRect(x: 0, y: 0, width: 500, height: 500)
item.view = hv

let menu = NSMenu()
menu.items = [item]
Pave answered 25/5, 2022 at 14:41 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Breathing

© 2022 - 2024 — McMap. All rights reserved.