1use crate::Utf16Writer;
6use crate::services::{apt::Apt, gfx::Gfx};
7
8use ctru_sys::{errorConf, errorDisp, errorInit};
9
10#[doc(alias = "errorConf")]
12pub struct PopUp {
13 state: Box<errorConf>,
14}
15
16#[doc(alias = "errorType")]
18#[derive(Copy, Clone, Debug, PartialEq, Eq)]
19#[repr(u16)]
20pub enum WordWrap {
21 Disabled = ctru_sys::ERROR_TEXT,
23 Enabled = ctru_sys::ERROR_TEXT_WORD_WRAP,
25}
26
27#[doc(alias = "errorReturnCode")]
29#[derive(Copy, Clone, Debug, PartialEq, Eq)]
30#[repr(i8)]
31pub enum Error {
32 Unknown = ctru_sys::ERROR_UNKNOWN,
34 NotSupported = ctru_sys::ERROR_NOT_SUPPORTED,
36 HomePressed = ctru_sys::ERROR_HOME_BUTTON,
38 PowerPressed = ctru_sys::ERROR_POWER_BUTTON,
40 ResetPressed = ctru_sys::ERROR_SOFTWARE_RESET,
42}
43
44impl PopUp {
45 #[doc(alias = "errorInit")]
47 pub fn new(word_wrap: WordWrap) -> Self {
48 let mut state = Box::<errorConf>::default();
49
50 unsafe { errorInit(state.as_mut(), word_wrap as _, 0) };
51
52 Self { state }
53 }
54
55 #[doc(alias = "errorText")]
78 pub fn writer(&mut self) -> Utf16Writer<'_> {
79 Utf16Writer::new(&mut self.state.Text)
80 }
81
82 #[doc(alias = "errorDisp")]
84 pub fn launch(&mut self, _apt: &Apt, _gfx: &Gfx) -> Result<(), Error> {
85 unsafe { self.launch_unchecked() }
86 }
87
88 unsafe fn launch_unchecked(&mut self) -> Result<(), Error> {
94 unsafe { ctru_sys::errorDisp(self.state.as_mut()) };
95
96 match self.state.returnCode {
97 ctru_sys::ERROR_NONE | ctru_sys::ERROR_SUCCESS => Ok(()),
98 ctru_sys::ERROR_NOT_SUPPORTED => Err(Error::NotSupported),
99 ctru_sys::ERROR_HOME_BUTTON => Err(Error::HomePressed),
100 ctru_sys::ERROR_POWER_BUTTON => Err(Error::PowerPressed),
101 ctru_sys::ERROR_SOFTWARE_RESET => Err(Error::ResetPressed),
102 _ => Err(Error::Unknown),
103 }
104 }
105}
106
107pub(crate) fn set_panic_hook(call_old_hook: bool) {
108 use crate::services::gfx::GFX_ACTIVE;
109 use std::fmt::Write;
110 use std::sync::{Mutex, TryLockError};
111
112 static ERROR_CONF: Mutex<errorConf> = unsafe { Mutex::new(std::mem::zeroed()) };
113
114 let mut lock = ERROR_CONF.lock().unwrap();
115
116 unsafe { errorInit(&mut *lock, WordWrap::Enabled as _, 0) };
117
118 let old_hook = std::panic::take_hook();
119
120 std::panic::set_hook(Box::new(move |panic_info| {
121 if let (Err(TryLockError::WouldBlock), Ok(_apt)) = (GFX_ACTIVE.try_lock(), Apt::new()) {
124 if call_old_hook {
125 old_hook(panic_info);
126 }
127
128 let mut lock = ERROR_CONF.lock().unwrap();
129
130 let error_conf = &mut *lock;
131
132 let mut writer = Utf16Writer::new(&mut error_conf.Text);
133
134 let thread = std::thread::current();
135
136 let name = thread.name().unwrap_or("<unnamed>");
137
138 let _ = write!(writer, "thread '{name}' {panic_info}");
139
140 unsafe {
141 errorDisp(error_conf);
142 }
143 } else {
144 old_hook(panic_info);
145 }
146 }));
147}
148
149impl std::fmt::Display for Error {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 Self::NotSupported => write!(f, "operation not supported"),
153 Self::HomePressed => write!(f, "home button pressed while error applet was running"),
154 Self::PowerPressed => write!(f, "power button pressed while error applet was running"),
155 Self::ResetPressed => write!(f, "reset button pressed while error applet was running"),
156 Self::Unknown => write!(f, "an unknown error occurred"),
157 }
158 }
159}
160
161impl std::error::Error for Error {}