Skip to content

Commit 27e475c

Browse files
committed
User events
1 parent 157418d commit 27e475c

File tree

6 files changed

+190
-91
lines changed

6 files changed

+190
-91
lines changed

src/platform_impl/macos/app_state.rs

+29-11
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ impl Event<Never> {
2727

2828
pub trait EventHandler: Debug {
2929
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
30-
//fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
30+
fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
3131
}
3232

3333
struct EventLoopHandler<F, T: 'static> {
3434
callback: F,
35+
will_exit: bool,
3536
window_target: RootWindowTarget<T>,
3637
}
3738

38-
impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
39+
impl<F, T> Debug for EventLoopHandler<F, T> {
3940
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
4041
formatter.debug_struct("EventLoopHandler")
4142
.field("window_target", &self.window_target)
@@ -54,17 +55,27 @@ where
5455
&self.window_target,
5556
control_flow,
5657
);
58+
self.will_exit |= *control_flow == ControlFlow::Exit;
59+
if self.will_exit {
60+
*control_flow = ControlFlow::Exit;
61+
}
5762
}
5863

59-
/*fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
60-
for event in self.event_loop.inner.receiver.try_iter() {
64+
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
65+
let mut will_exit = self.will_exit;
66+
for event in self.window_target.inner.receiver.try_iter() {
6167
(self.callback)(
6268
Event::UserEvent(event),
63-
&self.event_loop,
69+
&self.window_target,
6470
control_flow,
6571
);
72+
will_exit |= *control_flow == ControlFlow::Exit;
73+
if will_exit {
74+
*control_flow = ControlFlow::Exit;
75+
}
6676
}
67-
}*/
77+
self.will_exit = will_exit;
78+
}
6879
}
6980

7081
#[derive(Default)]
@@ -98,7 +109,7 @@ impl Handler {
98109
self.ready.store(true, Ordering::Release);
99110
}
100111

101-
fn is_control_flow_exit(&self) -> bool {
112+
fn should_exit(&self) -> bool {
102113
*self.control_flow.lock().unwrap() == ControlFlow::Exit
103114
}
104115

@@ -134,6 +145,14 @@ impl Handler {
134145
);
135146
}
136147
}
148+
149+
fn handle_user_events(&self) {
150+
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
151+
callback.handle_user_events(
152+
&mut *self.control_flow.lock().unwrap(),
153+
);
154+
}
155+
}
137156
}
138157

139158
pub enum AppState {}
@@ -146,6 +165,7 @@ impl AppState {
146165
{
147166
*HANDLER.callback.lock().unwrap() = Some(Box::new(EventLoopHandler {
148167
callback,
168+
will_exit: false,
149169
window_target,
150170
}));
151171
}
@@ -203,14 +223,12 @@ impl AppState {
203223

204224
pub fn cleared() {
205225
if !HANDLER.is_ready() { return }
206-
let mut will_stop = HANDLER.is_control_flow_exit();
226+
HANDLER.handle_user_events();
207227
for event in HANDLER.take_events() {
208228
HANDLER.handle_nonuser_event(event);
209-
will_stop |= HANDLER.is_control_flow_exit();
210229
}
211230
HANDLER.handle_nonuser_event(Event::EventsCleared);
212-
will_stop |= HANDLER.is_control_flow_exit();
213-
if will_stop {
231+
if HANDLER.should_exit() {
214232
let _: () = unsafe { msg_send![NSApp(), stop:nil] };
215233
return
216234
}

src/platform_impl/macos/event_loop.rs

+42-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::{
2-
collections::VecDeque, marker::PhantomData, process,
2+
collections::VecDeque, mem, os::raw::c_void, process, ptr, sync::mpsc,
33
};
44

55
use cocoa::{appkit::NSApp, base::{id, nil}, foundation::NSAutoreleasePool};
@@ -11,16 +11,18 @@ use {
1111
use platform_impl::platform::{
1212
app::APP_CLASS, app_delegate::APP_DELEGATE_CLASS,
1313
app_state::AppState, monitor::{self, MonitorHandle},
14-
observer::setup_control_flow_observers, util::IdRef,
14+
observer::*, util::IdRef,
1515
};
1616

1717
pub struct EventLoopWindowTarget<T: 'static> {
18-
_marker: PhantomData<T>,
18+
pub sender: mpsc::Sender<T>, // this is only here to be cloned elsewhere
19+
pub receiver: mpsc::Receiver<T>,
1920
}
2021

2122
impl<T> Default for EventLoopWindowTarget<T> {
2223
fn default() -> Self {
23-
EventLoopWindowTarget { _marker: PhantomData }
24+
let (sender, receiver) = mpsc::channel();
25+
EventLoopWindowTarget { sender, receiver }
2426
}
2527
}
2628

@@ -90,23 +92,50 @@ impl<T> EventLoop<T> {
9092
}
9193

9294
pub fn create_proxy(&self) -> Proxy<T> {
93-
Proxy::default()
95+
Proxy::new(self.window_target.inner.sender.clone())
9496
}
9597
}
9698

9799
#[derive(Clone)]
98100
pub struct Proxy<T> {
99-
_marker: PhantomData<T>,
101+
sender: mpsc::Sender<T>,
102+
source: CFRunLoopSourceRef,
100103
}
101104

102-
impl<T> Default for Proxy<T> {
103-
fn default() -> Self {
104-
Proxy { _marker: PhantomData }
105-
}
106-
}
105+
unsafe impl<T> Send for Proxy<T> {}
106+
unsafe impl<T> Sync for Proxy<T> {}
107107

108108
impl<T> Proxy<T> {
109-
pub fn send_event(&self, _event: T) -> Result<(), EventLoopClosed> {
110-
unimplemented!();
109+
fn new(sender: mpsc::Sender<T>) -> Self {
110+
unsafe {
111+
// just wakeup the eventloop
112+
extern "C" fn event_loop_proxy_handler(_: *mut c_void) {}
113+
114+
// adding a Source to the main CFRunLoop lets us wake it up and
115+
// process user events through the normal OS EventLoop mechanisms.
116+
let rl = CFRunLoopGetMain();
117+
let mut context: CFRunLoopSourceContext = mem::zeroed();
118+
context.perform = event_loop_proxy_handler;
119+
let source = CFRunLoopSourceCreate(
120+
ptr::null_mut(),
121+
CFIndex::max_value() - 1,
122+
&mut context,
123+
);
124+
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
125+
CFRunLoopWakeUp(rl);
126+
127+
Proxy { sender, source }
128+
}
129+
}
130+
131+
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
132+
self.sender.send(event).map_err(|_| EventLoopClosed)?;
133+
unsafe {
134+
// let the main thread know there's a new event
135+
CFRunLoopSourceSignal(self.source);
136+
let rl = CFRunLoopGetMain();
137+
CFRunLoopWakeUp(rl);
138+
}
139+
Ok(())
111140
}
112141
}

src/platform_impl/macos/observer.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ impl Default for EventLoopWaker {
215215
fn default() -> EventLoopWaker {
216216
extern fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {}
217217
unsafe {
218-
// create a timer with a 1microsec interval (1ns does not work) to mimic polling.
218+
// create a timer with a 1µs interval (1ns does not work) to mimic polling.
219219
// it is initially setup with a first fire time really far into the
220220
// future, but that gets changed to fire immediatley in did_finish_launching
221221
let timer = CFRunLoopTimerCreate(
@@ -228,7 +228,6 @@ impl Default for EventLoopWaker {
228228
ptr::null_mut(),
229229
);
230230
CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);
231-
232231
EventLoopWaker { timer }
233232
}
234233
}

src/platform_impl/macos/util.rs

+43-37
Original file line numberDiff line numberDiff line change
@@ -402,72 +402,78 @@ pub unsafe fn create_input_context(view: id) -> IdRef {
402402
IdRef::new(input_context)
403403
}
404404

405-
pub enum CursorType {
405+
pub enum Cursor {
406406
Native(&'static str),
407407
Undocumented(&'static str),
408408
WebKit(&'static str),
409409
}
410410

411-
impl From<MouseCursor> for CursorType {
411+
impl From<MouseCursor> for Cursor {
412412
fn from(cursor: MouseCursor) -> Self {
413413
match cursor {
414-
MouseCursor::Arrow | MouseCursor::Default => CursorType::Native("arrowCursor"),
415-
MouseCursor::Hand => CursorType::Native("pointingHandCursor"),
416-
MouseCursor::Grabbing | MouseCursor::Grab => CursorType::Native("closedHandCursor"),
417-
MouseCursor::Text => CursorType::Native("IBeamCursor"),
418-
MouseCursor::VerticalText => CursorType::Native("IBeamCursorForVerticalLayout"),
419-
MouseCursor::Copy => CursorType::Native("dragCopyCursor"),
420-
MouseCursor::Alias => CursorType::Native("dragLinkCursor"),
421-
MouseCursor::NotAllowed | MouseCursor::NoDrop => CursorType::Native("operationNotAllowedCursor"),
422-
MouseCursor::ContextMenu => CursorType::Native("contextualMenuCursor"),
423-
MouseCursor::Crosshair => CursorType::Native("crosshairCursor"),
424-
MouseCursor::EResize => CursorType::Native("resizeRightCursor"),
425-
MouseCursor::NResize => CursorType::Native("resizeUpCursor"),
426-
MouseCursor::WResize => CursorType::Native("resizeLeftCursor"),
427-
MouseCursor::SResize => CursorType::Native("resizeDownCursor"),
428-
MouseCursor::EwResize | MouseCursor::ColResize => CursorType::Native("resizeLeftRightCursor"),
429-
MouseCursor::NsResize | MouseCursor::RowResize => CursorType::Native("resizeUpDownCursor"),
414+
MouseCursor::Arrow | MouseCursor::Default => Cursor::Native("arrowCursor"),
415+
MouseCursor::Hand => Cursor::Native("pointingHandCursor"),
416+
MouseCursor::Grabbing | MouseCursor::Grab => Cursor::Native("closedHandCursor"),
417+
MouseCursor::Text => Cursor::Native("IBeamCursor"),
418+
MouseCursor::VerticalText => Cursor::Native("IBeamCursorForVerticalLayout"),
419+
MouseCursor::Copy => Cursor::Native("dragCopyCursor"),
420+
MouseCursor::Alias => Cursor::Native("dragLinkCursor"),
421+
MouseCursor::NotAllowed | MouseCursor::NoDrop => Cursor::Native("operationNotAllowedCursor"),
422+
MouseCursor::ContextMenu => Cursor::Native("contextualMenuCursor"),
423+
MouseCursor::Crosshair => Cursor::Native("crosshairCursor"),
424+
MouseCursor::EResize => Cursor::Native("resizeRightCursor"),
425+
MouseCursor::NResize => Cursor::Native("resizeUpCursor"),
426+
MouseCursor::WResize => Cursor::Native("resizeLeftCursor"),
427+
MouseCursor::SResize => Cursor::Native("resizeDownCursor"),
428+
MouseCursor::EwResize | MouseCursor::ColResize => Cursor::Native("resizeLeftRightCursor"),
429+
MouseCursor::NsResize | MouseCursor::RowResize => Cursor::Native("resizeUpDownCursor"),
430430

431431
// Undocumented cursors: https://stackoverflow.com/a/46635398/5435443
432-
MouseCursor::Help => CursorType::Undocumented("_helpCursor"),
433-
MouseCursor::ZoomIn => CursorType::Undocumented("_zoomInCursor"),
434-
MouseCursor::ZoomOut => CursorType::Undocumented("_zoomOutCursor"),
435-
MouseCursor::NeResize => CursorType::Undocumented("_windowResizeNorthEastCursor"),
436-
MouseCursor::NwResize => CursorType::Undocumented("_windowResizeNorthWestCursor"),
437-
MouseCursor::SeResize => CursorType::Undocumented("_windowResizeSouthEastCursor"),
438-
MouseCursor::SwResize => CursorType::Undocumented("_windowResizeSouthWestCursor"),
439-
MouseCursor::NeswResize => CursorType::Undocumented("_windowResizeNorthEastSouthWestCursor"),
440-
MouseCursor::NwseResize => CursorType::Undocumented("_windowResizeNorthWestSouthEastCursor"),
432+
MouseCursor::Help => Cursor::Undocumented("_helpCursor"),
433+
MouseCursor::ZoomIn => Cursor::Undocumented("_zoomInCursor"),
434+
MouseCursor::ZoomOut => Cursor::Undocumented("_zoomOutCursor"),
435+
MouseCursor::NeResize => Cursor::Undocumented("_windowResizeNorthEastCursor"),
436+
MouseCursor::NwResize => Cursor::Undocumented("_windowResizeNorthWestCursor"),
437+
MouseCursor::SeResize => Cursor::Undocumented("_windowResizeSouthEastCursor"),
438+
MouseCursor::SwResize => Cursor::Undocumented("_windowResizeSouthWestCursor"),
439+
MouseCursor::NeswResize => Cursor::Undocumented("_windowResizeNorthEastSouthWestCursor"),
440+
MouseCursor::NwseResize => Cursor::Undocumented("_windowResizeNorthWestSouthEastCursor"),
441441

442442
// While these are available, the former just loads a white arrow,
443443
// and the latter loads an ugly deflated beachball!
444-
// MouseCursor::Move => CursorType::Undocumented("_moveCursor"),
445-
// MouseCursor::Wait => CursorType::Undocumented("_waitCursor"),
444+
// MouseCursor::Move => Cursor::Undocumented("_moveCursor"),
445+
// MouseCursor::Wait => Cursor::Undocumented("_waitCursor"),
446446

447447
// An even more undocumented cursor...
448448
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=522349
449449
// This is the wrong semantics for `Wait`, but it's the same as
450450
// what's used in Safari and Chrome.
451-
MouseCursor::Wait | MouseCursor::Progress => CursorType::Undocumented("busyButClickableCursor"),
451+
MouseCursor::Wait | MouseCursor::Progress => Cursor::Undocumented("busyButClickableCursor"),
452452

453453
// For the rest, we can just snatch the cursors from WebKit...
454454
// They fit the style of the native cursors, and will seem
455455
// completely standard to macOS users.
456456
// https://stackoverflow.com/a/21786835/5435443
457-
MouseCursor::Move | MouseCursor::AllScroll => CursorType::WebKit("move"),
458-
MouseCursor::Cell => CursorType::WebKit("cell"),
457+
MouseCursor::Move | MouseCursor::AllScroll => Cursor::WebKit("move"),
458+
MouseCursor::Cell => Cursor::WebKit("cell"),
459459
}
460460
}
461461
}
462462

463-
impl CursorType {
464-
pub unsafe fn load(self) -> id {
463+
impl Default for Cursor {
464+
fn default() -> Self {
465+
Cursor::Native("arrowCursor")
466+
}
467+
}
468+
469+
impl Cursor {
470+
pub unsafe fn load(&self) -> id {
465471
match self {
466-
CursorType::Native(cursor_name) => {
472+
Cursor::Native(cursor_name) => {
467473
let sel = Sel::register(cursor_name);
468474
msg_send![class!(NSCursor), performSelector:sel]
469475
},
470-
CursorType::Undocumented(cursor_name) => {
476+
Cursor::Undocumented(cursor_name) => {
471477
let class = class!(NSCursor);
472478
let sel = Sel::register(cursor_name);
473479
let sel = if msg_send![class, respondsToSelector:sel] {
@@ -478,7 +484,7 @@ impl CursorType {
478484
};
479485
msg_send![class, performSelector:sel]
480486
},
481-
CursorType::WebKit(cursor_name) => load_webkit_cursor(cursor_name),
487+
Cursor::WebKit(cursor_name) => load_webkit_cursor(cursor_name),
482488
}
483489
}
484490
}

0 commit comments

Comments
 (0)