Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 30 additions & 13 deletions winit-win32/src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
SC_MINIMIZE, SC_RESTORE, SIZE_MAXIMIZED, SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES,
SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, SetCursor, SetWindowPos,
SystemParametersInfoW, TranslateMessage, WHEEL_DELTA, WINDOWPOS, WM_CAPTURECHANGED, WM_CLOSE,
WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO,
WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION,
WM_INPUT, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN,
WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE,
WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN,
WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS,
WM_SETTINGCHANGE, WM_SIZE, WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TOUCH,
WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, WMSZ_BOTTOM,
WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
WM_CREATE, WM_DESTROY, WM_DPICHANGED, WM_ENDSESSION, WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE,
WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_SETCONTEXT,
WM_IME_STARTCOMPOSITION, WM_INPUT, WM_KEYDOWN, WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN,
WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE,
WM_MOUSEWHEEL, WM_NCACTIVATE, WM_NCCALCSIZE, WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN,
WM_PAINT, WM_POINTERDOWN, WM_POINTERUP, WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP,
WM_SETCURSOR, WM_SETFOCUS, WM_SETTINGCHANGE, WM_SIZE, WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN,
WM_SYSKEYUP, WM_TOUCH, WM_WINDOWPOSCHANGED, WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP,
WMSZ_BOTTOM, WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
WMSZ_TOPRIGHT, WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW,
WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
};
Expand Down Expand Up @@ -249,12 +249,12 @@ impl EventLoop {

pub fn run_app_on_demand<A: ApplicationHandler>(
&mut self,
mut app: A,
app: A,
) -> Result<(), EventLoopError> {
self.runner.clear_exit();

// SAFETY: The resetter is not leaked.
let _app_resetter = unsafe { self.runner.set_app(&mut app) };
let _app_resetter = unsafe { self.runner.set_app(app) };

let exit_code = loop {
self.wait_for_messages(None);
Expand All @@ -281,10 +281,10 @@ impl EventLoop {
pub fn pump_app_events<A: ApplicationHandler>(
&mut self,
timeout: Option<Duration>,
mut app: A,
app: A,
) -> PumpStatus {
// SAFETY: The resetter is not leaked.
let _app_resetter = unsafe { self.runner.set_app(&mut app) };
let _app_resetter = unsafe { self.runner.set_app(app) };

self.runner.wakeup();

Expand Down Expand Up @@ -2384,6 +2384,23 @@ unsafe extern "system" fn thread_event_target_callback(

unsafe { DefWindowProcW(window, msg, wparam, lparam) }
},
WM_ENDSESSION => {
// `wParam` is `FALSE` is for if the shutdown gets canceled,
// and we don't need to handle that case since we didn't do anything prior in response
// to `WM_QUERYENDSESSION`
if wparam == true as usize {
userdata.event_loop_runner.loop_destroyed();
// `WM_ENDSESSION` can be sent by Windows during shutdown or by Restart Manager
//
// - From Windows shutdown: Windows will shut us down after we return `0` here
// - From Restart Manager: Restart Manager only sends the message but will wait for
// us to shutdown ourselves
//
// So, we call `exit` here directly to align this behavior
std::process::exit(0)
}
0
},

_ if msg == USER_EVENT_MSG_ID.get() => {
// synthesis a placeholder UserEvent, so that if the callback is
Expand Down
25 changes: 13 additions & 12 deletions winit-win32/src/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::{ActiveEventLoop, ControlFlow, EventLoopThreadExecutor};
use crate::event_loop::{GWL_USERDATA, WindowData};
use crate::util::get_window_long;

type EventHandler = Cell<Option<&'static mut (dyn ApplicationHandler + 'static)>>;
type EventHandler = Cell<Option<Box<dyn ApplicationHandler>>>;

pub(crate) struct EventLoopRunner {
pub(super) thread_id: u32,
Expand Down Expand Up @@ -96,19 +96,16 @@ impl EventLoopRunner {
///
/// The returned type must not be leaked (as that would allow the application to be associated
/// with the runner for too long).
pub(crate) unsafe fn set_app<'app>(
&self,
app: &'app mut (dyn ApplicationHandler + 'app),
) -> impl Drop + 'app {
pub(crate) unsafe fn set_app<A: ApplicationHandler>(&self, app: A) -> impl Drop + use<A> {
let app = Box::new(app);
// Erase app lifetime, to allow storing on the event loop runner.
//
// SAFETY: Caller upholds that the lifetime of the closure is upheld, by not dropping the
// return type which resets it.
let f = unsafe {
mem::transmute::<
&'app mut (dyn ApplicationHandler + 'app),
&'static mut (dyn ApplicationHandler + 'static),
>(app)
mem::transmute::<Box<dyn ApplicationHandler>, Box<dyn ApplicationHandler + 'static>>(
app,
)
};

let old_event_handler = self.event_handler.replace(Some(f));
Expand Down Expand Up @@ -260,12 +257,12 @@ impl EventLoopRunner {
closure: impl FnOnce(&mut dyn ApplicationHandler, &dyn RootActiveEventLoop),
) {
self.catch_unwind(|| {
let event_handler = self.event_handler.take().expect(
let mut event_handler = self.event_handler.take().expect(
"either event handler is re-entrant (likely), or no event handler is registered \
(very unlikely)",
);

closure(event_handler, ActiveEventLoop::from_ref(self));
closure(&mut event_handler, ActiveEventLoop::from_ref(self));

assert!(self.event_handler.replace(Some(event_handler)).is_none());
});
Expand Down Expand Up @@ -333,14 +330,17 @@ impl EventLoopRunner {
self.call_new_events(true);
self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop));
self.last_events_cleared.set(Instant::now());
drop(self.event_handler.take());
},
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),

// State transitions that start the event handling process.
(Idle, HandlingMainEvents) => {
self.call_new_events(false);
},
(Idle, Destroyed) => {},
(Idle, Destroyed) => {
drop(self.event_handler.take());
},

(HandlingMainEvents, Idle) => {
// This is always the last event we dispatch before waiting for new events
Expand All @@ -350,6 +350,7 @@ impl EventLoopRunner {
(HandlingMainEvents, Destroyed) => {
self.call_event_handler(|app, event_loop| app.about_to_wait(event_loop));
self.last_events_cleared.set(Instant::now());
drop(self.event_handler.take());
},

(Destroyed, _) => panic!("cannot move state from Destroyed"),
Expand Down
7 changes: 6 additions & 1 deletion winit/src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ changelog entry.

### Added

- Add `keyboard` support for OpenHarmony.
- Add `keyboard` support for OpenHarmony.

### Changed

- On Windows, the `ApplicationHandler` passed to `EventLoop::run_app` is now dropped on receiving `WM_ENDSESSION` message (usually from system shutdown and Restart Manager)
- On Windows, the process will exit on receiving `WM_ENDSESSION` in reaction to Restart Manager
5 changes: 4 additions & 1 deletion winit/src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ impl EventLoop {
mut app: A,
) -> Result<(), EventLoopError> {
#[cfg(any(
windows_platform,
macos_platform,
android_platform,
orbital_platform,
Expand All @@ -232,6 +231,10 @@ impl EventLoop {
drop(app);
result
}
#[cfg(windows_platform)]
{
self.event_loop.run_app_on_demand(app)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made this a separate call on Windows to pass in the ownership of app instead of &mut app so we can drop it later, but I am not exactly sure why it was done like this

let result = self.event_loop.run_app_on_demand(&mut app);
// SAFETY: unsure that the state is dropped before the exit from the event loop.
drop(app);
result

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was done like that, because run_on_demand borrows, so you can not drop from it, since you'll be dropping & more likely, which won't work, but in run_app it's :static thus the actual value is being dropped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure that it's wrong too? run_app_on_demand doesn't borrow, and passing a reference prevents it from Drop-ing when e.g. NSApplicationDelegate is terminated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should I change this for all platforms?

}
#[cfg(web_platform)]
{
self.event_loop.register_app(app);
Expand Down