3

When I trigger a modal window on macOS through a Button that has a ButtonStyle, a Button in that modal that also has a ButtonStyle doesn't register the click until after the modal window is closed. Buttons without styles work fine regardless.

This seems like a SwiftUI bug to me or am I missing something here? I'd like to use NSApp.runModal as it seems to be the only way to block the main window while the modal is open. Example code below video.

enter image description here

Opening modal window based on this code: https://github.com/onmyway133/blog/issues/768

struct ContentView: View {
    
    var modalWindowContent: some View {
        VStack {
            Button("Regular Button") {
                print("Regular Button Pressed")
            }
            Button("Plain Button") {
                print("Plain Button Pressed")
            }
            .buttonStyle(.plain)
        }
        .frame(width: 200, height: 100)
    }
    
    var body: some View {
        Group {
            Button("Open Modal Window") {
                openModalWindow()
            }
            Button("Open Modal Window") {
                openModalWindow()
            }
            .buttonStyle(.plain)
        }
        .frame(width: 300, height: 200)
    }
    
    func openModalWindow() {
        let window = ModalWindow(
            contentRect: .zero,
            styleMask: [.titled, .closable, .resizable],
            backing: .buffered,
            defer: false
        )
        window.titlebarAppearsTransparent = true
        window.title = "Title"
        window.center()
        window.isReleasedWhenClosed = false
        let view = modalWindowContent
        let hosting = NSHostingView(rootView: view)
        window.contentView = hosting
        hosting.autoresizingMask = [.width, .height]
        NSApp.runModal(for: window)
    }
}

final class ModalWindow: NSWindow {
    override func becomeKey() {
        super.becomeKey()
        level = .statusBar
    }
    
    override func close() {
        super.close()
        NSApp.stopModal()
    }
}
2
  • Maybe a bug maybe not... Apple knows. Apple does not recommend to use (read "don't use") modal mode for a long time, so who knows what's inside that plain button. Try something else, custom button style, tap gesture, etc. What's the goal? Commented Jul 12, 2022 at 11:37
  • 1
    Ended up using .sheet instead. While the solution below works for the button style, other code that worked flawlessly elsewhere breaks within the modal window. So yeah, staying away from it is probably the way to go. Commented Jul 16, 2022 at 13:15

1 Answer 1

6

Here's the solution that hopefully saves others from spending hours on this like I did. For whatever reason the action of the button opening the window needs to be explicitly dispatched on the main thread:

Button("Open Modal Window") {
    DispatchQueue.main.async {
        openModalWindow()
    }
}
.buttonStyle(.plain)
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.