Skip to content

Commit c04ace5

Browse files
committed
Add initial implementation of run_embedded
1 parent 324c4c4 commit c04ace5

File tree

3 files changed

+119
-37
lines changed

3 files changed

+119
-37
lines changed

src/platform/windows.rs

+42-3
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,20 @@ use winapi::shared::windef::HWND;
99

1010
use crate::{
1111
dpi::PhysicalSize,
12-
event::DeviceId,
13-
event_loop::{EventLoop, EventLoopWindowTarget},
12+
event::{DeviceId, Event},
13+
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
1414
monitor::MonitorHandle,
15-
platform_impl::{EventLoop as WindowsEventLoop, WinIcon},
15+
platform_impl::{EventLoop as WindowsEventLoop, WinIcon, EventLoopEmbedded as WindowsEventLoopEmbedded},
1616
window::{BadIcon, Icon, Window, WindowBuilder},
1717
};
1818

19+
pub struct EventLoopEmbedded<'a, T: 'static> {
20+
p: WindowsEventLoopEmbedded<'a, T>,
21+
}
22+
1923
/// Additional methods on `EventLoop` that are specific to Windows.
2024
pub trait EventLoopExtWindows {
25+
type UserEvent;
2126
/// Creates an event loop off of the main thread.
2227
///
2328
/// # `Window` caveats
@@ -41,9 +46,24 @@ pub trait EventLoopExtWindows {
4146
fn new_dpi_unaware_any_thread() -> Self
4247
where
4348
Self: Sized;
49+
50+
/// Initialize an event loop that can run through somebody else's event pump.
51+
///
52+
/// This does *not* dispatch events without external assistance! Other code must be running a
53+
/// [Win32 message loop](https://docs.microsoft.com/en-us/windows/win32/learnwin32/window-messages),
54+
/// and the `event_handler` closure will be called while the `EventLoopEmbedded` is in scope.
55+
/// The loop can come from any code that calls the native Win32 message loop functions - for
56+
/// example, this could be used to embed a Winit message loop in an SDL or GLFW application, or
57+
/// create a DAW plugin.
58+
///
59+
/// TODO: REWRITE `exit_requested` and `resume_panic_if_necessary` as trait functions.
60+
fn run_embedded<'a, F>(self, event_handler: F) -> EventLoopEmbedded<'a, Self::UserEvent>
61+
where
62+
F: 'a + FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
4463
}
4564

4665
impl<T> EventLoopExtWindows for EventLoop<T> {
66+
type UserEvent = T;
4767
#[inline]
4868
fn new_any_thread() -> Self {
4969
EventLoop {
@@ -67,6 +87,25 @@ impl<T> EventLoopExtWindows for EventLoop<T> {
6787
_marker: ::std::marker::PhantomData,
6888
}
6989
}
90+
91+
fn run_embedded<'a, F>(self, event_handler: F) -> EventLoopEmbedded<'a, Self::UserEvent>
92+
where
93+
F: 'a + FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow)
94+
{
95+
EventLoopEmbedded {
96+
p: self.event_loop.run_embedded(event_handler)
97+
}
98+
}
99+
}
100+
101+
impl<T> EventLoopEmbedded<'_, T> {
102+
pub fn exit_requested(&self) -> bool {
103+
self.p.exit_requested()
104+
}
105+
106+
pub fn resume_panic_if_necessary(&self) {
107+
self.p.resume_panic_if_necessary()
108+
}
70109
}
71110

72111
/// Additional methods on `EventLoopWindowTarget` that are specific to Windows.

src/platform_impl/windows/event_loop.rs

+76-33
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl<T> ThreadMsgTargetSubclassInput<T> {
104104

105105
pub struct EventLoop<T: 'static> {
106106
thread_msg_sender: Sender<T>,
107-
window_target: RootELW<T>,
107+
window_target: Rc<RootELW<T>>,
108108
}
109109

110110
pub struct EventLoopWindowTarget<T: 'static> {
@@ -113,6 +113,11 @@ pub struct EventLoopWindowTarget<T: 'static> {
113113
pub(crate) runner_shared: EventLoopRunnerShared<T>,
114114
}
115115

116+
pub struct EventLoopEmbedded<'a, T: 'static> {
117+
window_target: Rc<RootELW<T>>,
118+
_function_lifetime: PhantomData<&'a ()>,
119+
}
120+
116121
macro_rules! main_thread_check {
117122
($fn_name:literal) => {{
118123
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
@@ -163,14 +168,14 @@ impl<T: 'static> EventLoop<T> {
163168

164169
EventLoop {
165170
thread_msg_sender,
166-
window_target: RootELW {
171+
window_target: Rc::new(RootELW {
167172
p: EventLoopWindowTarget {
168173
thread_id,
169174
thread_msg_target,
170175
runner_shared,
171176
},
172177
_marker: PhantomData,
173-
},
178+
}),
174179
}
175180
}
176181

@@ -186,49 +191,62 @@ impl<T: 'static> EventLoop<T> {
186191
::std::process::exit(0);
187192
}
188193

189-
pub fn run_return<F>(&mut self, mut event_handler: F)
194+
pub fn run_return<F>(&mut self, event_handler: F)
190195
where
191196
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
192197
{
193-
let event_loop_windows_ref = &self.window_target;
194-
195-
unsafe {
196-
self.window_target
197-
.p
198-
.runner_shared
199-
.set_event_handler(move |event, control_flow| {
200-
event_handler(event, event_loop_windows_ref, control_flow)
201-
});
202-
}
203-
204-
let runner = &self.window_target.p.runner_shared;
205-
206198
unsafe {
199+
let runner = self.embedded_runner(event_handler);
207200
let mut msg = mem::zeroed();
208201

209-
runner.poll();
210202
'main: loop {
211203
if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) {
212204
break 'main;
213205
}
214206
winuser::TranslateMessage(&mut msg);
215207
winuser::DispatchMessageW(&mut msg);
216208

217-
if let Err(payload) = runner.take_panic_error() {
218-
runner.reset_runner();
219-
panic::resume_unwind(payload);
220-
}
209+
runner.resume_panic_if_necessary();
221210

222-
if runner.control_flow() == ControlFlow::Exit && !runner.handling_events() {
211+
if runner.exit_requested() {
223212
break 'main;
224213
}
225214
}
226215
}
216+
}
227217

218+
pub fn run_embedded<'a, F>(mut self, event_handler: F) -> EventLoopEmbedded<'a, T>
219+
where
220+
F: 'a + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow)
221+
{
228222
unsafe {
229-
runner.call_event_handler(Event::LoopDestroyed);
223+
self.embedded_runner(event_handler)
224+
}
225+
}
226+
227+
unsafe fn embedded_runner<'a, F>(
228+
&mut self,
229+
mut event_handler: F
230+
) -> EventLoopEmbedded<'a, T>
231+
where
232+
F: 'a + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow)
233+
{
234+
let window_target = self.window_target.clone();
235+
let event_loop_windows_ptr = &*window_target as *const RootELW<T>;
236+
237+
window_target
238+
.p
239+
.runner_shared
240+
.set_event_handler(move |event, control_flow| {
241+
event_handler(event, &*event_loop_windows_ptr, control_flow)
242+
});
243+
244+
window_target.p.runner_shared.poll();
245+
246+
EventLoopEmbedded {
247+
window_target,
248+
_function_lifetime: PhantomData,
230249
}
231-
runner.reset_runner();
232250
}
233251

234252
pub fn create_proxy(&self) -> EventLoopProxy<T> {
@@ -239,6 +257,39 @@ impl<T: 'static> EventLoop<T> {
239257
}
240258
}
241259

260+
impl<T> EventLoopEmbedded<'_, T> {
261+
pub fn exit_requested(&self) -> bool {
262+
let runner = &self.window_target.p.runner_shared;
263+
runner.control_flow() == ControlFlow::Exit && !runner.handling_events()
264+
}
265+
266+
pub fn resume_panic_if_necessary(&self) {
267+
let runner = &self.window_target.p.runner_shared;
268+
269+
if let Err(payload) = runner.take_panic_error() {
270+
runner.reset_runner();
271+
panic::resume_unwind(payload);
272+
}
273+
}
274+
}
275+
276+
impl<T> Drop for EventLoopEmbedded<'_, T> {
277+
fn drop(&mut self) {
278+
unsafe {
279+
self.window_target.p.runner_shared.call_event_handler(Event::LoopDestroyed);
280+
self.window_target.p.runner_shared.reset_runner();
281+
}
282+
}
283+
}
284+
285+
impl<T> Drop for EventLoopWindowTarget<T> {
286+
fn drop(&mut self) {
287+
unsafe {
288+
winuser::DestroyWindow(self.thread_msg_target);
289+
}
290+
}
291+
}
292+
242293
impl<T> EventLoopWindowTarget<T> {
243294
#[inline(always)]
244295
pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
@@ -380,14 +431,6 @@ fn dur2timeout(dur: Duration) -> DWORD {
380431
.unwrap_or(winbase::INFINITE)
381432
}
382433

383-
impl<T> Drop for EventLoop<T> {
384-
fn drop(&mut self) {
385-
unsafe {
386-
winuser::DestroyWindow(self.window_target.p.thread_msg_target);
387-
}
388-
}
389-
}
390-
391434
pub(crate) struct EventLoopThreadExecutor {
392435
thread_id: DWORD,
393436
target_window: HWND,

src/platform_impl/windows/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use winapi::{self, shared::windef::HWND};
44

55
pub use self::{
6-
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget},
6+
event_loop::{EventLoop, EventLoopEmbedded, EventLoopProxy, EventLoopWindowTarget},
77
icon::WinIcon,
88
monitor::{MonitorHandle, VideoMode},
99
window::Window,

0 commit comments

Comments
 (0)