diff --git a/ctru-rs/Cargo.toml b/ctru-rs/Cargo.toml index e841bf6..f33e177 100644 --- a/ctru-rs/Cargo.toml +++ b/ctru-rs/Cargo.toml @@ -12,6 +12,7 @@ name = "ctru" [dependencies] ctru-sys = { path = "../ctru-sys", version = "0.4" } +const-zero = "0.1.0" linker-fix-3ds = { git = "https://github.com/Meziu/rust-linker-fix-3ds.git" } pthread-3ds = { git = "https://github.com/Meziu/pthread-3ds.git" } libc = { git = "https://github.com/Meziu/libc.git" } diff --git a/ctru-rs/src/console.rs b/ctru-rs/src/console.rs index e640109..d7ab478 100644 --- a/ctru-rs/src/console.rs +++ b/ctru-rs/src/console.rs @@ -50,3 +50,31 @@ impl Default for Console { Console::init(Screen::Top) } } + +impl Drop for Console { + fn drop(&mut self) { + static mut EMPTY_CONSOLE: PrintConsole = unsafe { const_zero::const_zero!(PrintConsole) }; + + unsafe { + // Safety: We are about to deallocate the PrintConsole data pointed + // to by libctru. Without this drop code libctru would have a + // dangling pointer that it writes to on every print. To prevent + // this we replace the console with an empty one if it was selected. + // This is the same state that libctru starts up in, before + // initializing a console. Writes to the console will not show up on + // the screen, but it won't crash either. + + // Get the current console by replacing it with an empty one. + let current_console = ctru_sys::consoleSelect(&mut EMPTY_CONSOLE); + + if std::ptr::eq(current_console, &*self.context) { + // Console dropped while selected. We just replaced it with the + // empty console so nothing more to do. + } else { + // Console dropped while a different console was selected. Put back + // the console that was selected. + ctru_sys::consoleSelect(current_console); + } + } + } +}