All checks were successful
swift-macos-arm64 / swift-macos-arm64 (push) Successful in 11s
201 lines
6.4 KiB
Swift
201 lines
6.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)
|
|
NSApp.activate(ignoringOtherApps: 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)
|
|
}
|
|
|
|
static func renameMainWindow(to title: String) {
|
|
guard let window = mainWindow() else { return }
|
|
window.title = title
|
|
}
|
|
|
|
static func setMainWindowAlpha(_ value: Double) {
|
|
guard let window = mainWindow() else { return }
|
|
window.alphaValue = CGFloat(value)
|
|
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 MenuActionBox: NSObject {
|
|
private let action: () -> Void
|
|
|
|
init(action: @escaping () -> Void) {
|
|
self.action = action
|
|
}
|
|
|
|
@objc func performAction() {
|
|
action()
|
|
}
|
|
}
|
|
|
|
final class TrayController: NSObject {
|
|
private var statusItem: NSStatusItem?
|
|
private var retainedTargets: [MenuActionBox] = []
|
|
|
|
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()
|
|
menu.autoenablesItems = false
|
|
|
|
let openTarget = MenuActionBox {
|
|
WindowCommandCenter.showMainWindow()
|
|
}
|
|
let openItem = NSMenuItem(title: "Open Main Window", action: #selector(MenuActionBox.performAction), keyEquivalent: "o")
|
|
openItem.target = openTarget
|
|
openItem.isEnabled = true
|
|
menu.addItem(openItem)
|
|
|
|
let centerTarget = MenuActionBox {
|
|
WindowCommandCenter.centerMainWindow()
|
|
}
|
|
let centerItem = NSMenuItem(title: "Center Main Window", action: #selector(MenuActionBox.performAction), keyEquivalent: "c")
|
|
centerItem.target = centerTarget
|
|
centerItem.isEnabled = true
|
|
menu.addItem(centerItem)
|
|
|
|
let fullscreenTarget = MenuActionBox {
|
|
WindowCommandCenter.toggleFullScreen()
|
|
}
|
|
let fullscreenItem = NSMenuItem(title: "Toggle Full Screen", action: #selector(MenuActionBox.performAction), keyEquivalent: "f")
|
|
fullscreenItem.target = fullscreenTarget
|
|
fullscreenItem.isEnabled = true
|
|
menu.addItem(fullscreenItem)
|
|
|
|
menu.addItem(.separator())
|
|
|
|
let quitTarget = MenuActionBox {
|
|
NSApp.terminate(nil)
|
|
}
|
|
let quitItem = NSMenuItem(title: "Quit", action: #selector(MenuActionBox.performAction), keyEquivalent: "q")
|
|
quitItem.target = quitTarget
|
|
quitItem.isEnabled = true
|
|
menu.addItem(quitItem)
|
|
|
|
retainedTargets = [openTarget, centerTarget, fullscreenTarget, quitTarget]
|
|
item.menu = menu
|
|
statusItem = item
|
|
}
|
|
}
|
|
|
|
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")
|
|
Label("Opened from both sidebar actions and tray-driven workflows", systemImage: "menubar.rectangle")
|
|
}
|
|
.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")
|
|
|
|
Button("Toggle Full Screen") {
|
|
WindowCommandCenter.toggleFullScreen()
|
|
}
|
|
.keyboardShortcut("f")
|
|
}
|
|
}
|
|
|
|
Window("Inspector", id: "inspector") {
|
|
InspectorView()
|
|
}
|
|
.defaultSize(width: 360, height: 220)
|
|
.windowResizability(.contentSize)
|
|
}
|
|
}
|