Skip to content

Commit

Permalink
Dump (encapsulate) everything into AppState
Browse files Browse the repository at this point in the history
  • Loading branch information
francesca64 committed Dec 14, 2018
1 parent d2dc83d commit 8e6b986
Show file tree
Hide file tree
Showing 14 changed files with 546 additions and 701 deletions.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,5 @@ mod icon;
mod platform_impl;
pub mod window;
pub mod monitor;

pub mod platform;
mod util;
48 changes: 45 additions & 3 deletions src/platform_impl/macos/app.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use cocoa::{appkit, base::id};
use std::collections::VecDeque;

use cocoa::{appkit::{self, NSEvent}, base::id};
use objc::{declare::ClassDecl, runtime::{Class, Object, Sel}};

use platform_impl::platform::util;
use event::{DeviceEvent, Event};
use platform_impl::platform::{app_state::AppState, DEVICE_ID, util};

pub struct AppClass(pub *const Class);
unsafe impl Send for AppClass {}
Expand All @@ -26,7 +29,6 @@ lazy_static! {
// Fun fact: Firefox still has this bug! (https://bugzilla.mozilla.org/show_bug.cgi?id=1299553)
extern fn send_event(this: &Object, _sel: Sel, event: id) {
unsafe {
use self::appkit::NSEvent;
// For posterity, there are some undocumented event types
// (https://github.com/servo/cocoa-rs/issues/155)
// but that doesn't really matter here.
Expand All @@ -39,8 +41,48 @@ extern fn send_event(this: &Object, _sel: Sel, event: id) {
let key_window: id = msg_send![this, keyWindow];
let _: () = msg_send![key_window, sendEvent:event];
} else {
maybe_dispatch_device_event(event);
let superclass = util::superclass(this);
let _: () = msg_send![super(this, superclass), sendEvent:event];
}
}
}

unsafe fn maybe_dispatch_device_event(event: id) {
let event_type = event.eventType();
match event_type {
appkit::NSMouseMoved |
appkit::NSLeftMouseDragged |
appkit::NSOtherMouseDragged |
appkit::NSRightMouseDragged => {
let mut events = VecDeque::with_capacity(3);

let delta_x = event.deltaX() as f64;
let delta_y = event.deltaY() as f64;

if delta_x != 0.0 {
events.push_back(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::Motion { axis: 0, value: delta_x },
});
}

if delta_y != 0.0 {
events.push_back(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::Motion { axis: 1, value: delta_y },
});
}

if delta_x != 0.0 || delta_y != 0.0 {
events.push_back(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::MouseMotion { delta: (delta_x, delta_y) },
});
}

AppState::queue_events(events);
},
_ => (),
}
}
4 changes: 2 additions & 2 deletions src/platform_impl/macos/app_delegate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cocoa::base::id;
use objc::{runtime::{Class, Object, Sel, BOOL, YES}, declare::ClassDecl};

use platform_impl::platform::event_loop::HANDLER;
use platform_impl::platform::app_state::AppState;

pub struct AppDelegateClass(pub *const Class);
unsafe impl Send for AppDelegateClass {}
Expand Down Expand Up @@ -43,7 +43,7 @@ lazy_static! {

extern fn did_finish_launching(_: &Object, _: Sel, _: id) -> BOOL {
trace!("Triggered `didFinishLaunching`");
HANDLER.lock().unwrap().launched();
AppState::launched();
trace!("Completed `didFinishLaunching`");
YES
}
Expand Down
186 changes: 186 additions & 0 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
use std::{
self, collections::VecDeque, fmt::{self, Debug, Formatter},
hint::unreachable_unchecked, mem, sync::{Mutex, MutexGuard},
};

use cocoa::{appkit::NSApp, base::nil};

use {
event::{Event, StartCause},
event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget},
};
use platform_impl::platform::{observer::EventLoopWaker, util::Never};

lazy_static! {
static ref HANDLER: Mutex<Handler> = Default::default();
static ref EVENTS: Mutex<VecDeque<Event<Never>>> = Default::default();
}

impl Event<Never> {
fn userify<T: 'static>(self) -> Event<T> {
self.map_nonuser_event()
// `Never` can't be constructed, so the `UserEvent` variant can't
// be present here.
.unwrap_or_else(|_| unsafe { unreachable_unchecked() })
}
}

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);
}

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

impl<F, T: 'static> Debug for EventLoopHandler<F, T> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.debug_struct("EventLoopHandler")
.field("window_target", &self.window_target)
.finish()
}
}

impl<F, T> EventHandler for EventLoopHandler<F, T>
where
F: 'static + FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
T: 'static,
{
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: *mut ControlFlow) {
(self.callback)(
event.userify(),
&self.window_target,
unsafe { &mut *control_flow },
);
}

/*fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
for event in self.event_loop.inner.receiver.try_iter() {
(self.callback)(
Event::UserEvent(event),
&self.event_loop,
control_flow,
);
}
}*/
}

#[derive(Default)]
struct Handler {
control_flow: ControlFlow,
control_flow_prev: ControlFlow,
callback: Option<Box<dyn EventHandler>>,
waker: EventLoopWaker,
}

unsafe impl Send for Handler {}
unsafe impl Sync for Handler {}

impl Handler {
fn handle_nonuser_event(&mut self, event: Event<Never>) {
let control_flow = &mut self.control_flow;
if let Some(ref mut callback) = self.callback {
callback.handle_nonuser_event(event, control_flow);
}
}
}

pub enum AppState {}

impl AppState {
fn handler() -> MutexGuard<'static, Handler> {
HANDLER.lock().unwrap()
}

fn events() -> MutexGuard<'static, VecDeque<Event<Never>>> {
EVENTS.lock().unwrap()
}

pub fn set_callback<F, T>(callback: F, window_target: RootWindowTarget<T>)
where
F: 'static + FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
T: 'static,
{
Self::handler().callback = Some(Box::new(EventLoopHandler {
callback,
window_target,
}));
}

pub fn exit() -> ! {
let mut handler = Self::handler();
if let Some(mut callback) = handler.callback.take() {
callback.handle_nonuser_event(
Event::LoopDestroyed,
&mut handler.control_flow,
);
}
std::process::exit(0)
}

pub fn launched() {
let mut handler = Self::handler();
handler.waker.start();
handler.handle_nonuser_event(Event::NewEvents(StartCause::Init));
}

pub fn wakeup() {
let mut handler = Self::handler();
handler.control_flow_prev = handler.control_flow;
let cause = match handler.control_flow {
ControlFlow::Poll => StartCause::Poll,
/*ControlFlow::Wait => StartCause::WaitCancelled {
start,
requested_resume: None,
},
ControlFlow::WaitUntil(requested_resume) => {
if Instant::now() >= requested_resume {
StartCause::ResumeTimeReached {
start,
requested_resume,
}
} else {
StartCause::WaitCancelled {
start,
requested_resume: Some(requested_resume),
}
}
},*/
ControlFlow::Exit => StartCause::Poll,//panic!("unexpected `ControlFlow::Exit`"),
_ => unimplemented!(),
};
handler.handle_nonuser_event(Event::NewEvents(cause));
}

pub fn queue_event(event: Event<Never>) {
Self::events().push_back(event);
}

pub fn queue_events(mut events: VecDeque<Event<Never>>) {
Self::events().append(&mut events);
}

pub fn cleared() {
let mut handler = Self::handler();
handler.handle_nonuser_event(Event::EventsCleared);
let events = mem::replace(&mut *Self::events(), Default::default());
for event in events {
handler.handle_nonuser_event(event);
}
let old = handler.control_flow_prev;
let new = handler.control_flow;
match (old, new) {
(ControlFlow::Poll, ControlFlow::Poll) => (),
(ControlFlow::Wait, ControlFlow::Wait) => (),
(ControlFlow::WaitUntil(old_instant), ControlFlow::WaitUntil(new_instant)) if old_instant == new_instant => (),
(_, ControlFlow::Wait) => handler.waker.stop(),
(_, ControlFlow::WaitUntil(new_instant)) => handler.waker.start_at(new_instant),
(_, ControlFlow::Poll) => handler.waker.start(),
(_, ControlFlow::Exit) => {
let _: () = unsafe { msg_send![NSApp(), stop:nil] };
},
}
}
}
Loading

0 comments on commit 8e6b986

Please sign in to comment.