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:
John Tur authored and GitHub committed 2026-08-24 02:59:15 +00:00
1 parent a86d40eda5
commit 8a6aaa73ef
10 files changed
+79 -16

No files matched your search

+17
View File
@@ -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,
+29 -5
View File
@@ -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");