SwiftUI Mac menu command to create a single instance of a window?

43 Views Asked by At

I found that if I define a Window struct in my SwiftUI applications App struct, it creates a window that I can then open from a menu command with an environment variable.

However, the system opens the window at launch. What I want is a singe-instance of an info window that is ideally created lazily from a menu command, destroyed on close, and recreated the next time it the menu command is invoked. (I'm going to use it to display log information about the processing the app does.)

Failing that, I'd like the window to be created hidden, and then un-hidden with a menu command.

How would I do that? If I add .hidden to the window, it is hidden forever.

2

There are 2 best solutions below

1
Joakim Danielson On BEST ANSWER

Unless I misunderstood something you can use Window to have a window that you open separately, add it to the body in main but outside the any WindowGroup

var body: some Scene {
    WindowGroup {
        ContentView()
    }

    Window("Info Window",id: "info-window") {
        InfoWindowView()
    }
    .keyboardShortcut(KeyEquivalent("i"), modifiers: [.command, .shift])
}

This window can then be opened from the Window menu, Window -> Info Window or with the keyboard shortcut Cmd-Shift-I

7
Sweeper On

If your app has a MenuBarExtra, move it to the very start of var body: some Scene { ... }. If the MenuBarExtra is the first Scene, the Window/WindowGroup scene will not appear on launch.

@main
struct FooApp: App {
    @Environment(\.openWindow) var open
    var body: some Scene {
        MenuBarExtra("Extra Menu") {
            // ...
        }
        
        WindowGroup(id: "ID") {
            ContentView()
        }
        .commands {
            CommandMenu("Foo") {
                Button("Open Window") {
                    open(id: "ID")
                }
            }
        }
    }
}

If you don't want/need a MenuBarExtra, you can do:

MenuBarExtra("") { }

which makes it practically invisible.

That said, if I launch an app, I would expect to see a window popping up, or a new menu bar extra in the menu bar. Launching an app and then nothing happens except the app name on the top left changing is a bit weird.