22 September 2024

Hide macOS window controls using SwiftUI

2 minute read

For certain macOS applications, you might want to hide the macOS window controls, commonly called ‘traffic light buttons’. These are the close, minimize and maximize buttons that appear on the top-left of most macOS applications.

To solve this problem, we will do the following:

  • Track when the application has opened and become the key window.
  • Identify the window that will have it’s windows controls hidden.
  • Hide the window controls

To track when the application has opened and become the key window, we can make use of SwiftUI’s View.onReceive() function. It allow us to add an action to perform when this view detects data emitted by a given publisher. A publisher is any object that implements the Publisher protocol which imparts that object the power to transmit a sequence of values over time to some subscriber.

We can use the NotificationCenter.default.publisher to emit a notification when a Window has become the key window and run some action.

@main
struct hide_window_controlsApp: App {
    var body: some Scene {
        WindowGroup("SwiftUI") {
            ContentView().onReceive(NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification)) { _ in
                
            }
        }
    }
}

The next step involves identifying which window within our app will have it’s window controls removed. We can use NSApplication.shared.windows to return a list of windows associated with our application and filter based on a given identifier. In our case, we filter based on the title we provide our apps WindowGroup or Window and return the given window. If a window with that title does not exist for our app, we return an error instead.

func getWindowByTitle(title: String) -> NSWindow? {
    guard let window = NSApplication.shared.windows.first(where: { $0.title == title }) else {
        fatalError("Window with title '\(title)' not found.")
    }
    return window
}

Now that we can identify the target window by it’s title, we can remove the window controls.

For this, macOS allows us to modify an NSWindow window controls using the NSWindow.standardWindowButton API like such: window.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true.

To hide all the window controls for a specific window, we implement the following function:

func hideWindowControls(for window: NSWindow) {
    window.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true
    window.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)?.isHidden = true
    window.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true
}

Now,we pass our action into our .onReceive function to find the window by it’s title and hide the window controls for said window:

if let window = getWindowByTitle(title: "SwiftUI") {
    hideWindowControls(for: window)
}

This will lead us to this complete solution:

import SwiftUI

func hideWindowControls(for window: NSWindow) {
    window.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true
    window.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)?.isHidden = true
    window.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true
}

func getWindowByTitle(title: String) -> NSWindow? {
    guard let window = NSApplication.shared.windows.first(where: { $0.title == title }) else {
        fatalError("Window with title '\(title)' not found.")
    }
    return window
}

@main
struct hide_window_controlsApp: App {
    var body: some Scene {
        WindowGroup("SwiftUI") {
            ContentView().onReceive(NotificationCenter.default.publisher(for: NSWindow.didBecomeKeyNotification)) { _ in
                if let window = getWindowByTitle(title: "SwiftUI") {
                    hideWindowControls(for: window)
                }
            }
        }
    }
}

For updates about the blog and software development tips, follow me on X @0xFFA4.