Skip to content

Commit

Permalink
User events
Browse files Browse the repository at this point in the history
  • Loading branch information
francesca64 committed Dec 20, 2018
1 parent 157418d commit 27e475c
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 91 deletions.
40 changes: 29 additions & 11 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ impl Event<Never> {

pub trait EventHandler: Debug {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
//fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
}

struct EventLoopHandler<F, T: 'static> {
callback: F,
will_exit: bool,
window_target: RootWindowTarget<T>,
}

impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
impl<F, T> Debug for EventLoopHandler<F, T> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.debug_struct("EventLoopHandler")
.field("window_target", &self.window_target)
Expand All @@ -54,17 +55,27 @@ where
&self.window_target,
control_flow,
);
self.will_exit |= *control_flow == ControlFlow::Exit;
if self.will_exit {
*control_flow = ControlFlow::Exit;
}
}

/*fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
for event in self.event_loop.inner.receiver.try_iter() {
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
let mut will_exit = self.will_exit;
for event in self.window_target.inner.receiver.try_iter() {
(self.callback)(
Event::UserEvent(event),
&self.event_loop,
&self.window_target,
control_flow,
);
will_exit |= *control_flow == ControlFlow::Exit;
if will_exit {
*control_flow = ControlFlow::Exit;
}
}
}*/
self.will_exit = will_exit;
}
}

#[derive(Default)]
Expand Down Expand Up @@ -98,7 +109,7 @@ impl Handler {
self.ready.store(true, Ordering::Release);
}

fn is_control_flow_exit(&self) -> bool {
fn should_exit(&self) -> bool {
*self.control_flow.lock().unwrap() == ControlFlow::Exit
}

Expand Down Expand Up @@ -134,6 +145,14 @@ impl Handler {
);
}
}

fn handle_user_events(&self) {
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
callback.handle_user_events(
&mut *self.control_flow.lock().unwrap(),
);
}
}
}

pub enum AppState {}
Expand All @@ -146,6 +165,7 @@ impl AppState {
{
*HANDLER.callback.lock().unwrap() = Some(Box::new(EventLoopHandler {
callback,
will_exit: false,
window_target,
}));
}
Expand Down Expand Up @@ -203,14 +223,12 @@ impl AppState {

pub fn cleared() {
if !HANDLER.is_ready() { return }
let mut will_stop = HANDLER.is_control_flow_exit();
HANDLER.handle_user_events();
for event in HANDLER.take_events() {
HANDLER.handle_nonuser_event(event);
will_stop |= HANDLER.is_control_flow_exit();
}
HANDLER.handle_nonuser_event(Event::EventsCleared);
will_stop |= HANDLER.is_control_flow_exit();
if will_stop {
if HANDLER.should_exit() {
let _: () = unsafe { msg_send![NSApp(), stop:nil] };
return
}
Expand Down
55 changes: 42 additions & 13 deletions src/platform_impl/macos/event_loop.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::{
collections::VecDeque, marker::PhantomData, process,
collections::VecDeque, mem, os::raw::c_void, process, ptr, sync::mpsc,
};

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

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

impl<T> Default for EventLoopWindowTarget<T> {
fn default() -> Self {
EventLoopWindowTarget { _marker: PhantomData }
let (sender, receiver) = mpsc::channel();
EventLoopWindowTarget { sender, receiver }
}
}

Expand Down Expand Up @@ -90,23 +92,50 @@ impl<T> EventLoop<T> {
}

pub fn create_proxy(&self) -> Proxy<T> {
Proxy::default()
Proxy::new(self.window_target.inner.sender.clone())
}
}

#[derive(Clone)]
pub struct Proxy<T> {
_marker: PhantomData<T>,
sender: mpsc::Sender<T>,
source: CFRunLoopSourceRef,
}

impl<T> Default for Proxy<T> {
fn default() -> Self {
Proxy { _marker: PhantomData }
}
}
unsafe impl<T> Send for Proxy<T> {}
unsafe impl<T> Sync for Proxy<T> {}

impl<T> Proxy<T> {
pub fn send_event(&self, _event: T) -> Result<(), EventLoopClosed> {
unimplemented!();
fn new(sender: mpsc::Sender<T>) -> Self {
unsafe {
// just wakeup the eventloop
extern "C" fn event_loop_proxy_handler(_: *mut c_void) {}

// adding a Source to the main CFRunLoop lets us wake it up and
// process user events through the normal OS EventLoop mechanisms.
let rl = CFRunLoopGetMain();
let mut context: CFRunLoopSourceContext = mem::zeroed();
context.perform = event_loop_proxy_handler;
let source = CFRunLoopSourceCreate(
ptr::null_mut(),
CFIndex::max_value() - 1,
&mut context,
);
CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
CFRunLoopWakeUp(rl);

Proxy { sender, source }
}
}

pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> {
self.sender.send(event).map_err(|_| EventLoopClosed)?;
unsafe {
// let the main thread know there's a new event
CFRunLoopSourceSignal(self.source);
let rl = CFRunLoopGetMain();
CFRunLoopWakeUp(rl);
}
Ok(())
}
}
3 changes: 1 addition & 2 deletions src/platform_impl/macos/observer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl Default for EventLoopWaker {
fn default() -> EventLoopWaker {
extern fn wakeup_main_loop(_timer: CFRunLoopTimerRef, _info: *mut c_void) {}
unsafe {
// create a timer with a 1microsec interval (1ns does not work) to mimic polling.
// create a timer with a 1µs interval (1ns does not work) to mimic polling.
// it is initially setup with a first fire time really far into the
// future, but that gets changed to fire immediatley in did_finish_launching
let timer = CFRunLoopTimerCreate(
Expand All @@ -228,7 +228,6 @@ impl Default for EventLoopWaker {
ptr::null_mut(),
);
CFRunLoopAddTimer(CFRunLoopGetMain(), timer, kCFRunLoopCommonModes);

EventLoopWaker { timer }
}
}
Expand Down
80 changes: 43 additions & 37 deletions src/platform_impl/macos/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,72 +402,78 @@ pub unsafe fn create_input_context(view: id) -> IdRef {
IdRef::new(input_context)
}

pub enum CursorType {
pub enum Cursor {
Native(&'static str),
Undocumented(&'static str),
WebKit(&'static str),
}

impl From<MouseCursor> for CursorType {
impl From<MouseCursor> for Cursor {
fn from(cursor: MouseCursor) -> Self {
match cursor {
MouseCursor::Arrow | MouseCursor::Default => CursorType::Native("arrowCursor"),
MouseCursor::Hand => CursorType::Native("pointingHandCursor"),
MouseCursor::Grabbing | MouseCursor::Grab => CursorType::Native("closedHandCursor"),
MouseCursor::Text => CursorType::Native("IBeamCursor"),
MouseCursor::VerticalText => CursorType::Native("IBeamCursorForVerticalLayout"),
MouseCursor::Copy => CursorType::Native("dragCopyCursor"),
MouseCursor::Alias => CursorType::Native("dragLinkCursor"),
MouseCursor::NotAllowed | MouseCursor::NoDrop => CursorType::Native("operationNotAllowedCursor"),
MouseCursor::ContextMenu => CursorType::Native("contextualMenuCursor"),
MouseCursor::Crosshair => CursorType::Native("crosshairCursor"),
MouseCursor::EResize => CursorType::Native("resizeRightCursor"),
MouseCursor::NResize => CursorType::Native("resizeUpCursor"),
MouseCursor::WResize => CursorType::Native("resizeLeftCursor"),
MouseCursor::SResize => CursorType::Native("resizeDownCursor"),
MouseCursor::EwResize | MouseCursor::ColResize => CursorType::Native("resizeLeftRightCursor"),
MouseCursor::NsResize | MouseCursor::RowResize => CursorType::Native("resizeUpDownCursor"),
MouseCursor::Arrow | MouseCursor::Default => Cursor::Native("arrowCursor"),
MouseCursor::Hand => Cursor::Native("pointingHandCursor"),
MouseCursor::Grabbing | MouseCursor::Grab => Cursor::Native("closedHandCursor"),
MouseCursor::Text => Cursor::Native("IBeamCursor"),
MouseCursor::VerticalText => Cursor::Native("IBeamCursorForVerticalLayout"),
MouseCursor::Copy => Cursor::Native("dragCopyCursor"),
MouseCursor::Alias => Cursor::Native("dragLinkCursor"),
MouseCursor::NotAllowed | MouseCursor::NoDrop => Cursor::Native("operationNotAllowedCursor"),
MouseCursor::ContextMenu => Cursor::Native("contextualMenuCursor"),
MouseCursor::Crosshair => Cursor::Native("crosshairCursor"),
MouseCursor::EResize => Cursor::Native("resizeRightCursor"),
MouseCursor::NResize => Cursor::Native("resizeUpCursor"),
MouseCursor::WResize => Cursor::Native("resizeLeftCursor"),
MouseCursor::SResize => Cursor::Native("resizeDownCursor"),
MouseCursor::EwResize | MouseCursor::ColResize => Cursor::Native("resizeLeftRightCursor"),
MouseCursor::NsResize | MouseCursor::RowResize => Cursor::Native("resizeUpDownCursor"),

// Undocumented cursors: https://stackoverflow.com/a/46635398/5435443
MouseCursor::Help => CursorType::Undocumented("_helpCursor"),
MouseCursor::ZoomIn => CursorType::Undocumented("_zoomInCursor"),
MouseCursor::ZoomOut => CursorType::Undocumented("_zoomOutCursor"),
MouseCursor::NeResize => CursorType::Undocumented("_windowResizeNorthEastCursor"),
MouseCursor::NwResize => CursorType::Undocumented("_windowResizeNorthWestCursor"),
MouseCursor::SeResize => CursorType::Undocumented("_windowResizeSouthEastCursor"),
MouseCursor::SwResize => CursorType::Undocumented("_windowResizeSouthWestCursor"),
MouseCursor::NeswResize => CursorType::Undocumented("_windowResizeNorthEastSouthWestCursor"),
MouseCursor::NwseResize => CursorType::Undocumented("_windowResizeNorthWestSouthEastCursor"),
MouseCursor::Help => Cursor::Undocumented("_helpCursor"),
MouseCursor::ZoomIn => Cursor::Undocumented("_zoomInCursor"),
MouseCursor::ZoomOut => Cursor::Undocumented("_zoomOutCursor"),
MouseCursor::NeResize => Cursor::Undocumented("_windowResizeNorthEastCursor"),
MouseCursor::NwResize => Cursor::Undocumented("_windowResizeNorthWestCursor"),
MouseCursor::SeResize => Cursor::Undocumented("_windowResizeSouthEastCursor"),
MouseCursor::SwResize => Cursor::Undocumented("_windowResizeSouthWestCursor"),
MouseCursor::NeswResize => Cursor::Undocumented("_windowResizeNorthEastSouthWestCursor"),
MouseCursor::NwseResize => Cursor::Undocumented("_windowResizeNorthWestSouthEastCursor"),

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

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

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

impl CursorType {
pub unsafe fn load(self) -> id {
impl Default for Cursor {
fn default() -> Self {
Cursor::Native("arrowCursor")
}
}

impl Cursor {
pub unsafe fn load(&self) -> id {
match self {
CursorType::Native(cursor_name) => {
Cursor::Native(cursor_name) => {
let sel = Sel::register(cursor_name);
msg_send![class!(NSCursor), performSelector:sel]
},
CursorType::Undocumented(cursor_name) => {
Cursor::Undocumented(cursor_name) => {
let class = class!(NSCursor);
let sel = Sel::register(cursor_name);
let sel = if msg_send![class, respondsToSelector:sel] {
Expand All @@ -478,7 +484,7 @@ impl CursorType {
};
msg_send![class, performSelector:sel]
},
CursorType::WebKit(cursor_name) => load_webkit_cursor(cursor_name),
Cursor::WebKit(cursor_name) => load_webkit_cursor(cursor_name),
}
}
}
Expand Down
Loading

0 comments on commit 27e475c

Please sign in to comment.