Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions Examples/Sources/WindowingExample/WindowingApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,21 @@ struct SheetDemo: View {
}
}

struct TertiaryWindowView: View {
@Environment(\.dismissWindow) private var dismissWindow

var body: some View {
VStack {
Text("This a tertiary window!")
.padding(10)

Button("Close window") {
dismissWindow()
}
}
}
}

@main
@HotReloadable
struct WindowingApp: App {
Expand Down Expand Up @@ -220,8 +235,7 @@ struct WindowingApp: App {

WindowGroup("Tertiary window") {
#hotReloadable {
Text("This a tertiary window!")
.padding(10)
TertiaryWindowView()
}
}
.defaultSize(width: 200, height: 200)
Expand Down
4 changes: 4 additions & 0 deletions Sources/AppKitBackend/AppKitBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ public final class AppKitBackend: AppBackend {
window.makeKeyAndOrderFront(nil)
}

public func close(window: Window) {
window.close()
}

public func openExternalURL(_ url: URL) throws {
NSWorkspace.shared.open(url)
}
Expand Down
6 changes: 6 additions & 0 deletions Sources/SwiftCrossUI/Backend/AppBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ public protocol AppBackend: Sendable {
/// receives an external URL or file to handle from the desktop environment.
/// May be used in other circumstances eventually.
func activate(window: Window)
/// Closes a window.
func close(window: Window)

/// Sets the application's global menu. Some backends may make use of the host
/// platform's global menu bar (such as macOS's menu bar), and others may render their
Expand Down Expand Up @@ -825,6 +827,10 @@ extension AppBackend {

// MARK: Application

public func close(window: Window) {
todo()
}

public func setApplicationMenu(_ submenus: [ResolvedMenu.Submenu]) {
todo()
}
Expand Down
5 changes: 3 additions & 2 deletions Sources/SwiftCrossUI/Environment/Actions/DismissAction.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// An action that dismisses the current presentation context.
///
/// Use the `dismiss` environment value to get an instance of this action,
/// then call it to dismiss the current sheet.
/// then call it to dismiss (close) the current window or sheet.
///
/// Example usage:
/// ```swift
Expand Down Expand Up @@ -48,7 +48,8 @@ extension EnvironmentValues {
/// An action that dismisses the current presentation context.
///
/// Use this environment value to get a dismiss action that can be called
/// to dismiss the current sheet, popover, or other presentation.
/// to dismiss (close) the current window, sheet, popover, or other
/// presentation.
///
/// Example:
/// ```swift
Expand Down
38 changes: 38 additions & 0 deletions Sources/SwiftCrossUI/Environment/Actions/DismissWindowAction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// An action that closes the current window.
///
/// Use the `dismissWindow` environment value to get an instance of this action,
/// then call it to close the current window .
///
/// Example usage:
/// ```swift
/// struct ContentView: View {
/// @Environment(\.dismissWindow) var dismissWindow
///
/// var body: some View {
/// VStack {
/// Text("Window Content")
/// Button("Close") {
/// dismissWindow()
/// }
/// }
/// }
/// }
/// ```
@MainActor
public struct DismissWindowAction {
let backend: any AppBackend
let window: MainActorBox<Any?>

/// Dismisses the current presentation context.
public func callAsFunction() {
func closeWindow<Backend: AppBackend>(backend: Backend) {
guard let window = window.value else {
print("warning: dismissWindow() called outside of a window")
return
}
backend.close(window: window as! Backend.Window)
}

closeWindow(backend: backend)
}
}
9 changes: 9 additions & 0 deletions Sources/SwiftCrossUI/Environment/EnvironmentValues.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ public struct EnvironmentValues {
)
}

/// Closes the current window.
@MainActor
public var dismissWindow: DismissWindowAction {
return DismissWindowAction(
backend: backend,
window: .init(value: window)
)
}

/// Reveals a file in the system's file manager. This opens
/// the file's enclosing directory and highlighting the file.
///
Expand Down
7 changes: 6 additions & 1 deletion Sources/SwiftCrossUI/Scenes/WindowGroupNode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ public final class WindowGroupNode<Content: View>: SceneGraphNode {
viewGraph = ViewGraph(
for: scene.body,
backend: backend,
environment: environment.with(\.window, window)
environment: environment
.with(\.window, window)
.with(\.dismiss, DismissAction {
backend.close(window: window)
})
)
let rootWidget = viewGraph.rootNode.concreteNode(for: Backend.self).widget

Expand Down Expand Up @@ -135,6 +139,7 @@ public final class WindowGroupNode<Content: View>: SceneGraphNode {
)
}
.with(\.window, window)
.with(\.dismiss, DismissAction { backend.close(window: window) })

let dryRunResult: ViewUpdateResult?
if !windowSizeIsFinal {
Expand Down