Skip to content

Commit 7c7fcc9

Browse files
committed
Very rough usage of CFRunLoop
1 parent 3c7a52f commit 7c7fcc9

File tree

5 files changed

+522
-48
lines changed

5 files changed

+522
-48
lines changed
+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use cocoa::base::id;
2+
use objc::{runtime::{Class, Object, Sel, BOOL, YES}, declare::ClassDecl};
3+
4+
use platform_impl::platform::event_loop::HANDLER;
5+
6+
pub struct AppDelegateClass(pub *const Class);
7+
unsafe impl Send for AppDelegateClass {}
8+
unsafe impl Sync for AppDelegateClass {}
9+
10+
lazy_static! {
11+
pub static ref APP_DELEGATE_CLASS: AppDelegateClass = unsafe {
12+
let superclass = class!(NSResponder);
13+
let mut decl = ClassDecl::new("WinitAppDelegate", superclass).unwrap();
14+
15+
decl.add_method(
16+
sel!(applicationDidFinishLaunching:),
17+
did_finish_launching as extern fn(&Object, Sel, id) -> BOOL,
18+
);
19+
decl.add_method(
20+
sel!(applicationDidBecomeActive:),
21+
did_become_active as extern fn(&Object, Sel, id),
22+
);
23+
decl.add_method(
24+
sel!(applicationWillResignActive:),
25+
will_resign_active as extern fn(&Object, Sel, id),
26+
);
27+
decl.add_method(
28+
sel!(applicationWillEnterForeground:),
29+
will_enter_foreground as extern fn(&Object, Sel, id),
30+
);
31+
decl.add_method(
32+
sel!(applicationDidEnterBackground:),
33+
did_enter_background as extern fn(&Object, Sel, id),
34+
);
35+
decl.add_method(
36+
sel!(applicationWillTerminate:),
37+
will_terminate as extern fn(&Object, Sel, id),
38+
);
39+
40+
AppDelegateClass(decl.register())
41+
};
42+
}
43+
44+
extern fn did_finish_launching(_: &Object, _: Sel, _: id) -> BOOL {
45+
trace!("Triggered `didFinishLaunching`");
46+
HANDLER.lock().unwrap().launched();
47+
trace!("Completed `didFinishLaunching`");
48+
YES
49+
}
50+
51+
extern fn did_become_active(_: &Object, _: Sel, _: id) {
52+
trace!("Triggered `didBecomeActive`");
53+
/*unsafe {
54+
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(false))
55+
}*/
56+
trace!("Completed `didBecomeActive`");
57+
}
58+
59+
extern fn will_resign_active(_: &Object, _: Sel, _: id) {
60+
trace!("Triggered `willResignActive`");
61+
/*unsafe {
62+
HANDLER.lock().unwrap().handle_nonuser_event(Event::Suspended(true))
63+
}*/
64+
trace!("Completed `willResignActive`");
65+
}
66+
67+
extern fn will_enter_foreground(_: &Object, _: Sel, _: id) {
68+
trace!("Triggered `willEnterForeground`");
69+
trace!("Completed `willEnterForeground`");
70+
}
71+
72+
extern fn did_enter_background(_: &Object, _: Sel, _: id) {
73+
trace!("Triggered `didEnterBackground`");
74+
trace!("Completed `didEnterBackground`");
75+
}
76+
77+
extern fn will_terminate(_: &Object, _: Sel, _: id) {
78+
trace!("Triggered `willTerminate`");
79+
/*unsafe {
80+
let app: id = msg_send![class!(UIApplication), sharedApplication];
81+
let windows: id = msg_send![app, windows];
82+
let windows_enum: id = msg_send![windows, objectEnumerator];
83+
let mut events = Vec::new();
84+
loop {
85+
let window: id = msg_send![windows_enum, nextObject];
86+
if window == nil {
87+
break
88+
}
89+
let is_winit_window: BOOL = msg_send![window, isKindOfClass:class!(WinitUIWindow)];
90+
if is_winit_window == YES {
91+
events.push(Event::WindowEvent {
92+
window_id: RootWindowId(window.into()),
93+
event: WindowEvent::Destroyed,
94+
});
95+
}
96+
}
97+
HANDLER.lock().unwrap().handle_nonuser_events(events);
98+
HANDLER.lock().unwrap().terminated();
99+
}*/
100+
trace!("Completed `willTerminate`");
101+
}

src/platform_impl/macos/event_loop.rs

+154-47
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{
2-
collections::VecDeque, hint::unreachable_unchecked, marker::PhantomData,
3-
mem, os::raw::*, process::exit, sync::{Arc, Mutex, Weak},
2+
collections::VecDeque, fmt::{self, Debug, Formatter},
3+
hint::unreachable_unchecked, marker::PhantomData, mem, os::raw::*,
4+
process::exit, sync::{Arc, Mutex, Weak},
45
};
56

67
use cocoa::{
@@ -21,7 +22,9 @@ use {
2122
window,
2223
};
2324
use platform_impl::platform::{
24-
DEVICE_ID, monitor::{self, MonitorHandle}, window::UnownedWindow,
25+
app_delegate::APP_DELEGATE_CLASS, DEVICE_ID, monitor::{self, MonitorHandle},
26+
observer::{EventLoopWaker, setup_control_flow_observers},
27+
util::IdRef, window::UnownedWindow,
2528
};
2629

2730
#[derive(Default)]
@@ -87,6 +90,118 @@ impl WindowList {
8790
}
8891
}
8992

93+
lazy_static! {
94+
pub static ref HANDLER: Mutex<Handler> = Default::default();
95+
}
96+
97+
#[derive(Default)]
98+
pub struct Handler {
99+
control_flow: ControlFlow,
100+
control_flow_prev: ControlFlow,
101+
callback: Option<Box<dyn EventHandler>>,
102+
waker: EventLoopWaker,
103+
}
104+
105+
unsafe impl Send for Handler {}
106+
unsafe impl Sync for Handler {}
107+
108+
impl Handler {
109+
pub fn launched(&mut self) {
110+
self.waker.start();
111+
if let Some(ref mut callback) = self.callback {
112+
callback.handle_nonuser_event(Event::NewEvents(StartCause::Init), &mut self.control_flow);
113+
}
114+
}
115+
116+
pub fn wakeup(&mut self) {
117+
self.control_flow_prev = self.control_flow;
118+
let cause = match self.control_flow {
119+
ControlFlow::Poll => StartCause::Poll,
120+
/*ControlFlow::Wait => StartCause::WaitCancelled {
121+
start,
122+
requested_resume: None,
123+
},
124+
ControlFlow::WaitUntil(requested_resume) => {
125+
if Instant::now() >= requested_resume {
126+
StartCause::ResumeTimeReached {
127+
start,
128+
requested_resume,
129+
}
130+
} else {
131+
StartCause::WaitCancelled {
132+
start,
133+
requested_resume: Some(requested_resume),
134+
}
135+
}
136+
},*/
137+
ControlFlow::Exit => panic!("unexpected `ControlFlow::Exit`"),
138+
_ => unimplemented!(),
139+
};
140+
if let Some(ref mut callback) = self.callback {
141+
callback.handle_nonuser_event(Event::NewEvents(cause), &mut self.control_flow);
142+
}
143+
}
144+
145+
pub fn cleared(&mut self) {
146+
if let Some(ref mut callback) = self.callback {
147+
callback.handle_nonuser_event(Event::EventsCleared, &mut self.control_flow);
148+
}
149+
let old = self.control_flow_prev;
150+
let new = self.control_flow;
151+
match (old, new) {
152+
(ControlFlow::Poll, ControlFlow::Poll) => (),
153+
(ControlFlow::Wait, ControlFlow::Wait) => (),
154+
(ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant)) if old_instant == new_instant => (),
155+
(_, ControlFlow::Wait) => self.waker.stop(),
156+
(_, ControlFlow::WaitUntil(new_instant)) => self.waker.start_at(new_instant),
157+
(_, ControlFlow::Poll) => self.waker.start(),
158+
(_, ControlFlow::Exit) => (),
159+
}
160+
}
161+
}
162+
163+
pub trait EventHandler: Debug {
164+
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
165+
//fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
166+
}
167+
168+
struct EventLoopHandler<F, T: 'static> {
169+
callback: F,
170+
event_loop: RootELW<T>,
171+
}
172+
173+
impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
174+
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
175+
formatter.debug_struct("EventLoopHandler")
176+
.field("event_loop", &self.event_loop)
177+
.finish()
178+
}
179+
}
180+
181+
impl<F, T> EventHandler for EventLoopHandler<F, T>
182+
where
183+
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
184+
T: 'static,
185+
{
186+
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
187+
(self.callback)(
188+
event.userify(),
189+
&self.event_loop,
190+
control_flow,
191+
);
192+
}
193+
194+
/*fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
195+
for event in self.event_loop.inner.receiver.try_iter() {
196+
(self.callback)(
197+
Event::UserEvent(event),
198+
&self.event_loop,
199+
control_flow,
200+
);
201+
}
202+
}*/
203+
}
204+
90205
pub struct EventLoopWindowTarget<T: 'static> {
91206
pub pending_events: Arc<Mutex<PendingEvents>>,
92207
pub window_list: Arc<Mutex<WindowList>>,
@@ -105,19 +220,35 @@ impl<T> Default for EventLoopWindowTarget<T> {
105220

106221
pub struct EventLoop<T: 'static> {
107222
elw_target: RootELW<T>,
223+
delegate: IdRef,
108224
modifiers: Modifiers,
109225
}
110226

111227
impl<T> EventLoop<T> {
112228
pub fn new() -> Self {
113-
// Mark this thread as the main thread of the Cocoa event system.
114-
//
115-
// This must be done before any worker threads get a chance to call it
116-
// (e.g., via `EventLoopProxy::wakeup()`), causing a wrong thread to be
117-
// marked as the main thread.
118-
unsafe { NSApp() };
229+
let delegate = unsafe {
230+
if !msg_send![class!(NSThread), isMainThread] {
231+
// This check should be in `new` instead
232+
panic!("Events can only be polled from the main thread on macOS");
233+
}
234+
235+
// Mark this thread as the main thread of the Cocoa event system.
236+
//
237+
// This must be done before any worker threads get a chance to call it
238+
// (e.g., via `EventLoopProxy::wakeup()`), causing a wrong thread to be
239+
// marked as the main thread.
240+
let app = NSApp();
241+
242+
let delegate = IdRef::new(msg_send![APP_DELEGATE_CLASS.0, new]);
243+
let pool = NSAutoreleasePool::new(nil);
244+
let _: () = msg_send![app, setDelegate:*delegate];
245+
let _: () = msg_send![pool, drain];
246+
delegate
247+
};
248+
setup_control_flow_observers();
119249
EventLoop {
120250
elw_target: RootELW::new(Default::default()),
251+
delegate, // is this necessary?
121252
modifiers: Default::default(),
122253
}
123254
}
@@ -139,18 +270,8 @@ impl<T> EventLoop<T> {
139270
pub fn run<F>(mut self, mut callback: F) -> !
140271
where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
141272
{
142-
unsafe {
143-
if !msg_send![class!(NSThread), isMainThread] {
144-
panic!("Events can only be polled from the main thread on macOS");
145-
}
146-
}
147-
148-
let mut control_flow = Default::default();
149-
let mut cause = StartCause::Init;
150-
273+
/*
151274
loop {
152-
callback(Event::NewEvents(cause), self.window_target(), &mut control_flow);
153-
154275
{
155276
trace!("Locked pending events in `run`");
156277
let mut pending = self.elw_target
@@ -169,38 +290,24 @@ impl<T> EventLoop<T> {
169290
}
170291
}
171292
172-
let maybe_event = unsafe {
173-
let pool = NSAutoreleasePool::new(nil);
174-
175-
// Wait for the next event. Note that this function blocks during resize.
176-
let ns_event = NSApp().nextEventMatchingMask_untilDate_inMode_dequeue_(
177-
NSEventMask::NSAnyEventMask.bits() | NSEventMask::NSEventMaskPressure.bits(),
178-
NSDate::distantFuture(nil),
179-
NSDefaultRunLoopMode,
180-
YES,
181-
);
182-
183-
let maybe_event = self.translate_event(ns_event);
184-
185-
// Release the pool before calling the top callback in case the user calls either
186-
// `run_forever` or `poll_events` within the callback.
187-
let _: () = msg_send![pool, release];
188-
189-
maybe_event
190-
};
191-
192-
if let Some(event) = maybe_event {
193-
callback(event.userify(), self.window_target(), &mut control_flow);
194-
}
195-
196-
callback(Event::EventsCleared, self.window_target(), &mut control_flow);
197-
198293
if let ControlFlow::Exit = control_flow {
199294
callback(Event::LoopDestroyed, self.window_target(), &mut control_flow);
200295
exit(0);
201296
}
297+
}
298+
*/
202299

203-
cause = StartCause::Poll;
300+
unsafe {
301+
let _pool = NSAutoreleasePool::new(nil);
302+
let app = NSApp();
303+
assert!(!app.is_null());
304+
HANDLER.lock().unwrap().callback = Some(Box::new(EventLoopHandler {
305+
callback,
306+
event_loop: self.elw_target,
307+
}));
308+
let _: () = msg_send![app, run];
309+
// This is probably wrong
310+
unreachable_unchecked()
204311
}
205312
}
206313

src/platform_impl/macos/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#![cfg(target_os = "macos")]
22

3+
mod app_delegate;
34
mod event_loop;
45
mod ffi;
56
mod monitor;
7+
mod observer;
68
mod util;
79
mod view;
810
mod window;

0 commit comments

Comments
 (0)