windows: no console window for the release app and its children
- the oak-editor release build lacked the `windows_subsystem = "windows"` crate attribute, so launching the installed app opened a console window next to the editor (debug builds keep the console so `cargo run` shows logs); - oak-worker, the OFX host and the ffmpeg/ffprobe helpers are console-subsystem binaries spawned by the GUI app, so each spawn now carries CREATE_NO_WINDOW through the shared oak_core::miscutils::hide_console_window helper (a no-op off Windows).
This commit is contained in:
@@ -16,6 +16,12 @@
|
||||
|
||||
//! The `oakapp` binary: opens the Oak main window (see [`oakapp::app`]).
|
||||
|
||||
// Windows release builds are GUI applications: without the subsystem
|
||||
// attribute the linker marks the executable as a console program and
|
||||
// launching Oak opens a console window. Debug builds keep the console
|
||||
// (`cargo run` shows logs). The attribute is ignored elsewhere.
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
oakapp::run();
|
||||
}
|
||||
|
||||
@@ -316,6 +316,25 @@ impl Current {
|
||||
}
|
||||
}
|
||||
|
||||
/// Hide the console window a child process would otherwise create on
|
||||
/// Windows: a GUI binary (the release `oak-editor.exe`) spawning a
|
||||
/// console-subsystem child — `oak-worker`, the OFX host, `ffmpeg` —
|
||||
/// flashes a console window even when every stream is piped. No-op on
|
||||
/// other platforms.
|
||||
pub fn hide_console_window(command: &mut std::process::Command) {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::process::CommandExt;
|
||||
/// `CREATE_NO_WINDOW` (winbase.h).
|
||||
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
|
||||
command.creation_flags(CREATE_NO_WINDOW);
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = command;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ffi::c_void;
|
||||
|
||||
@@ -466,6 +466,8 @@ impl OfxHost {
|
||||
for (key, value) in &config.env {
|
||||
command.env(key, value);
|
||||
}
|
||||
// A GUI Oak spawning a console child would flash a console window.
|
||||
oak_core::miscutils::hide_console_window(&mut command);
|
||||
let mut child = command
|
||||
.spawn()
|
||||
.map_err(|e| Error::Failed(format!("spawn OFX host {}: {e}", bin.display())))?;
|
||||
|
||||
@@ -1950,14 +1950,18 @@ impl ProcessDispatcher {
|
||||
);
|
||||
let shm = ShmRegionView::create(&key, inner.slots, inner.slot_bytes)?;
|
||||
|
||||
let mut child = Command::new(&inner.bin)
|
||||
let mut command = Command::new(&inner.bin);
|
||||
command
|
||||
// Auto backend: prefer the GPU, fall back to the CPU renderer
|
||||
// (M16 S1 — the worker tolerates a GPU init failure and keeps
|
||||
// evaluating headless).
|
||||
.args(["--backend", "auto"])
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.stderr(Stdio::inherit());
|
||||
// A GUI Oak spawning a console child would flash a console window.
|
||||
oak_core::miscutils::hide_console_window(&mut command);
|
||||
let mut child = command
|
||||
.spawn()
|
||||
.map_err(|e| Error::Failed(format!("spawn oak-worker: {e}")))?;
|
||||
let stdin = child.stdin.take();
|
||||
|
||||
@@ -213,9 +213,10 @@ impl ProxyTask {
|
||||
}
|
||||
|
||||
fn probe_hw_encoder_uncached(ffmpeg_path: &str) -> HwEncoder {
|
||||
let out = Command::new(ffmpeg_path)
|
||||
.args(["-hide_banner", "-encoders"])
|
||||
.output();
|
||||
let mut command = Command::new(ffmpeg_path);
|
||||
command.args(["-hide_banner", "-encoders"]);
|
||||
oak_core::miscutils::hide_console_window(&mut command);
|
||||
let out = command.output();
|
||||
let Ok(out) = out else {
|
||||
return HwEncoder::Software;
|
||||
};
|
||||
@@ -251,24 +252,25 @@ impl ProxyTask {
|
||||
/// Whether `encoder` can initialize and encode one tiny frame; see the
|
||||
/// caller for why the `-encoders` list is not enough.
|
||||
fn encoder_usable(ffmpeg_path: &str, encoder: &str) -> bool {
|
||||
let out = Command::new(ffmpeg_path)
|
||||
.args([
|
||||
"-hide_banner",
|
||||
"-loglevel",
|
||||
"error",
|
||||
"-f",
|
||||
"lavfi",
|
||||
"-i",
|
||||
"color=size=64x64:rate=1:duration=1",
|
||||
"-frames:v",
|
||||
"1",
|
||||
"-c:v",
|
||||
encoder,
|
||||
"-f",
|
||||
"null",
|
||||
"-",
|
||||
])
|
||||
.output();
|
||||
let mut command = Command::new(ffmpeg_path);
|
||||
command.args([
|
||||
"-hide_banner",
|
||||
"-loglevel",
|
||||
"error",
|
||||
"-f",
|
||||
"lavfi",
|
||||
"-i",
|
||||
"color=size=64x64:rate=1:duration=1",
|
||||
"-frames:v",
|
||||
"1",
|
||||
"-c:v",
|
||||
encoder,
|
||||
"-f",
|
||||
"null",
|
||||
"-",
|
||||
]);
|
||||
oak_core::miscutils::hide_console_window(&mut command);
|
||||
let out = command.output();
|
||||
matches!(out, Ok(out) if out.status.success())
|
||||
}
|
||||
|
||||
@@ -508,6 +510,8 @@ impl TaskBehavior for ProxyTask {
|
||||
.args(&args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
// A GUI Oak spawning a console child would flash a console window.
|
||||
oak_core::miscutils::hide_console_window(&mut command);
|
||||
let mut child = match command.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(_) => {
|
||||
@@ -601,17 +605,18 @@ fn probe_source_duration_seconds(ffmpeg_path: &str, source_filename: &str) -> f6
|
||||
if !ffprobe.exists() {
|
||||
return 0.0;
|
||||
}
|
||||
let output = Command::new(&ffprobe)
|
||||
.args([
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
source_filename,
|
||||
])
|
||||
.output();
|
||||
let mut command = Command::new(&ffprobe);
|
||||
command.args([
|
||||
"-v",
|
||||
"error",
|
||||
"-show_entries",
|
||||
"format=duration",
|
||||
"-of",
|
||||
"default=noprint_wrappers=1:nokey=1",
|
||||
source_filename,
|
||||
]);
|
||||
oak_core::miscutils::hide_console_window(&mut command);
|
||||
let output = command.output();
|
||||
match output {
|
||||
Ok(out) if out.status.success() => {
|
||||
let text = String::from_utf8_lossy(&out.stdout);
|
||||
|
||||
Reference in New Issue
Block a user