Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error applet support + error applet panic hook #162

Merged
merged 17 commits into from
Feb 27, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions ctru-rs/src/applets/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,21 @@ impl PopUp {
}
}

/// Sets a custom panic hook that uses the error applet to display panic messages. You can also choose to have
/// messages printed over stderr along with the pop-up display.
/// Sets a custom panic hook that uses the error applet to display panic messages. You can also choose to have the
/// default panic hook called to print the message over stderr.
///
/// If the `Gfx` service is not initialized during a panic, the error applet will not be displayed and the panic
/// message will be printed over stderr.
pub fn set_panic_hook(use_stderr: bool) {
/// If the `Gfx` service is not initialized during a panic, the error applet will not be displayed and the default
/// hook will be called.
pub fn set_panic_hook(call_default_hook: bool) {
use crate::services::gfx::GFX_ACTIVE;

use std::io::Write;
use std::sync::TryLockError;

// Ensure we get the default hook instead of a previously registered user hook.
FenrirWolf marked this conversation as resolved.
Show resolved Hide resolved
let default_hook = {
let _ = std::panic::take_hook();
std::panic::take_hook()
};

std::panic::set_hook(Box::new(move |panic_info| {
let thread = std::thread::current();

Expand All @@ -107,8 +111,8 @@ pub fn set_panic_hook(use_stderr: bool) {
// If we get a `WouldBlock` error, we know that the `Gfx` service has been initialized.
// Otherwise fallback to printing over stderr.
FenrirWolf marked this conversation as resolved.
Show resolved Hide resolved
if let (Err(TryLockError::WouldBlock), Ok(_apt)) = (GFX_ACTIVE.try_lock(), Apt::new()) {
if use_stderr {
print_to_stderr(name, panic_info);
if call_default_hook {
default_hook(panic_info);
}

let payload = format!("thread '{name}' {panic_info}");
Expand All @@ -121,15 +125,9 @@ pub fn set_panic_hook(use_stderr: bool) {
popup.launch_unchecked();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to check my understanding, this will block the app until the popup is closed, and then the app will quit (since there's no loop or anything)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, you've got that right. Though the app can technically continue if the panic is stopped by a thread boundary or catch_unwind or whatever.

}
} else {
print_to_stderr(name, panic_info);
default_hook(panic_info);
}
}));

fn print_to_stderr(name: &str, panic_info: &std::panic::PanicInfo) {
let mut stderr = std::io::stderr().lock();

let _ = writeln!(stderr, "thread '{name}' {panic_info}");
}
}

impl std::fmt::Display for Error {
Expand Down
Loading