M1: say why when the window can't open (#261)

Release builds on Windows have no console, so an eframe::run_native error
(no usable graphics adapter, a device the driver refuses) went to an unseen
standard error and the app quit silently. The error is now logged and shown
in a message box with a hint: unset WGPU_BACKEND when it is set, otherwise
update the driver or try another graphics API (OpenGL on Windows), and
where to report it. With --control the box is skipped so agents aren't
blocked.
This commit is contained in:
Barzabel
2026-10-15 20:24:04 +03:00
parent 102404e8c3
commit 97f9c2fc5d
3 changed files with 89 additions and 2 deletions
+10 -2
View File
@@ -17,6 +17,7 @@ mod gamepad;
mod graphics;
mod recovery;
mod services;
mod startup;
#[cfg(all(test, target_os = "macos"))]
mod apple_events_tests;
@@ -30,6 +31,8 @@ mod recovery_online_tests;
mod recovery_tests;
#[cfg(test)]
mod services_tests;
#[cfg(test)]
mod startup_tests;
use std::sync::{Arc, Mutex};
@@ -203,7 +206,7 @@ fn main() -> eframe::Result {
let apple_events = apple_events::AppleEvents::install();
#[cfg(target_os = "macos")]
let apple_events = &apple_events;
eframe::run_native(
let result = eframe::run_native(
"FigCraft",
options,
Box::new(move |_cc| {
@@ -216,5 +219,10 @@ fn main() -> eframe::Result {
apple_events: apple_events.connect(&_cc.egui_ctx),
}))
}),
)
);
// Say why instead of quitting silently: release builds on Windows have no console.
if let Err(e) = &result {
startup::failed(e, port.is_some());
}
result
}
+44
View File
@@ -0,0 +1,44 @@
//! When the window can't open.
//!
//! Release builds on Windows have no console, so an error from `eframe::run_native` (no usable
//! graphics adapter, a surface or device the driver refuses) went to a standard error nobody sees
//! and the app quit without a word (#261). Now it is logged and shown in a message box.
/// Where a report goes.
const ISSUES: &str = "https://github.com/storytold/figcraft/issues";
/// The text shown when the window couldn't open with `error`. `backend_set`: `WGPU_BACKEND` named
/// the graphics API, so the hint is to unset it rather than to try another one.
pub fn message(error: &str, backend_set: bool) -> String {
let hint = if backend_set {
"WGPU_BACKEND is set and names the graphics API to use; unsetting it lets FigCraft choose."
} else if cfg!(windows) {
// Direct3D 12 and OpenGL are both offered (`graphics.rs`), but wgpu keeps the Direct3D 12
// adapter it picked even when its device then fails, so naming OpenGL alone can still help.
"Updating the graphics driver often helps. To use OpenGL only, start FigCraft from a Command Prompt with:\n\nset WGPU_BACKEND=gl\nfigcraft.exe"
} else {
"Updating the graphics driver often helps. WGPU_BACKEND (vulkan, gl, metal) names another graphics API to try."
};
format!("FigCraft couldn't open its window: {error}\n\n{hint}\n\nIf it keeps happening, please report it at {ISSUES} with this message.")
}
/// Log the failure and, unless `quiet` (started for an agent with `--control`: a modal box would
/// keep the caller waiting, and it reads standard error), show it in a message box.
pub fn failed(error: &eframe::Error, quiet: bool) {
let text = message(&error.to_string(), std::env::var_os("WGPU_BACKEND").is_some());
// Standard error even when RUST_LOG turned errors off.
if log::log_enabled!(log::Level::Error) {
log::error!("{text}");
} else {
eprintln!("figcraft: {text}");
}
if quiet {
return;
}
let _ = rfd::MessageDialog::new()
.set_level(rfd::MessageLevel::Error)
.set_title("FigCraft")
.set_description(text)
.set_buttons(rfd::MessageButtons::Ok)
.show();
}
+35
View File
@@ -0,0 +1,35 @@
//! The message shown when the window can't open: it carries the error, a next step and where to
//! report it, instead of the app quitting silently (#261).
use crate::startup::message;
const ERROR: &str = "WGPU error: Failed to create surface for any enabled backend: {}";
#[test]
fn the_message_carries_the_error_and_where_to_report_it() {
let text = message(ERROR, false);
assert!(text.contains(ERROR), "the error itself: {text}");
assert!(text.contains("https://github.com/storytold/figcraft/issues"), "where to report it: {text}");
}
#[test]
fn without_wgpu_backend_it_suggests_the_driver_and_another_graphics_api() {
let text = message(ERROR, false);
assert!(text.contains("graphics driver"), "{text}");
assert!(text.contains("WGPU_BACKEND"), "another graphics API to try: {text}");
assert!(!text.contains("unsetting"), "{text}");
}
#[cfg(windows)]
#[test]
fn on_windows_it_shows_how_to_start_with_opengl() {
let text = message(ERROR, false);
assert!(text.contains("set WGPU_BACKEND=gl"), "a release build has no console to look this up from: {text}");
}
#[test]
fn with_wgpu_backend_set_it_suggests_unsetting_it() {
let text = message(ERROR, true);
assert!(text.contains("unsetting"), "{text}");
assert!(!text.contains("graphics driver"), "the chosen backend is the likelier cause: {text}");
}