Home > Back-end >  How to open new window on second screen (second display)
How to open new window on second screen (second display)

Time:10-15

The task is simple, but I don't know where to start looking for any pointers on MacOs App development with two displays. I'm building a presenter app where the main app will be displaying on the primary display and with the push of a button I need to push a fullscreen window onto the second display or second monitor. How would I go about doing this? I am using SwiftUI, but am open to other suggestions.

CodePudding user response:

After a bit of tinkering around I came across this solution which I modified to make it work for me. Add the following extension.

extension View {
    private func newWindowInternal(with title: String) -> NSWindow {
        let window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 0, height: 0),
            styleMask: [.closable, .borderless],
            backing: .buffered,
            defer: false)
        
        guard let secondScreen = NSScreen.screens.last else {
            print("Failed to find last display")
            return window
        }
        
        window.setFrame(secondScreen.frame, display: true)
        window.level = NSWindow.Level.screenSaver
        window.isReleasedWhenClosed = false
        window.title = title
        window.orderFront(nil)
        return window
    }
    
    func openNewWindow(with title: String = "new Window") {
        self.newWindowInternal(with: title).contentView = NSHostingView(rootView: self)
    }
}

In your ContentView, add a button which will trigger the activation of the new window. Here's an example ContentView

struct ContentView: View {
    @State private var windowOpened = false
    
    var body: some View {
        VStack {
            Button("Open window") {
                if !windowOpened {
                    ProjectorView(isOpen: $windowOpened).openNewWindow(with: "Projector")
                }
            }
            .keyboardShortcut("o", modifiers: [.option, .command])
            
            Button("Close window") {
                NSApplication.shared.windows.first(where: { $0.title == "Projector" })?.close()
            }
            .keyboardShortcut("w", modifiers: [.option, .command])
        }
        .frame(width: 300, height: 100)
    }
}

Finally, here's what ProjectorView looks like.

struct ProjectorView: View {
    @Binding var isOpen: Bool
    
    var body: some View {
        HStack {
            Spacer()
            VStack {
                Spacer()
                Text("Hello World!")
                    .font(.title2)
                Spacer()
            }
            Spacer()
        }
        .padding()
        .onDisappear {
            isOpen = false
        }
        .onAppear {
            isOpen = true
        }
    }
}

This solution works great. Pressing O will open ProjectorView on the second screen above all other windows and pressing W will close ProjectorView window. Window settings, and window level can be tweaked in the extension.

Tested on macOS Monterey, Xcode 13, Apple M1 MacBook Air.

  • Related