44
55use crate :: services:: { apt:: Apt , gfx:: Gfx } ;
66
7- use ctru_sys:: errorConf;
7+ use ctru_sys:: { errorConf, errorDisp} ;
8+
9+ use std:: cell:: UnsafeCell ;
810
911/// Configuration struct to set up the Error applet.
1012#[ doc( alias = "errorConf" ) ]
@@ -94,12 +96,32 @@ impl PopUp {
9496 }
9597}
9698
99+ struct PanicHookConfig {
100+ error_app : UnsafeCell < PopUp > ,
101+ }
102+
103+ impl PanicHookConfig {
104+ fn new ( ) -> Self {
105+ Self {
106+ error_app : UnsafeCell :: new ( PopUp :: new ( WordWrap :: Enabled ) ) ,
107+ }
108+ }
109+
110+ unsafe fn get ( & self ) -> * mut errorConf {
111+ unsafe { ( * self . error_app . get ( ) ) . state . as_mut ( ) }
112+ }
113+ }
114+
115+ unsafe impl Sync for PanicHookConfig { }
116+
97117pub ( crate ) fn set_panic_hook ( call_old_hook : bool ) {
98118 use crate :: services:: gfx:: GFX_ACTIVE ;
99119 use std:: sync:: TryLockError ;
100120
101121 let old_hook = std:: panic:: take_hook ( ) ;
102122
123+ let config = PanicHookConfig :: new ( ) ;
124+
103125 std:: panic:: set_hook ( Box :: new ( move |panic_info| {
104126 // If we get a `WouldBlock` error, we know that the `Gfx` service has been initialized.
105127 // Otherwise fallback to using the old panic hook.
@@ -108,18 +130,57 @@ pub(crate) fn set_panic_hook(call_old_hook: bool) {
108130 old_hook ( panic_info) ;
109131 }
110132
111- let thread = std :: thread :: current ( ) ;
133+ let error_conf = unsafe { & mut * config . get ( ) } ;
112134
113- let name = thread . name ( ) . unwrap_or ( "<unnamed>" ) ;
135+ let mut buf1 = itoa :: Buffer :: new ( ) ;
114136
115- let message = format ! ( "thread '{name}' {panic_info}" ) ;
137+ let mut buf2 = itoa :: Buffer :: new ( ) ;
116138
117- let mut popup = PopUp :: new ( WordWrap :: Enabled ) ;
139+ let thread = std:: thread:: current ( ) ;
140+
141+ let name = thread. name ( ) . unwrap_or ( "<unnamed>" ) ;
118142
119- popup. set_text ( & message) ;
143+ let location = panic_info. location ( ) . unwrap ( ) ;
144+
145+ let file = location. file ( ) ;
146+
147+ let line = buf1. format ( location. line ( ) ) ;
148+
149+ let column = buf2. format ( location. column ( ) ) ;
150+
151+ let payload = if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < & str > ( ) {
152+ s
153+ } else if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < String > ( ) {
154+ s. as_str ( )
155+ } else {
156+ ""
157+ } ;
158+
159+ let message = [
160+ "thread '" ,
161+ name,
162+ "' panicked at " ,
163+ file,
164+ ":" ,
165+ line,
166+ ":" ,
167+ column,
168+ ":" ,
169+ payload,
170+ ] ;
171+
172+ for ( idx, code_unit) in message
173+ . into_iter ( )
174+ . flat_map ( str:: encode_utf16)
175+ . take ( error_conf. Text . len ( ) - 1 )
176+ . chain ( std:: iter:: once ( 0 ) )
177+ . enumerate ( )
178+ {
179+ error_conf. Text [ idx] = code_unit;
180+ }
120181
121182 unsafe {
122- let _ = popup . launch_unchecked ( ) ;
183+ errorDisp ( error_conf ) ;
123184 }
124185 } else {
125186 old_hook ( panic_info) ;
0 commit comments