@@ -42,7 +42,8 @@ use std::{
4242 borrow:: Cow ,
4343 collections:: HashMap ,
4444 fmt,
45- sync:: { mpsc:: Sender , Arc , MutexGuard } ,
45+ sync:: { mpsc:: Sender , Arc , Mutex , MutexGuard } ,
46+ thread:: ThreadId ,
4647} ;
4748
4849use crate :: { event:: EventId , runtime:: RuntimeHandle , Event , EventTarget } ;
@@ -73,14 +74,19 @@ pub const RESTART_EXIT_CODE: i32 = i32::MAX;
7374
7475/// Api exposed on the `ExitRequested` event.
7576#[ derive( Debug , Clone ) ]
76- pub struct ExitRequestApi ( Sender < ExitRequestedEventAction > ) ;
77+ pub struct ExitRequestApi {
78+ tx : Sender < ExitRequestedEventAction > ,
79+ code : Option < i32 > ,
80+ }
7781
7882impl ExitRequestApi {
7983 /// Prevents the app from exiting.
8084 ///
8185 /// **Note:** This is ignored when using [`AppHandle#method.restart`].
8286 pub fn prevent_exit ( & self ) {
83- self . 0 . send ( ExitRequestedEventAction :: Prevent ) . unwrap ( ) ;
87+ if self . code != Some ( RESTART_EXIT_CODE ) {
88+ self . tx . send ( ExitRequestedEventAction :: Prevent ) . unwrap ( ) ;
89+ }
8490 }
8591}
8692
@@ -339,6 +345,12 @@ impl<R: Runtime> AssetResolver<R> {
339345pub struct AppHandle < R : Runtime > {
340346 pub ( crate ) runtime_handle : R :: Handle ,
341347 pub ( crate ) manager : Arc < AppManager < R > > ,
348+ event_loop : Arc < Mutex < EventLoop > > ,
349+ }
350+
351+ #[ derive( Debug ) ]
352+ struct EventLoop {
353+ main_thread_id : ThreadId ,
342354}
343355
344356/// APIs specific to the wry runtime.
@@ -428,6 +440,7 @@ impl<R: Runtime> Clone for AppHandle<R> {
428440 Self {
429441 runtime_handle : self . runtime_handle . clone ( ) ,
430442 manager : self . manager . clone ( ) ,
443+ event_loop : self . event_loop . clone ( ) ,
431444 }
432445 }
433446}
@@ -522,10 +535,27 @@ impl<R: Runtime> AppHandle<R> {
522535 }
523536 }
524537
525- /// Restarts the app by triggering [`RunEvent::ExitRequested`] with code [`RESTART_EXIT_CODE`] and [`RunEvent::Exit`]..
538+ /// Restarts the app by triggering [`RunEvent::ExitRequested`] with code [`RESTART_EXIT_CODE`](crate::RESTART_EXIT_CODE) and [`RunEvent::Exit`].
539+ ///
540+ /// When this function is called on the main thread, we cannot guarantee the delivery of those events,
541+ /// so we skip them and directly restart the process.
526542 pub fn restart ( & self ) -> ! {
527- if self . runtime_handle . request_exit ( RESTART_EXIT_CODE ) . is_err ( ) {
543+ if self . event_loop . lock ( ) . unwrap ( ) . main_thread_id == std:: thread:: current ( ) . id ( ) {
544+ log:: debug!( "restart triggered on the main thread" ) ;
528545 self . cleanup_before_exit ( ) ;
546+ self . manager . notify_event_loop_exit ( ) ;
547+ } else {
548+ log:: debug!( "restart triggered from a separate thread" ) ;
549+ // we're running on a separate thread, so we must trigger the exit request and wait for it to finish
550+ match self . runtime_handle . request_exit ( RESTART_EXIT_CODE ) {
551+ Ok ( ( ) ) => {
552+ let _impede = self . manager . wait_for_event_loop_exit ( ) ;
553+ }
554+ Err ( e) => {
555+ log:: error!( "failed to request exit: {e}" ) ;
556+ self . cleanup_before_exit ( ) ;
557+ }
558+ }
529559 }
530560 crate :: process:: restart ( & self . env ( ) ) ;
531561 }
@@ -1125,6 +1155,9 @@ impl<R: Runtime> App<R> {
11251155 pub fn run < F : FnMut ( & AppHandle < R > , RunEvent ) + ' static > ( mut self , mut callback : F ) {
11261156 let app_handle = self . handle ( ) . clone ( ) ;
11271157 let manager = self . manager . clone ( ) ;
1158+
1159+ app_handle. event_loop . lock ( ) . unwrap ( ) . main_thread_id = std:: thread:: current ( ) . id ( ) ;
1160+
11281161 self . runtime . take ( ) . unwrap ( ) . run ( move |event| match event {
11291162 RuntimeRunEvent :: Ready => {
11301163 if let Err ( e) = setup ( & mut self ) {
@@ -1137,6 +1170,7 @@ impl<R: Runtime> App<R> {
11371170 let event = on_event_loop_event ( & app_handle, RuntimeRunEvent :: Exit , & manager) ;
11381171 callback ( & app_handle, event) ;
11391172 app_handle. cleanup_before_exit ( ) ;
1173+ manager. notify_event_loop_exit ( ) ;
11401174 }
11411175 _ => {
11421176 let event = on_event_loop_event ( & app_handle, event, & manager) ;
@@ -1178,6 +1212,8 @@ impl<R: Runtime> App<R> {
11781212 }
11791213 }
11801214
1215+ app_handle. event_loop . lock ( ) . unwrap ( ) . main_thread_id = std:: thread:: current ( ) . id ( ) ;
1216+
11811217 self . runtime . as_mut ( ) . unwrap ( ) . run_iteration ( move |event| {
11821218 let event = on_event_loop_event ( & app_handle, event, & manager) ;
11831219 callback ( & app_handle, event) ;
@@ -2016,6 +2052,9 @@ tauri::Builder::default()
20162052 handle : AppHandle {
20172053 runtime_handle,
20182054 manager,
2055+ event_loop : Arc :: new ( Mutex :: new ( EventLoop {
2056+ main_thread_id : std:: thread:: current ( ) . id ( ) ,
2057+ } ) ) ,
20192058 } ,
20202059 ran_setup : false ,
20212060 } ;
@@ -2207,7 +2246,7 @@ fn on_event_loop_event<R: Runtime>(
22072246 RuntimeRunEvent :: Exit => RunEvent :: Exit ,
22082247 RuntimeRunEvent :: ExitRequested { code, tx } => RunEvent :: ExitRequested {
22092248 code,
2210- api : ExitRequestApi ( tx ) ,
2249+ api : ExitRequestApi { tx , code } ,
22112250 } ,
22122251 RuntimeRunEvent :: WindowEvent { label, event } => RunEvent :: WindowEvent {
22132252 label,
0 commit comments