gpui: Support Windows Restart Manager shutdown (#62987)
Handle the `WM_QUERYENDSESSION` and `WM_ENDSESSION` messages, which are used by Windows when shutting down an application. For example, Restart Manager uses this mechanism to gracefully close applications (e.g. when installing an update to the application). Release Notes: - N/A
This commit is contained in:
1 parent
a86d40eda5
commit
8a6aaa73ef
10 files changed
+79
-16
No files matched your search
@@ -28,6 +28,7 @@ pub(crate) const WM_GPUI_FORCE_UPDATE_WINDOW: u32 = WM_USER + 5;
|
||||
pub(crate) const WM_GPUI_KEYBOARD_LAYOUT_CHANGED: u32 = WM_USER + 6;
|
||||
pub(crate) const WM_GPUI_GPU_DEVICE_LOST: u32 = WM_USER + 7;
|
||||
pub(crate) const WM_GPUI_KEYDOWN: u32 = WM_USER + 8;
|
||||
pub(crate) const WM_GPUI_END_SESSION: u32 = WM_USER + 9;
|
||||
|
||||
const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;
|
||||
|
||||
@@ -108,6 +109,8 @@ impl WindowsWindowInner {
|
||||
WM_PAINT => self.handle_paint_msg(handle),
|
||||
WM_CLOSE => self.handle_close_msg(),
|
||||
WM_DESTROY => self.handle_destroy_msg(handle),
|
||||
WM_QUERYENDSESSION => Some(1),
|
||||
WM_ENDSESSION => self.handle_end_session_msg(wparam),
|
||||
WM_MOUSEMOVE => self.handle_mouse_move_msg(handle, lparam, wparam),
|
||||
WM_MOUSELEAVE | WM_NCMOUSELEAVE => self.handle_mouse_leave_msg(),
|
||||
WM_NCMOUSEMOVE => self.handle_nc_mouse_move_msg(handle, lparam),
|
||||
@@ -170,6 +173,20 @@ impl WindowsWindowInner {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_end_session_msg(&self, wparam: WPARAM) -> Option<isize> {
|
||||
if wparam.0 != 0 {
|
||||
unsafe {
|
||||
SendMessageW(
|
||||
self.platform_window_handle,
|
||||
WM_GPUI_END_SESSION,
|
||||
Some(WPARAM(self.validation_number)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn handle_move_msg(&self, handle: HWND, lparam: LPARAM) -> Option<isize> {
|
||||
let origin = logical_point(
|
||||
lparam.signed_loword() as f32,
|
||||
|
||||
@@ -79,7 +79,7 @@ pub(crate) struct WindowsPlatformState {
|
||||
#[derive(Default)]
|
||||
struct PlatformCallbacks {
|
||||
open_urls: Cell<Option<Box<dyn FnMut(Vec<String>)>>>,
|
||||
quit: Cell<Option<Box<dyn FnMut()>>>,
|
||||
quit: Cell<Option<Box<dyn FnMut() -> bool>>>,
|
||||
reopen: Cell<Option<Box<dyn FnMut()>>>,
|
||||
app_menu_action: Cell<Option<Box<dyn FnMut(&dyn Action)>>>,
|
||||
will_open_app_menu: Cell<Option<Box<dyn FnMut()>>>,
|
||||
@@ -460,8 +460,12 @@ impl Platform for WindowsPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
self.inner
|
||||
.with_callback(|callbacks| &callbacks.quit, |callback| callback());
|
||||
self.inner.with_callback(
|
||||
|callbacks| &callbacks.quit,
|
||||
|callback| {
|
||||
callback();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn quit(&self) {
|
||||
@@ -667,7 +671,7 @@ impl Platform for WindowsPlatform {
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn on_quit(&self, callback: Box<dyn FnMut()>) {
|
||||
fn on_quit(&self, callback: Box<dyn FnMut() -> bool>) {
|
||||
self.inner.state.callbacks.quit.set(Some(callback));
|
||||
}
|
||||
|
||||
@@ -997,7 +1001,8 @@ impl WindowsPlatformInner {
|
||||
| WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD
|
||||
| WM_GPUI_DOCK_MENU_ACTION
|
||||
| WM_GPUI_KEYBOARD_LAYOUT_CHANGED
|
||||
| WM_GPUI_GPU_DEVICE_LOST => self.handle_gpui_events(msg, wparam, lparam),
|
||||
| WM_GPUI_GPU_DEVICE_LOST
|
||||
| WM_GPUI_END_SESSION => self.handle_gpui_events(msg, wparam, lparam),
|
||||
WM_POWERBROADCAST => self.handle_power_broadcast(wparam),
|
||||
_ => None,
|
||||
};
|
||||
@@ -1022,10 +1027,29 @@ impl WindowsPlatformInner {
|
||||
WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _),
|
||||
WM_GPUI_KEYBOARD_LAYOUT_CHANGED => self.handle_keyboard_layout_change(),
|
||||
WM_GPUI_GPU_DEVICE_LOST => self.handle_device_lost(lparam),
|
||||
WM_GPUI_END_SESSION => self.handle_end_session(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_end_session(&self) -> Option<isize> {
|
||||
let mut shutdown_completed = false;
|
||||
self.with_callback(
|
||||
|callbacks| &callbacks.quit,
|
||||
|callback| shutdown_completed = callback(),
|
||||
);
|
||||
log::logger().flush();
|
||||
if shutdown_completed {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// Shutdown couldn't run synchronously, since the AppCell is already borrowed.
|
||||
// Windows may terminate the application as soon as we return from this handler, but if we post a WM_QUIT message now,
|
||||
// we may get to gracefully shut down the app before we're terminated by the OS.
|
||||
unsafe { PostQuitMessage(0) };
|
||||
Some(0)
|
||||
}
|
||||
|
||||
fn close_one_window(&self, target_window: HWND) -> bool {
|
||||
let Some(all_windows) = self.raw_window_handles.upgrade() else {
|
||||
log::error!("Failed to upgrade raw window handles");
|
||||
|
||||
Reference in new issue
Block a user