Skip to content

Commit 892c63a

Browse files
woubuclucasfernog
andauthored
feat(#2287): Add ExitRequested event to let users prevent app from exiting (#2293)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent fd80dd9 commit 892c63a

File tree

4 files changed

+71
-13
lines changed

4 files changed

+71
-13
lines changed

.changes/exit-requested-event.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"tauri": patch
3+
"tauri-runtime": patch
4+
"tauri-runtime-wry": patch
5+
---
6+
7+
Add `ExitRequested` event that allows preventing the app from exiting when all windows are closed, and an `AppHandle.exit()` function to exit the app manually.

core/tauri-runtime-wry/src/lib.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use tauri_runtime::{
1313
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
1414
DetachedWindow, PendingWindow, WindowEvent,
1515
},
16-
ClipboardManager, Dispatch, Error, GlobalShortcutManager, Icon, Result, RunEvent, RunIteration,
17-
Runtime, RuntimeHandle, UserAttentionType,
16+
ClipboardManager, Dispatch, Error, ExitRequestedEventAction, GlobalShortcutManager, Icon, Result,
17+
RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType,
1818
};
1919

2020
#[cfg(feature = "menu")]
@@ -2063,8 +2063,16 @@ fn on_window_close<'a>(
20632063
callback(RunEvent::WindowClose(webview.label));
20642064
}
20652065
if windows.is_empty() {
2066-
*control_flow = ControlFlow::Exit;
2067-
callback(RunEvent::Exit);
2066+
let (tx, rx) = channel();
2067+
callback(RunEvent::ExitRequested { tx });
2068+
2069+
let recv = rx.try_recv();
2070+
let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent));
2071+
2072+
if !should_prevent {
2073+
*control_flow = ControlFlow::Exit;
2074+
callback(RunEvent::Exit);
2075+
}
20682076
}
20692077
// TODO: tao does not fire the destroyed event properly
20702078
#[cfg(target_os = "linux")]

core/tauri-runtime/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ impl Icon {
170170
pub enum RunEvent {
171171
/// Event loop is exiting.
172172
Exit,
173+
/// Event loop is about to exit
174+
ExitRequested {
175+
tx: Sender<ExitRequestedEventAction>,
176+
},
173177
/// Window close was requested by the user.
174178
CloseRequested {
175179
/// The window label.
@@ -181,6 +185,13 @@ pub enum RunEvent {
181185
WindowClose(String),
182186
}
183187

188+
/// Action to take when the event loop is about to exit
189+
#[derive(Debug)]
190+
pub enum ExitRequestedEventAction {
191+
/// Prevent the event loop from exiting
192+
Prevent,
193+
}
194+
184195
/// A system tray event.
185196
pub enum SystemTrayEvent {
186197
MenuItemClick(u16),

core/tauri/src/app.rs

+41-9
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
runtime::{
1616
webview::{CustomProtocol, WebviewAttributes, WindowBuilder},
1717
window::{PendingWindow, WindowEvent},
18-
Dispatch, RunEvent, Runtime,
18+
Dispatch, ExitRequestedEventAction, RunEvent, Runtime,
1919
},
2020
sealed::{ManagerBase, RuntimeOrDispatch},
2121
Context, Invoke, InvokeError, Manager, StateManager, Window,
@@ -47,7 +47,19 @@ pub(crate) type GlobalWindowEventListener<R> = Box<dyn Fn(GlobalWindowEvent<R>)
4747
#[cfg(feature = "system-tray")]
4848
type SystemTrayEventListener<R> = Box<dyn Fn(&AppHandle<R>, tray::SystemTrayEvent) + Send + Sync>;
4949

50+
/// Api exposed on the `ExitRequested` event.
51+
#[derive(Debug)]
52+
pub struct ExitRequestApi(Sender<ExitRequestedEventAction>);
53+
54+
impl ExitRequestApi {
55+
/// Prevents the app from exiting
56+
pub fn prevent_exit(&self) {
57+
self.0.send(ExitRequestedEventAction::Prevent).unwrap();
58+
}
59+
}
60+
5061
/// Api exposed on the `CloseRequested` event.
62+
#[derive(Debug)]
5163
pub struct CloseRequestApi(Sender<bool>);
5264

5365
impl CloseRequestApi {
@@ -58,10 +70,17 @@ impl CloseRequestApi {
5870
}
5971

6072
/// An application event, triggered from the event loop.
73+
#[derive(Debug)]
6174
#[non_exhaustive]
6275
pub enum Event {
6376
/// Event loop is exiting.
6477
Exit,
78+
/// The app is about to exit
79+
#[non_exhaustive]
80+
ExitRequested {
81+
/// Event API
82+
api: ExitRequestApi,
83+
},
6584
/// Window close was requested by the user.
6685
#[non_exhaustive]
6786
CloseRequested {
@@ -223,6 +242,23 @@ impl<R: Runtime> AppHandle<R> {
223242
.register(plugin);
224243
Ok(())
225244
}
245+
246+
/// Exits the app
247+
pub fn exit(&self, exit_code: i32) {
248+
std::process::exit(exit_code);
249+
}
250+
251+
/// Runs necessary cleanup tasks before exiting the process
252+
fn cleanup_before_exit(&self) {
253+
#[cfg(shell_execute)]
254+
{
255+
crate::api::process::kill_children();
256+
}
257+
#[cfg(all(windows, feature = "system-tray"))]
258+
{
259+
let _ = self.remove_system_tray();
260+
}
261+
}
226262
}
227263

228264
impl<R: Runtime> Manager<R> for AppHandle<R> {}
@@ -356,14 +392,7 @@ impl<R: Runtime> App<R> {
356392
let manager = self.manager.clone();
357393
self.runtime.take().unwrap().run(move |event| match event {
358394
RunEvent::Exit => {
359-
#[cfg(shell_execute)]
360-
{
361-
crate::api::process::kill_children();
362-
}
363-
#[cfg(all(windows, feature = "system-tray"))]
364-
{
365-
let _ = app_handle.remove_system_tray();
366-
}
395+
app_handle.cleanup_before_exit();
367396
callback(&app_handle, Event::Exit);
368397
}
369398
_ => {
@@ -372,6 +401,9 @@ impl<R: Runtime> App<R> {
372401
&app_handle,
373402
match event {
374403
RunEvent::Exit => Event::Exit,
404+
RunEvent::ExitRequested { tx } => Event::ExitRequested {
405+
api: ExitRequestApi(tx),
406+
},
375407
RunEvent::CloseRequested { label, signal_tx } => Event::CloseRequested {
376408
label: label.parse().unwrap_or_else(|_| unreachable!()),
377409
api: CloseRequestApi(signal_tx),

0 commit comments

Comments
 (0)