swift-tests/SwiftTrayDemo/SwiftTrayDemoApp.swift
Gremlin cf2bfc3aa8
Some checks failed
swift-macos-arm64 / swift-macos-arm64 (push) Failing after 11s
feat: add SwiftUI macOS main window demo with CI
2026-03-21 15:50:21 +01:00

169 lines
5.4 KiB
Swift

import SwiftUI
import AppKit
import ObjectiveC
enum WindowCommandCenter {
static func mainWindow() -> NSWindow? {
NSApp.windows.first { $0.identifier?.rawValue == "main-window" } ?? NSApp.windows.first
}
static func resizeMainWindow(width: Double, height: Double) {
guard let window = mainWindow() else { return }
var frame = window.frame
frame.size = NSSize(width: width, height: height)
window.setFrame(frame, display: true, animate: true)
window.makeKeyAndOrderFront(nil)
}
static func centerMainWindow() {
guard let window = mainWindow() else { return }
window.center()
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
}
static func toggleFullScreen() {
guard let window = mainWindow() else { return }
NSApp.activate(ignoringOtherApps: true)
window.toggleFullScreen(nil)
}
static func showMainWindow() {
guard let window = mainWindow() else { return }
NSApp.activate(ignoringOtherApps: true)
window.makeKeyAndOrderFront(nil)
}
}
final class WindowAccessor: NSView {
var onResolve: ((NSWindow) -> Void)?
override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
if let window {
onResolve?(window)
}
}
}
struct MainWindowConfigurator: NSViewRepresentable {
func makeNSView(context: Context) -> NSView {
let view = WindowAccessor()
view.onResolve = { window in
window.identifier = NSUserInterfaceItemIdentifier("main-window")
window.title = "Swift Window Demo"
window.setContentSize(NSSize(width: 980, height: 640))
window.center()
window.styleMask.insert(.resizable)
window.styleMask.insert(.miniaturizable)
window.toolbarStyle = .unified
window.titlebarAppearsTransparent = false
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) {}
}
final class TrayController: NSObject {
private var statusItem: NSStatusItem?
func install() {
let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
item.button?.image = NSImage(systemSymbolName: "menubar.rectangle", accessibilityDescription: "Swift Window Demo")
item.button?.toolTip = "Swift Window Demo"
let menu = NSMenu()
let openItem = NSMenuItem(title: "Open Main Window", action: #selector(MenuActionBox.performAction), keyEquivalent: "o")
openItem.target = MenuActionBox {
WindowCommandCenter.showMainWindow()
}
menu.addItem(openItem)
let centerItem = NSMenuItem(title: "Center Main Window", action: #selector(MenuActionBox.performAction), keyEquivalent: "c")
centerItem.target = MenuActionBox {
WindowCommandCenter.centerMainWindow()
}
menu.addItem(centerItem)
menu.addItem(.separator())
let quitItem = NSMenuItem(title: "Quit", action: #selector(MenuActionBox.performAction), keyEquivalent: "q")
quitItem.target = MenuActionBox {
NSApp.terminate(nil)
}
menu.addItem(quitItem)
objc_setAssociatedObject(openItem, UnsafeRawPointer(bitPattern: 1)!, openItem.target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_setAssociatedObject(centerItem, UnsafeRawPointer(bitPattern: 2)!, centerItem.target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_setAssociatedObject(quitItem, UnsafeRawPointer(bitPattern: 3)!, quitItem.target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
item.menu = menu
statusItem = item
}
}
final class MenuActionBox: NSObject {
private let action: () -> Void
init(action: @escaping () -> Void) {
self.action = action
}
@objc func performAction() {
action()
}
}
final class AppDelegate: NSObject, NSApplicationDelegate {
private let trayController = TrayController()
func applicationDidFinishLaunching(_ notification: Notification) {
trayController.install()
}
}
struct InspectorView: View {
var body: some View {
VStack(alignment: .leading, spacing: 14) {
Text("Utility Window")
.font(.title2.bold())
Text("This secondary scene proves the app supports more than one real macOS window.")
.foregroundStyle(.secondary)
Divider()
Label("Independent scene", systemImage: "macwindow.on.rectangle")
Label("Useful for inspectors, logs, or tools", systemImage: "sidebar.right")
}
.padding(20)
.frame(minWidth: 360, minHeight: 220)
}
}
@main
struct SwiftTrayDemoApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
var body: some Scene {
WindowGroup("Swift Window Demo") {
ContentView()
.background(MainWindowConfigurator())
}
.defaultSize(width: 980, height: 640)
.commands {
CommandGroup(after: .windowArrangement) {
Button("Center Main Window") {
WindowCommandCenter.centerMainWindow()
}
.keyboardShortcut("0")
}
}
Window("Inspector", id: "inspector") {
InspectorView()
}
.defaultSize(width: 360, height: 220)
.windowResizability(.contentSize)
}
}