feat(clients/windows): single-window handoff, shared settings store, console-UI surfacing
UX polish batch 1 (clients/windows/ui-polish-plan.md, workstreams W0/A1/B/C/E):
- W0: the shell's duplicated trust/settings structs are gone — src/trust.rs
re-exports pf-client-core's, so the shell and the spawned session binary share
ONE Settings shape over client-windows-settings.json. Fixes real bugs: the
shell's saves no longer drop session-side fields; the stats-overlay toggle
(show_hud -> show_stats, serde alias migrates old files) and the forwarded-
controller pick now actually reach the spawned session. The "Streaming engine"
Settings combo is gone (PUNKTFUNK_BUILTIN_STREAM=1 stays as the dev A/B knob).
- Forwarded-controller pinning by stable key (vid:pid:name, pf-client-core's
format): persisted as forward_pad, applied by the shell's own service at
startup AND by the session binary in session_params (both OSes — the session
never applied the pin before).
- A1 single window: the shell hides itself when the spawned session window
presents its first frame ({"ready":true}) and restores + foregrounds on the
child's exit — exactly one visible Punktfunk window at any time. Restore runs
before the request-access cancel gate so a Ready/Cancel race can't strand the
shell hidden.
- C console UI: punktfunk-session --browse gains --json-status (ready when the
library window presents; error line on a failed start), and the shell
surfaces it — "Open console UI" on paired hosts' menus, plus a controller-
detected hint card targeting the most recent paired host (x64 only; aarch64
ships no skia ui feature). Browse spawns hide/restore the shell like streams.
- B responsive: minimum window size (420x360); the hosts header collapses to
icon-only buttons below 700 px; the session status card shrinks instead of
clipping (max_width); busy pages, help actions, licenses and long labels wrap.
- E polish: session exe gets the app icon (winresource + WM_SETICON via the new
pf-presenter win32.rs); both exes share an explicit AppUserModelID on
unpackaged runs (packaged identity wins) so the windows group as one taskbar
app across the visibility handoff; "Start streams fullscreen" toggle passes
--fullscreen (GTK parity); connects stamp KnownHost::last_used; the connect
target is stashed for every route so "Connecting to X" always names the host.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -133,6 +133,9 @@ pub(crate) struct Shared {
|
||||
/// only publishes its outcome while its generation is still current, so a test abandoned
|
||||
/// mid-run can't overwrite a newer run's result when it finally resolves.
|
||||
pub(crate) speed_gen: std::sync::atomic::AtomicU64,
|
||||
/// Whether the live session child is a `--browse` console-UI run (vs a stream) — the
|
||||
/// session status page words itself accordingly. Set by each spawn.
|
||||
pub(crate) browse: std::sync::atomic::AtomicBool,
|
||||
}
|
||||
|
||||
pub struct AppCtx {
|
||||
@@ -143,12 +146,11 @@ pub struct AppCtx {
|
||||
}
|
||||
|
||||
/// The legacy in-process streaming path (SwapChainPanel + D3D11VA) instead of the
|
||||
/// spawned punktfunk-session window: the Settings "Streaming engine" pick, or the
|
||||
/// `PUNKTFUNK_BUILTIN_STREAM=1` env override. A temporary A/B knob — both go away with
|
||||
/// the legacy path once the Vulkan session is fully validated.
|
||||
pub(crate) fn use_builtin_stream(ctx: &AppCtx) -> bool {
|
||||
/// spawned punktfunk-session window: the `PUNKTFUNK_BUILTIN_STREAM=1` env override — a
|
||||
/// developer A/B knob only (the former Settings "Streaming engine" pick is gone), removed
|
||||
/// with the legacy path once the Vulkan session is fully validated.
|
||||
pub(crate) fn use_builtin_stream(_ctx: &AppCtx) -> bool {
|
||||
std::env::var_os("PUNKTFUNK_BUILTIN_STREAM").is_some_and(|v| v == "1")
|
||||
|| ctx.settings.lock().unwrap().engine == "builtin"
|
||||
}
|
||||
|
||||
pub fn run(identity: (String, String), gamepad: GamepadService) -> windows_reactor::Result<()> {
|
||||
@@ -158,10 +160,25 @@ pub fn run(identity: (String, String), gamepad: GamepadService) -> windows_react
|
||||
gamepad,
|
||||
shared: Arc::new(Shared::default()),
|
||||
});
|
||||
// Re-apply the persisted forwarded-controller pin (stable key; the service matches it
|
||||
// whenever such a pad connects) — GTK-shell parity.
|
||||
{
|
||||
let forward = ctx.settings.lock().unwrap().forward_pad.clone();
|
||||
if !forward.is_empty() {
|
||||
ctx.gamepad.set_pinned(Some(forward));
|
||||
}
|
||||
}
|
||||
apply_window_icon_when_ready();
|
||||
App::new()
|
||||
.title("Punktfunk")
|
||||
.inner_size(1000.0, 720.0)
|
||||
// A floor under every layout: below this the header/cards would clip rather than
|
||||
// reflow (the pages adapt down to it — see the hosts page's responsive grid).
|
||||
.inner_constraints(InnerConstraints {
|
||||
min_width: Some(420.0),
|
||||
min_height: Some(360.0),
|
||||
..Default::default()
|
||||
})
|
||||
.backdrop(Backdrop::Mica)
|
||||
.render(move |cx| root(cx, &ctx))
|
||||
}
|
||||
@@ -232,6 +249,22 @@ fn root(cx: &mut RenderCx, ctx: &Arc<AppCtx>) -> Element {
|
||||
let (hover, set_hover) = cx.use_async_state(Option::<String>::None);
|
||||
// Which Settings section the NavigationView shows (persists across visits this run).
|
||||
let (settings_nav, set_settings_nav) = cx.use_async_state("display".to_string());
|
||||
// Connected-controller count, mirrored from the gamepad service by a poll thread
|
||||
// (thread-driven state must be root state — see the module docs). Drives the hosts
|
||||
// page's "Open console UI" hint; the compare in `call` makes the steady state free.
|
||||
let (pads, set_pads) = cx.use_async_state(0usize);
|
||||
cx.use_effect((), {
|
||||
let (gp, set_pads) = (ctx.gamepad.clone(), set_pads.clone());
|
||||
move || {
|
||||
std::thread::Builder::new()
|
||||
.name("pf-pads".into())
|
||||
.spawn(move || loop {
|
||||
std::thread::sleep(std::time::Duration::from_secs(2));
|
||||
set_pads.call(gp.pads().len());
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
});
|
||||
|
||||
// Continuous LAN discovery (spawned once).
|
||||
cx.use_effect((), {
|
||||
@@ -392,6 +425,7 @@ fn root(cx: &mut RenderCx, ctx: &Arc<AppCtx>) -> Element {
|
||||
svc,
|
||||
hosts,
|
||||
status,
|
||||
pads,
|
||||
forget,
|
||||
rename,
|
||||
show_add,
|
||||
|
||||
Reference in New Issue
Block a user