forked from unom/punktfunk
Six crates were still unguarded, and all six are OURS — none vendored: pf-console-ui, pf-gpu, punktfunk-tray, clients/windows, tools/display-disturb, wdk-probe. Two of them ship (the tray and the Windows client), so "small" was about item count, not exposure. Five are closed here. Only 17 of their 75 unsafe items actually lacked a proof — pf-gpu, punktfunk-tray and display-disturb were already fully documented and needed nothing but the deny, which is the good case: the convention was being followed, just not enforced. The 17 that were missing are the usual Win32/COM shapes, and two were worth stating properly. `clients/windows`'s `GetCurrentPackageFullName` is called with `len = 0` and no buffer — that is the documented identity PROBE, which writes nothing, and reading it as a normal query would be a mistake. `pf-console-ui`'s two `destroy_image_view` calls are the load-bearing ones: the comment above one already argued that in-flight sampling of that slot ended two presents ago (the ring alternates and the presenter waits its fence before each record), which is exactly the kind of reasoning a `// SAFETY:` should carry and it was sitting there unlabelled. Also fixes a real Windows-only clippy error this uncovered: `pf-gpu` had a `#[cfg(target_os = "windows")]` fn AFTER its `mod tests`, tripping `items_after_test_module`. It never fired on Linux (the item does not exist there) and no CI job clippies pf-gpu on Windows, so it sat unseen. Moved above the test module. Remaining: `wdk-probe` (26 items) alone, and only because it needs the WDK to build — .47 cannot, so nothing here can verify a deny on it. Verified: Linux .21 fmt + both CI clippy steps rc=0; Windows .47 the four Windows-relevant crates at `-D warnings` rc=0.
74 lines
3.1 KiB
Rust
74 lines
3.1 KiB
Rust
//! Hide/restore the shell's top-level window around a spawned session, so exactly ONE
|
|
//! Punktfunk window is visible at a time: the spawned stream/browse window IS the app
|
|
//! while it runs (hidden = no taskbar entry, no Alt-Tab ghost), and the shell reappears
|
|
//! the moment the child exits — every exit path funnels through the spawn reader's
|
|
//! `Exited` event (clean end, error, crash, Disconnect kill), so the shell can never stay
|
|
//! hidden with no child.
|
|
//!
|
|
//! windows-reactor exposes no window handle, so the HWND is resolved by its (unique)
|
|
//! title and cached — the same pattern as `app::apply_window_icon_when_ready` and
|
|
//! `stream::window_dpi`.
|
|
|
|
use std::sync::atomic::{AtomicIsize, Ordering};
|
|
use windows::Win32::Foundation::{HWND, RECT};
|
|
use windows::Win32::UI::WindowsAndMessaging::{
|
|
FindWindowW, GetWindowRect, IsWindow, SetForegroundWindow, ShowWindow, SW_HIDE, SW_SHOW,
|
|
};
|
|
|
|
static SHELL_HWND: AtomicIsize = AtomicIsize::new(0);
|
|
|
|
fn shell_hwnd() -> Option<HWND> {
|
|
// SAFETY: the cached value is an `HWND` this process obtained itself; it is re-validated with
|
|
// `IsWindow` before use (a stale handle is treated as absent), and the lookup calls take only
|
|
// static wide literals.
|
|
unsafe {
|
|
let cached = SHELL_HWND.load(Ordering::Relaxed);
|
|
if cached != 0 {
|
|
let h = HWND(cached as *mut _);
|
|
if IsWindow(Some(h)).as_bool() {
|
|
return Some(h);
|
|
}
|
|
}
|
|
let h = FindWindowW(None, windows::core::w!("Punktfunk")).ok()?;
|
|
SHELL_HWND.store(h.0 as isize, Ordering::Relaxed);
|
|
Some(h)
|
|
}
|
|
}
|
|
|
|
/// Hide the shell while a spawned session window is up. Called on the child's
|
|
/// `{"ready":true}` (its window has presented — never earlier, so a failed connect keeps
|
|
/// the shell in view with its error banner).
|
|
pub(crate) fn hide() {
|
|
if let Some(h) = shell_hwnd() {
|
|
// SAFETY: `h` is the validated shell window handle from `shell_hwnd`; `ShowWindow` takes it
|
|
// plus a plain flag and dereferences nothing.
|
|
unsafe {
|
|
let _ = ShowWindow(h, SW_HIDE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Bring the shell back (and to the foreground) when the child exits. Safe to call when
|
|
/// it was never hidden — showing a visible window is a no-op.
|
|
pub(crate) fn restore() {
|
|
if let Some(h) = shell_hwnd() {
|
|
// SAFETY: as `hide` — `h` is the validated shell window handle, and both calls take only
|
|
// that handle plus a plain flag.
|
|
unsafe {
|
|
let _ = ShowWindow(h, SW_SHOW);
|
|
let _ = SetForegroundWindow(h);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The shell window's top-left in desktop coordinates — passed to the spawned session
|
|
/// (`--window-pos`) so its window opens on the SAME monitor, roughly where the shell is,
|
|
/// and the visibility handoff reads as one window changing content.
|
|
pub(crate) fn position() -> Option<(i32, i32)> {
|
|
let h = shell_hwnd()?;
|
|
let mut r = RECT::default();
|
|
// SAFETY: `h` is the validated shell window handle and `r` is a live local the call fills.
|
|
unsafe { GetWindowRect(h, &mut r).ok()? };
|
|
Some((r.left, r.top))
|
|
}
|