Files
punktfunk/clients/apple/Sources/PunktfunkClient/SettingsView.swift
T
enricobuehler a9d1c16067
ci / rust (push) Has been cancelled
feat(apple): client-selectable compositor in the macOS client
Adopts punktfunk_connect_ex from the compositor-selection batch: a Compositor enum on
PunktfunkConnection (auto/kwin/wlroots/mutter/gamescope, with the host's name aliases
for env parsing), a "Host compositor" picker in Settings (default Automatic — a
concrete choice is honored only if that backend is available host-side), and
PUNKTFUNK_COMPOSITOR / PUNKTFUNK_REMOTE_COMPOSITOR pass-throughs for the autoconnect
dev hook and the remote first-light test. The wire change is backward-compatible
(optional trailing byte), so no behavior changes at the default.

Validated live against the box: host with no compositor env (auto-detect = KWin)
logged "honoring client compositor request compositor=gamescope" and streamed 60/60
decoded frames from the spawned gamescope.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 22:51:42 +02:00

67 lines
2.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// App settings (,): the stream mode + the host compositor. The host creates a native
// virtual output at exactly this size/refresh there is no scaling anywhere in the
// pipeline.
import AppKit
import PunktfunkKit
import SwiftUI
struct SettingsView: View {
@AppStorage("punktfunk.width") private var width = 1920
@AppStorage("punktfunk.height") private var height = 1080
@AppStorage("punktfunk.hz") private var hz = 60
@AppStorage("punktfunk.compositor") private var compositor = 0
var body: some View {
Form {
Section {
HStack {
TextField("Resolution", value: $width, format: .number.grouping(.never))
Text("×")
TextField("", value: $height, format: .number.grouping(.never))
.labelsHidden()
}
TextField("Refresh rate (Hz)", value: $hz, format: .number.grouping(.never))
LabeledContent("") {
Button("Use this display's mode") { fillFromMainScreen() }
}
} header: {
Text("Stream mode")
} footer: {
Text("The host creates a virtual output at exactly this mode — "
+ "native resolution, no scaling.")
.font(.caption)
.foregroundStyle(.secondary)
}
Section {
Picker("Compositor", selection: $compositor) {
Text("Automatic").tag(0)
Text("KWin (KDE Plasma)").tag(1)
Text("wlroots (Sway / Hyprland)").tag(2)
Text("Mutter (GNOME)").tag(3)
Text("gamescope").tag(4)
}
} header: {
Text("Host compositor")
} footer: {
Text("Which compositor drives the virtual output on the host. A specific "
+ "choice is honored only if that backend is available there — "
+ "otherwise the host falls back to auto-detection.")
.font(.caption)
.foregroundStyle(.secondary)
}
}
.formStyle(.grouped)
.frame(width: 380)
.fixedSize()
}
private func fillFromMainScreen() {
guard let screen = NSScreen.main else { return }
let scale = screen.backingScaleFactor
width = Int(screen.frame.width * scale)
height = Int(screen.frame.height * scale)
hz = screen.maximumFramesPerSecond
}
}