Jack
Jack

Reputation: 1076

Menu access from NSStatusItem (Menu Bar) Application in Swift

I'm creating an application where a menubar seems to be the most convenient way to have the user's desktop clean without a window. I've seen many tutorials online and on stack overflow but they seem to be only for Objective-C. I only use Swift. If you don't know what a menubar is, they're these icons:

enter image description here

I would like my app to have one of these instead of a constant full window. And if I can, how can I have a button on my menubar that brings up the window. Lastly, how can I have my icon not show, but I still have the finder advantages. (Like File, Edit..). For example,

enter image description here

I have already tried to put

Application is Agent (UIElement) to False

in my Info.plist but that also takes away my finder advantages.

Upvotes: 0

Views: 4204

Answers (1)

rob mayoff
rob mayoff

Reputation: 385890

Presumably what you're saying is that you want the text editing items (like Undo, Cut, Copy, Paste, Select All) from the Edit menu to work in your app's window.

Those menu items are part of another application, and only send messages in that application. They aren't available to your application, regardless of whether it's an “agent” (with no visible menu bar of its own). If one of your agent app's windows is the key window and the user clicks on a menu title (like File or Edit) that belongs to another app, then that app will activate and your app's window will “resign” the key window status.

You can make the usual shortcut keys (like ⌘X for Cut) work for your app, and it's easy. When one of your app's windows is the user's key window, your app receives keyboard events, and your NSApplication object (created for you automatically) will check its mainMenu for keyboard shortcuts even though the main menu is not displayed on the screen.

The OS X “Cocoa Application” project template sets up a main menu bar for you in MainMenu.xib (or in Main.storyboard), with all of the menu items wired up to the appropriate actions. So if you keep that main menu bar and the Edit menu and the menu items in the Edit menu and leave the shortcuts set on those items, then the keyboard shortcuts will work even if you set LSUIElement to YES in your Info.plist, when one of your app's windows is the key window. In other words, the shortcut keys will work by default, and you have to change things to make them stop working.

Text fields in your app's windows will also still get the default right-click menu with the usual items like Cut, Copy, and Paste, so you don't need to do anything else to make that work either.

Here's the contents of my test app's MainMenu.xib:

MainMenu.xib

I've left the main menu bar alone. I've created a separate menu with two items, “Show Window” and “Quit”. I've set the shortcut for “Quit” to ⌘Q, but this shortcut has no effect. The StatusItem > Quit menu item (not visible in my screen shot) off the main menu bar has the same shortcut set, and that's the setting that matters. I've set the shortcut on this other Quit item because it's visible to the user, and the main menu bar won't be visible to the user.

I've wired this Quit item to the terminate: action of First Responder. (The StatusItem > Quit menu item is connected the same way by default.)

Here's my AppDelegate:

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet var window: NSWindow!
    @IBOutlet var statusItemMenu: NSMenu!

    var statusItem: NSStatusItem?

    func applicationDidFinishLaunching(aNotification: NSNotification) {
        self.statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
        let statusItem = self.statusItem!
        let button = statusItem.button!
        button.title = "Hello"
        statusItem.menu = statusItemMenu
    }

    @IBAction func showWindow(sender: AnyObject) {
        NSApp.activateIgnoringOtherApps(true)
        window.makeKeyAndOrderFront(sender)
    }

}

I've wired the “Show Window” menu item to the showWindow(_:) action, and I've connected the statusItemMenu outlet to that standalone menu in the XIB.

I also set “Application is Agent (UIElement)” to “YES” in Info.plist.

When I run this app, it creates the status item in the menu bar. I can choose “Show Window” from the item and my window comes to the front and becomes key. I can right-click the text field to get its context menu. I can use the standard shortcuts to cut/copy/paste/etc., to close the window, and even to quit the app.

Upvotes: 8

Related Questions