diff --git a/src/lib.rs b/src/lib.rs index 86323be6b0..66d78ad6a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,5 +114,5 @@ mod icon; mod platform_impl; pub mod window; pub mod monitor; - pub mod platform; +mod util; diff --git a/src/platform_impl/macos/app.rs b/src/platform_impl/macos/app.rs index 292e82752a..2699eedc2b 100644 --- a/src/platform_impl/macos/app.rs +++ b/src/platform_impl/macos/app.rs @@ -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 {} @@ -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. @@ -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); + }, + _ => (), + } +} diff --git a/src/platform_impl/macos/app_delegate.rs b/src/platform_impl/macos/app_delegate.rs index 09b2945071..8e4ab19dcd 100644 --- a/src/platform_impl/macos/app_delegate.rs +++ b/src/platform_impl/macos/app_delegate.rs @@ -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 {} @@ -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 } diff --git a/src/platform_impl/macos/app_state.rs b/src/platform_impl/macos/app_state.rs new file mode 100644 index 0000000000..38bd902630 --- /dev/null +++ b/src/platform_impl/macos/app_state.rs @@ -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 = Default::default(); + static ref EVENTS: Mutex>> = Default::default(); +} + +impl Event { + fn userify(self) -> Event { + 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, control_flow: *mut ControlFlow); + //fn handle_user_events(&mut self, control_flow: &mut ControlFlow); +} + +struct EventLoopHandler { + callback: F, + window_target: RootWindowTarget, +} + +impl Debug for EventLoopHandler { + fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.debug_struct("EventLoopHandler") + .field("window_target", &self.window_target) + .finish() + } +} + +impl EventHandler for EventLoopHandler +where + F: 'static + FnMut(Event, &RootWindowTarget, &mut ControlFlow), + T: 'static, +{ + fn handle_nonuser_event(&mut self, event: Event, 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>, + waker: EventLoopWaker, +} + +unsafe impl Send for Handler {} +unsafe impl Sync for Handler {} + +impl Handler { + fn handle_nonuser_event(&mut self, event: Event) { + 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>> { + EVENTS.lock().unwrap() + } + + pub fn set_callback(callback: F, window_target: RootWindowTarget) + where + F: 'static + FnMut(Event, &RootWindowTarget, &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) { + Self::events().push_back(event); + } + + pub fn queue_events(mut events: VecDeque>) { + 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] }; + }, + } + } +} diff --git a/src/platform_impl/macos/event.rs b/src/platform_impl/macos/event.rs new file mode 100644 index 0000000000..10cd876f81 --- /dev/null +++ b/src/platform_impl/macos/event.rs @@ -0,0 +1,202 @@ +use std::os::raw::c_ushort; + +use cocoa::{appkit::{NSEvent, NSEventModifierFlags}, base::id}; + +use event::{ + ElementState, KeyboardInput, + ModifiersState, VirtualKeyCode, WindowEvent, +}; +use platform_impl::platform::DEVICE_ID; + +pub fn to_virtual_keycode(scancode: c_ushort) -> Option { + Some(match scancode { + 0x00 => VirtualKeyCode::A, + 0x01 => VirtualKeyCode::S, + 0x02 => VirtualKeyCode::D, + 0x03 => VirtualKeyCode::F, + 0x04 => VirtualKeyCode::H, + 0x05 => VirtualKeyCode::G, + 0x06 => VirtualKeyCode::Z, + 0x07 => VirtualKeyCode::X, + 0x08 => VirtualKeyCode::C, + 0x09 => VirtualKeyCode::V, + //0x0a => World 1, + 0x0b => VirtualKeyCode::B, + 0x0c => VirtualKeyCode::Q, + 0x0d => VirtualKeyCode::W, + 0x0e => VirtualKeyCode::E, + 0x0f => VirtualKeyCode::R, + 0x10 => VirtualKeyCode::Y, + 0x11 => VirtualKeyCode::T, + 0x12 => VirtualKeyCode::Key1, + 0x13 => VirtualKeyCode::Key2, + 0x14 => VirtualKeyCode::Key3, + 0x15 => VirtualKeyCode::Key4, + 0x16 => VirtualKeyCode::Key6, + 0x17 => VirtualKeyCode::Key5, + 0x18 => VirtualKeyCode::Equals, + 0x19 => VirtualKeyCode::Key9, + 0x1a => VirtualKeyCode::Key7, + 0x1b => VirtualKeyCode::Minus, + 0x1c => VirtualKeyCode::Key8, + 0x1d => VirtualKeyCode::Key0, + 0x1e => VirtualKeyCode::RBracket, + 0x1f => VirtualKeyCode::O, + 0x20 => VirtualKeyCode::U, + 0x21 => VirtualKeyCode::LBracket, + 0x22 => VirtualKeyCode::I, + 0x23 => VirtualKeyCode::P, + 0x24 => VirtualKeyCode::Return, + 0x25 => VirtualKeyCode::L, + 0x26 => VirtualKeyCode::J, + 0x27 => VirtualKeyCode::Apostrophe, + 0x28 => VirtualKeyCode::K, + 0x29 => VirtualKeyCode::Semicolon, + 0x2a => VirtualKeyCode::Backslash, + 0x2b => VirtualKeyCode::Comma, + 0x2c => VirtualKeyCode::Slash, + 0x2d => VirtualKeyCode::N, + 0x2e => VirtualKeyCode::M, + 0x2f => VirtualKeyCode::Period, + 0x30 => VirtualKeyCode::Tab, + 0x31 => VirtualKeyCode::Space, + 0x32 => VirtualKeyCode::Grave, + 0x33 => VirtualKeyCode::Back, + //0x34 => unkown, + 0x35 => VirtualKeyCode::Escape, + 0x36 => VirtualKeyCode::RWin, + 0x37 => VirtualKeyCode::LWin, + 0x38 => VirtualKeyCode::LShift, + //0x39 => Caps lock, + 0x3a => VirtualKeyCode::LAlt, + 0x3b => VirtualKeyCode::LControl, + 0x3c => VirtualKeyCode::RShift, + 0x3d => VirtualKeyCode::RAlt, + 0x3e => VirtualKeyCode::RControl, + //0x3f => Fn key, + 0x40 => VirtualKeyCode::F17, + 0x41 => VirtualKeyCode::Decimal, + //0x42 -> unkown, + 0x43 => VirtualKeyCode::Multiply, + //0x44 => unkown, + 0x45 => VirtualKeyCode::Add, + //0x46 => unkown, + 0x47 => VirtualKeyCode::Numlock, + //0x48 => KeypadClear, + 0x49 => VirtualKeyCode::VolumeUp, + 0x4a => VirtualKeyCode::VolumeDown, + 0x4b => VirtualKeyCode::Divide, + 0x4c => VirtualKeyCode::NumpadEnter, + //0x4d => unkown, + 0x4e => VirtualKeyCode::Subtract, + 0x4f => VirtualKeyCode::F18, + 0x50 => VirtualKeyCode::F19, + 0x51 => VirtualKeyCode::NumpadEquals, + 0x52 => VirtualKeyCode::Numpad0, + 0x53 => VirtualKeyCode::Numpad1, + 0x54 => VirtualKeyCode::Numpad2, + 0x55 => VirtualKeyCode::Numpad3, + 0x56 => VirtualKeyCode::Numpad4, + 0x57 => VirtualKeyCode::Numpad5, + 0x58 => VirtualKeyCode::Numpad6, + 0x59 => VirtualKeyCode::Numpad7, + 0x5a => VirtualKeyCode::F20, + 0x5b => VirtualKeyCode::Numpad8, + 0x5c => VirtualKeyCode::Numpad9, + //0x5d => unkown, + //0x5e => unkown, + //0x5f => unkown, + 0x60 => VirtualKeyCode::F5, + 0x61 => VirtualKeyCode::F6, + 0x62 => VirtualKeyCode::F7, + 0x63 => VirtualKeyCode::F3, + 0x64 => VirtualKeyCode::F8, + 0x65 => VirtualKeyCode::F9, + //0x66 => unkown, + 0x67 => VirtualKeyCode::F11, + //0x68 => unkown, + 0x69 => VirtualKeyCode::F13, + 0x6a => VirtualKeyCode::F16, + 0x6b => VirtualKeyCode::F14, + //0x6c => unkown, + 0x6d => VirtualKeyCode::F10, + //0x6e => unkown, + 0x6f => VirtualKeyCode::F12, + //0x70 => unkown, + 0x71 => VirtualKeyCode::F15, + 0x72 => VirtualKeyCode::Insert, + 0x73 => VirtualKeyCode::Home, + 0x74 => VirtualKeyCode::PageUp, + 0x75 => VirtualKeyCode::Delete, + 0x76 => VirtualKeyCode::F4, + 0x77 => VirtualKeyCode::End, + 0x78 => VirtualKeyCode::F2, + 0x79 => VirtualKeyCode::PageDown, + 0x7a => VirtualKeyCode::F1, + 0x7b => VirtualKeyCode::Left, + 0x7c => VirtualKeyCode::Right, + 0x7d => VirtualKeyCode::Down, + 0x7e => VirtualKeyCode::Up, + //0x7f => unkown, + + 0xa => VirtualKeyCode::Caret, + _ => return None, + }) +} + +// While F1-F20 have scancodes we can match on, we have to check against UTF-16 +// constants for the rest. +// https://developer.apple.com/documentation/appkit/1535851-function-key_unicodes?preferredLanguage=occ +pub fn check_function_keys(string: &Option) -> Option { + string + .as_ref() + .and_then(|string| string.encode_utf16().next()) + .and_then(|character| match character { + 0xf718 => Some(VirtualKeyCode::F21), + 0xf719 => Some(VirtualKeyCode::F22), + 0xf71a => Some(VirtualKeyCode::F23), + 0xf71b => Some(VirtualKeyCode::F24), + _ => None, + }) +} + +pub fn event_mods(event: id) -> ModifiersState { + let flags = unsafe { + NSEvent::modifierFlags(event) + }; + ModifiersState { + shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask), + ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask), + alt: flags.contains(NSEventModifierFlags::NSAlternateKeyMask), + logo: flags.contains(NSEventModifierFlags::NSCommandKeyMask), + } +} + +pub unsafe fn modifier_event( + ns_event: id, + keymask: NSEventModifierFlags, + was_key_pressed: bool, +) -> Option { + if !was_key_pressed && NSEvent::modifierFlags(ns_event).contains(keymask) + || was_key_pressed && !NSEvent::modifierFlags(ns_event).contains(keymask) { + let state = if was_key_pressed { + ElementState::Released + } else { + ElementState::Pressed + }; + let keycode = NSEvent::keyCode(ns_event); + let scancode = keycode as u32; + let virtual_keycode = to_virtual_keycode(keycode); + Some(WindowEvent::KeyboardInput { + device_id: DEVICE_ID, + input: KeyboardInput { + state, + scancode, + virtual_keycode, + modifiers: event_mods(ns_event), + }, + }) + } else { + None + } +} diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index f021284041..1ae21d9552 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -1,228 +1,31 @@ use std::{ - collections::VecDeque, fmt::{self, Debug, Formatter}, - hint::unreachable_unchecked, marker::PhantomData, mem, os::raw::*, - process::exit, sync::{Arc, Mutex, Weak}, + collections::VecDeque, marker::PhantomData, }; -use cocoa::{ - appkit::{ - self, NSApp, NSApplication, NSApplicationDefined, NSEvent, - NSEventModifierFlags, NSEventSubtype, - }, - base::{BOOL, id, nil, NO, YES}, - foundation::{NSAutoreleasePool, NSPoint}, -}; +use cocoa::{appkit::NSApp, base::{id, nil}, foundation::NSAutoreleasePool}; use { - event::{ - self, DeviceEvent, ElementState, Event, KeyboardInput, - ModifiersState, StartCause, WindowEvent, - }, - event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW}, + event::Event, + event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootWindowTarget}, }; use platform_impl::platform::{ - app::APP_CLASS, app_delegate::APP_DELEGATE_CLASS, DEVICE_ID, - monitor::{self, MonitorHandle}, - observer::{EventLoopWaker, setup_control_flow_observers}, - util::{Access, IdRef}, window::UnownedWindow, + app::APP_CLASS, app_delegate::APP_DELEGATE_CLASS, + app_state::AppState, monitor::{self, MonitorHandle}, + observer::setup_control_flow_observers, util::IdRef, }; -// Change to `!` once stable -pub enum Never {} - -impl Event { - fn userify(self) -> Event { - self.map_nonuser_event() - // `Never` can't be constructed, so the `UserEvent` variant can't - // be present here. - .unwrap_or_else(|_| unsafe { unreachable_unchecked() }) - } -} - -// State shared between the `EventLoop` and its registered windows and delegates. -#[derive(Default)] -pub struct PendingEvents { - pending: VecDeque>, -} - -impl PendingEvents { - pub fn queue_event(&mut self, event: Event) { - self.pending.push_back(event); - } - - pub fn queue_events(&mut self, mut events: VecDeque>) { - self.pending.append(&mut events); - } - - fn take(&mut self) -> VecDeque> { - mem::replace(&mut self.pending, Default::default()) - } -} - -#[derive(Default)] -pub struct WindowList { - windows: Vec>, -} - -impl WindowList { - pub fn insert_window(&mut self, window: Weak) { - self.windows.push(window); - } - - // Removes the window with the given `Id` from the `windows` list. - // - // This is called in response to `windowWillClose`. - pub fn remove_window(&mut self, id: super::window::Id) { - self.windows - .retain(|window| window - .upgrade() - .map(|window| window.id() != id) - .unwrap_or(false) - ); - } -} - -lazy_static! { - pub static ref HANDLER: Mutex = Default::default(); -} - -#[derive(Default)] -pub struct Handler { - control_flow: ControlFlow, - control_flow_prev: ControlFlow, - callback: Option>, - waker: EventLoopWaker, - pending_events: Weak>, -} - -unsafe impl Send for Handler {} -unsafe impl Sync for Handler {} - -impl Handler { - pub fn launched(&mut self) { - self.waker.start(); - if let Some(ref mut callback) = self.callback { - callback.handle_nonuser_event(Event::NewEvents(StartCause::Init), &mut self.control_flow); - } - } - - pub fn wakeup(&mut self) { - self.control_flow_prev = self.control_flow; - let cause = match self.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!(), - }; - if let Some(ref mut callback) = self.callback { - callback.handle_nonuser_event(Event::NewEvents(cause), &mut self.control_flow); - } - } - - pub fn cleared(&mut self) { - if let Some(ref mut callback) = self.callback { - callback.handle_nonuser_event(Event::EventsCleared, &mut self.control_flow); - //trace!("Locked pending events in `run`"); - let mut pending = self.pending_events - .access(|pending| pending.take()) - .unwrap(); - //trace!("Unlocked pending events in `run`"); - for event in pending.drain(0..) { - callback.handle_nonuser_event(event, &mut self.control_flow); - } - } - let old = self.control_flow_prev; - let new = self.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) => self.waker.stop(), - (_, ControlFlow::WaitUntil(new_instant)) => self.waker.start_at(new_instant), - (_, ControlFlow::Poll) => self.waker.start(), - (_, ControlFlow::Exit) => { - let _: () = unsafe { msg_send![NSApp(), stop:nil] }; - }, - } - } -} - -pub trait EventHandler: Debug { - fn handle_nonuser_event(&mut self, event: Event, control_flow: &mut ControlFlow); - //fn handle_user_events(&mut self, control_flow: &mut ControlFlow); -} - -struct EventLoopHandler { - callback: F, - event_loop: RootELW, -} - -impl Debug for EventLoopHandler { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.debug_struct("EventLoopHandler") - .field("event_loop", &self.event_loop) - .finish() - } -} - -impl EventHandler for EventLoopHandler -where - F: 'static + FnMut(Event, &RootELW, &mut ControlFlow), - T: 'static, -{ - fn handle_nonuser_event(&mut self, event: Event, control_flow: &mut ControlFlow) { - (self.callback)( - event.userify(), - &self.event_loop, - 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, - ); - } - }*/ -} - pub struct EventLoopWindowTarget { - pub pending_events: Arc>, - pub window_list: Arc>, _marker: PhantomData, } impl Default for EventLoopWindowTarget { fn default() -> Self { - EventLoopWindowTarget { - pending_events: Default::default(), - window_list: Default::default(), - _marker: PhantomData, - } + EventLoopWindowTarget { _marker: PhantomData } } } pub struct EventLoop { - elw_target: RootELW, + window_target: RootWindowTarget, _delegate: IdRef, } @@ -230,15 +33,13 @@ impl EventLoop { pub fn new() -> Self { let delegate = unsafe { if !msg_send![class!(NSThread), isMainThread] { - // This check should be in `new` instead panic!("On macOS, `EventLoop` must be created on the main thread!"); } - // Mark this thread as the main thread of the Cocoa event system. - // - // This must be done before any worker threads get a chance to call it - // (e.g., via `EventLoopProxy::wakeup()`), causing a wrong thread to be - // marked as the main thread. + // This must be done before `NSApp()` (equivalent to sending + // `sharedApplication`) is called anywhere else, or we'll end up + // with the wrong `NSApplication` class and the wrong thread could + // be marked as main. let app: id = msg_send![APP_CLASS.0, sharedApplication]; let delegate = IdRef::new(msg_send![APP_DELEGATE_CLASS.0, new]); @@ -249,8 +50,8 @@ impl EventLoop { }; setup_control_flow_observers(); EventLoop { - elw_target: RootELW::new(Default::default()), - _delegate: delegate, // is this necessary? + window_target: RootWindowTarget::new(Default::default()), + _delegate: delegate, } } @@ -264,118 +65,29 @@ impl EventLoop { monitor::get_primary_monitor() } - pub fn window_target(&self) -> &RootELW { - &self.elw_target + pub fn window_target(&self) -> &RootWindowTarget { + &self.window_target } pub fn run(self, callback: F) -> ! - where F: 'static + FnMut(Event, &RootELW, &mut ControlFlow), + where F: 'static + FnMut(Event, &RootWindowTarget, &mut ControlFlow), { unsafe { let _pool = NSAutoreleasePool::new(nil); let app = NSApp(); assert_ne!(app, nil); - { - let pending_events = Arc::downgrade(&self.elw_target.inner.pending_events); - let mut handler = HANDLER.lock().unwrap(); - handler.callback = Some(Box::new(EventLoopHandler { - callback, - event_loop: self.elw_target, - })); - handler.pending_events = pending_events; - } + AppState::set_callback(callback, self.window_target); let _: () = msg_send![app, run]; - { - let mut handler = HANDLER.lock().unwrap(); - if let Some(mut callback) = handler.callback.take() { - callback.handle_nonuser_event( - Event::LoopDestroyed, - &mut handler.control_flow, - ); - } - } - exit(0) + AppState::exit() } } pub fn run_return(&mut self, _callback: F) - where F: FnMut(Event, &RootELW, &mut ControlFlow), + where F: FnMut(Event, &RootWindowTarget, &mut ControlFlow), { unimplemented!(); } - // Converts an `NSEvent` to a winit `Event`. - unsafe fn translate_event(&mut self, ns_event: id) -> Option> { - let event_type = ns_event.eventType(); - let ns_window = ns_event.window(); - let window_id = super::window::get_window_id(ns_window); - - let windows = self.elw_target.inner.window_list.lock().unwrap(); - let maybe_window = (*windows) - .windows - .iter() - .filter_map(Weak::upgrade) - .find(|window| window_id == window.id()); - - // Returns `Some` window if one of our windows is the key window. - let maybe_key_window = || (*windows) - .windows - .iter() - .filter_map(Weak::upgrade) - .find(|window| { - let is_key_window: BOOL = msg_send![*window.nswindow, isKeyWindow]; - is_key_window == YES - }); - - match event_type { - appkit::NSMouseMoved | - appkit::NSLeftMouseDragged | - appkit::NSOtherMouseDragged | - appkit::NSRightMouseDragged => { - // If the mouse movement was on one of our windows, use it. - // Otherwise, if one of our windows is the key window (receiving input), use it. - // Otherwise, return `None`. - match maybe_window.or_else(maybe_key_window) { - Some(_window) => (), - None => return None, - } - - let mut events = VecDeque::with_capacity(3); - - let delta_x = ns_event.deltaX() as f64; - if delta_x != 0.0 { - let motion_event = DeviceEvent::Motion { axis: 0, value: delta_x }; - let event = Event::DeviceEvent { device_id: DEVICE_ID, event: motion_event }; - events.push_back(event); - } - - let delta_y = ns_event.deltaY() as f64; - if delta_y != 0.0 { - let motion_event = DeviceEvent::Motion { axis: 1, value: delta_y }; - let event = Event::DeviceEvent { device_id: DEVICE_ID, event: motion_event }; - events.push_back(event); - } - - if delta_x != 0.0 || delta_y != 0.0 { - let motion_event = DeviceEvent::MouseMotion { delta: (delta_x, delta_y) }; - let event = Event::DeviceEvent { device_id: DEVICE_ID, event: motion_event }; - events.push_back(event); - } - - let event = events.pop_front(); - trace!("Locked pending events in `translate_event`"); - self.elw_target.inner.pending_events - .lock() - .unwrap() - .queue_events(events); - trace!("Unlocked pending events in `translate_event`"); - event - }, - - _ => None, - } - } - pub fn create_proxy(&self) -> Proxy { Proxy::default() } @@ -393,222 +105,7 @@ impl Default for Proxy { } impl Proxy { - #[allow(unreachable_code)] - pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed> { + pub fn send_event(&self, _event: T) -> Result<(), EventLoopClosed> { unimplemented!(); - // Awaken the event loop by triggering `NSApplicationActivatedEventType`. - unsafe { - let pool = NSAutoreleasePool::new(nil); - let event = - NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_( - nil, - NSApplicationDefined, - NSPoint::new(0.0, 0.0), - NSEventModifierFlags::empty(), - 0.0, - 0, - nil, - NSEventSubtype::NSApplicationActivatedEventType, - 0, - 0, - ); - NSApp().postEvent_atStart_(event, NO); - NSAutoreleasePool::drain(pool); - } - Ok(()) - } -} - -pub fn to_virtual_key_code(code: c_ushort) -> Option { - Some(match code { - 0x00 => event::VirtualKeyCode::A, - 0x01 => event::VirtualKeyCode::S, - 0x02 => event::VirtualKeyCode::D, - 0x03 => event::VirtualKeyCode::F, - 0x04 => event::VirtualKeyCode::H, - 0x05 => event::VirtualKeyCode::G, - 0x06 => event::VirtualKeyCode::Z, - 0x07 => event::VirtualKeyCode::X, - 0x08 => event::VirtualKeyCode::C, - 0x09 => event::VirtualKeyCode::V, - //0x0a => World 1, - 0x0b => event::VirtualKeyCode::B, - 0x0c => event::VirtualKeyCode::Q, - 0x0d => event::VirtualKeyCode::W, - 0x0e => event::VirtualKeyCode::E, - 0x0f => event::VirtualKeyCode::R, - 0x10 => event::VirtualKeyCode::Y, - 0x11 => event::VirtualKeyCode::T, - 0x12 => event::VirtualKeyCode::Key1, - 0x13 => event::VirtualKeyCode::Key2, - 0x14 => event::VirtualKeyCode::Key3, - 0x15 => event::VirtualKeyCode::Key4, - 0x16 => event::VirtualKeyCode::Key6, - 0x17 => event::VirtualKeyCode::Key5, - 0x18 => event::VirtualKeyCode::Equals, - 0x19 => event::VirtualKeyCode::Key9, - 0x1a => event::VirtualKeyCode::Key7, - 0x1b => event::VirtualKeyCode::Minus, - 0x1c => event::VirtualKeyCode::Key8, - 0x1d => event::VirtualKeyCode::Key0, - 0x1e => event::VirtualKeyCode::RBracket, - 0x1f => event::VirtualKeyCode::O, - 0x20 => event::VirtualKeyCode::U, - 0x21 => event::VirtualKeyCode::LBracket, - 0x22 => event::VirtualKeyCode::I, - 0x23 => event::VirtualKeyCode::P, - 0x24 => event::VirtualKeyCode::Return, - 0x25 => event::VirtualKeyCode::L, - 0x26 => event::VirtualKeyCode::J, - 0x27 => event::VirtualKeyCode::Apostrophe, - 0x28 => event::VirtualKeyCode::K, - 0x29 => event::VirtualKeyCode::Semicolon, - 0x2a => event::VirtualKeyCode::Backslash, - 0x2b => event::VirtualKeyCode::Comma, - 0x2c => event::VirtualKeyCode::Slash, - 0x2d => event::VirtualKeyCode::N, - 0x2e => event::VirtualKeyCode::M, - 0x2f => event::VirtualKeyCode::Period, - 0x30 => event::VirtualKeyCode::Tab, - 0x31 => event::VirtualKeyCode::Space, - 0x32 => event::VirtualKeyCode::Grave, - 0x33 => event::VirtualKeyCode::Back, - //0x34 => unkown, - 0x35 => event::VirtualKeyCode::Escape, - 0x36 => event::VirtualKeyCode::RWin, - 0x37 => event::VirtualKeyCode::LWin, - 0x38 => event::VirtualKeyCode::LShift, - //0x39 => Caps lock, - 0x3a => event::VirtualKeyCode::LAlt, - 0x3b => event::VirtualKeyCode::LControl, - 0x3c => event::VirtualKeyCode::RShift, - 0x3d => event::VirtualKeyCode::RAlt, - 0x3e => event::VirtualKeyCode::RControl, - //0x3f => Fn key, - 0x40 => event::VirtualKeyCode::F17, - 0x41 => event::VirtualKeyCode::Decimal, - //0x42 -> unkown, - 0x43 => event::VirtualKeyCode::Multiply, - //0x44 => unkown, - 0x45 => event::VirtualKeyCode::Add, - //0x46 => unkown, - 0x47 => event::VirtualKeyCode::Numlock, - //0x48 => KeypadClear, - 0x49 => event::VirtualKeyCode::VolumeUp, - 0x4a => event::VirtualKeyCode::VolumeDown, - 0x4b => event::VirtualKeyCode::Divide, - 0x4c => event::VirtualKeyCode::NumpadEnter, - //0x4d => unkown, - 0x4e => event::VirtualKeyCode::Subtract, - 0x4f => event::VirtualKeyCode::F18, - 0x50 => event::VirtualKeyCode::F19, - 0x51 => event::VirtualKeyCode::NumpadEquals, - 0x52 => event::VirtualKeyCode::Numpad0, - 0x53 => event::VirtualKeyCode::Numpad1, - 0x54 => event::VirtualKeyCode::Numpad2, - 0x55 => event::VirtualKeyCode::Numpad3, - 0x56 => event::VirtualKeyCode::Numpad4, - 0x57 => event::VirtualKeyCode::Numpad5, - 0x58 => event::VirtualKeyCode::Numpad6, - 0x59 => event::VirtualKeyCode::Numpad7, - 0x5a => event::VirtualKeyCode::F20, - 0x5b => event::VirtualKeyCode::Numpad8, - 0x5c => event::VirtualKeyCode::Numpad9, - //0x5d => unkown, - //0x5e => unkown, - //0x5f => unkown, - 0x60 => event::VirtualKeyCode::F5, - 0x61 => event::VirtualKeyCode::F6, - 0x62 => event::VirtualKeyCode::F7, - 0x63 => event::VirtualKeyCode::F3, - 0x64 => event::VirtualKeyCode::F8, - 0x65 => event::VirtualKeyCode::F9, - //0x66 => unkown, - 0x67 => event::VirtualKeyCode::F11, - //0x68 => unkown, - 0x69 => event::VirtualKeyCode::F13, - 0x6a => event::VirtualKeyCode::F16, - 0x6b => event::VirtualKeyCode::F14, - //0x6c => unkown, - 0x6d => event::VirtualKeyCode::F10, - //0x6e => unkown, - 0x6f => event::VirtualKeyCode::F12, - //0x70 => unkown, - 0x71 => event::VirtualKeyCode::F15, - 0x72 => event::VirtualKeyCode::Insert, - 0x73 => event::VirtualKeyCode::Home, - 0x74 => event::VirtualKeyCode::PageUp, - 0x75 => event::VirtualKeyCode::Delete, - 0x76 => event::VirtualKeyCode::F4, - 0x77 => event::VirtualKeyCode::End, - 0x78 => event::VirtualKeyCode::F2, - 0x79 => event::VirtualKeyCode::PageDown, - 0x7a => event::VirtualKeyCode::F1, - 0x7b => event::VirtualKeyCode::Left, - 0x7c => event::VirtualKeyCode::Right, - 0x7d => event::VirtualKeyCode::Down, - 0x7e => event::VirtualKeyCode::Up, - //0x7f => unkown, - - 0xa => event::VirtualKeyCode::Caret, - _ => return None, - }) -} - -pub fn check_additional_virtual_key_codes( - s: &Option -) -> Option { - if let &Some(ref s) = s { - if let Some(ch) = s.encode_utf16().next() { - return Some(match ch { - 0xf718 => event::VirtualKeyCode::F21, - 0xf719 => event::VirtualKeyCode::F22, - 0xf71a => event::VirtualKeyCode::F23, - 0xf71b => event::VirtualKeyCode::F24, - _ => return None, - }) - } - } - None -} - -pub fn event_mods(event: id) -> ModifiersState { - let flags = unsafe { - NSEvent::modifierFlags(event) - }; - ModifiersState { - shift: flags.contains(NSEventModifierFlags::NSShiftKeyMask), - ctrl: flags.contains(NSEventModifierFlags::NSControlKeyMask), - alt: flags.contains(NSEventModifierFlags::NSAlternateKeyMask), - logo: flags.contains(NSEventModifierFlags::NSCommandKeyMask), - } -} - -pub unsafe fn modifier_event( - ns_event: id, - keymask: NSEventModifierFlags, - was_key_pressed: bool, -) -> Option { - if !was_key_pressed && NSEvent::modifierFlags(ns_event).contains(keymask) - || was_key_pressed && !NSEvent::modifierFlags(ns_event).contains(keymask) { - let state = if was_key_pressed { - ElementState::Released - } else { - ElementState::Pressed - }; - let keycode = NSEvent::keyCode(ns_event); - let scancode = keycode as u32; - let virtual_keycode = to_virtual_key_code(keycode); - Some(WindowEvent::KeyboardInput { - device_id: DEVICE_ID, - input: KeyboardInput { - state, - scancode, - virtual_keycode, - modifiers: event_mods(ns_event), - }, - }) - } else { - None } } diff --git a/src/platform_impl/macos/mod.rs b/src/platform_impl/macos/mod.rs index 26b15bf11b..6ed4bb11ad 100644 --- a/src/platform_impl/macos/mod.rs +++ b/src/platform_impl/macos/mod.rs @@ -2,6 +2,8 @@ mod app; mod app_delegate; +mod app_state; +mod event; mod event_loop; mod ffi; mod monitor; @@ -47,18 +49,11 @@ impl Deref for Window { impl Window { pub fn new( - elw_target: &EventLoopWindowTarget, + _window_target: &EventLoopWindowTarget, attributes: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result { - UnownedWindow::new(elw_target, attributes, pl_attribs) - .map(|(window, _delegate)| { - elw_target - .window_list - .lock() - .unwrap() - .insert_window(Arc::downgrade(&window)); - Window { window, _delegate } - }) + let (window, _delegate) = UnownedWindow::new(attributes, pl_attribs)?; + Ok(Window { window, _delegate }) } } diff --git a/src/platform_impl/macos/observer.rs b/src/platform_impl/macos/observer.rs index 64caf35383..374a53c632 100644 --- a/src/platform_impl/macos/observer.rs +++ b/src/platform_impl/macos/observer.rs @@ -1,6 +1,6 @@ use std::{self, ptr, os::raw::*, time::Instant}; -use platform_impl::platform::event_loop::HANDLER; +use platform_impl::platform::app_state::AppState; #[link(name = "CoreFoundation", kind = "framework")] extern { @@ -125,17 +125,15 @@ extern fn control_flow_begin_handler( activity: CFRunLoopActivity, _: *mut c_void, ) { - unsafe { - #[allow(non_upper_case_globals)] - match activity { - kCFRunLoopAfterWaiting => { - //trace!("Triggered `CFRunLoopAfterWaiting`"); - HANDLER.lock().unwrap().wakeup(); - //trace!("Completed `CFRunLoopAfterWaiting`"); - }, - kCFRunLoopEntry => unimplemented!(), // not expected to ever happen - _ => unreachable!(), - } + #[allow(non_upper_case_globals)] + match activity { + kCFRunLoopAfterWaiting => { + //trace!("Triggered `CFRunLoopAfterWaiting`"); + AppState::wakeup(); + //trace!("Completed `CFRunLoopAfterWaiting`"); + }, + kCFRunLoopEntry => unimplemented!(), // not expected to ever happen + _ => unreachable!(), } } @@ -146,17 +144,15 @@ extern fn control_flow_end_handler( activity: CFRunLoopActivity, _: *mut c_void, ) { - unsafe { - #[allow(non_upper_case_globals)] - match activity { - kCFRunLoopBeforeWaiting => { - //trace!("Triggered `CFRunLoopBeforeWaiting`"); - HANDLER.lock().unwrap().cleared(); - //trace!("Completed `CFRunLoopBeforeWaiting`"); - }, - kCFRunLoopExit => (),//unimplemented!(), // not expected to ever happen - _ => unreachable!(), - } + #[allow(non_upper_case_globals)] + match activity { + kCFRunLoopBeforeWaiting => { + //trace!("Triggered `CFRunLoopBeforeWaiting`"); + AppState::cleared(); + //trace!("Completed `CFRunLoopBeforeWaiting`"); + }, + kCFRunLoopExit => (),//unimplemented!(), // not expected to ever happen + _ => unreachable!(), } } diff --git a/src/platform_impl/macos/util.rs b/src/platform_impl/macos/util.rs index c59929dd0d..3b7bc54416 100644 --- a/src/platform_impl/macos/util.rs +++ b/src/platform_impl/macos/util.rs @@ -1,4 +1,4 @@ -use std::{ops::{BitAnd, Deref}, sync::{Arc, Mutex, Weak}}; +use std::ops::Deref; use cocoa::{ appkit::{NSApp, NSWindowStyleMask}, @@ -8,6 +8,7 @@ use cocoa::{ use core_graphics::display::CGDisplay; use objc::runtime::{BOOL, Class, Object, Sel, YES}; +pub use util::*; use platform_impl::platform::ffi; pub const EMPTY_RANGE: ffi::NSRange = ffi::NSRange { @@ -63,25 +64,6 @@ impl Clone for IdRef { } } -pub trait Access { - fn access O, O>(&self, callback: F) -> Option; -} - -impl Access for Arc> { - fn access O, O>(&self, callback: F) -> Option { - self.lock() - .ok() - .map(|ref mut mutex_guard| callback(mutex_guard)) - } -} - -impl Access for Weak> { - fn access O, O>(&self, callback: F) -> Option { - self.upgrade() - .and_then(|arc| arc.access(callback)) - } -} - // For consistency with other platforms, this will... // 1. translate the bottom-left window corner into the top-left window corner // 2. translate the coordinate from a bottom-left origin coordinate system to a top-left one @@ -89,13 +71,6 @@ pub fn bottom_left_to_top_left(rect: NSRect) -> f64 { CGDisplay::main().pixels_high() as f64 - (rect.origin.y + rect.size.height) } -pub fn has_flag(bitset: T, flag: T) -> bool -where T: - Copy + PartialEq + BitAnd -{ - bitset & flag == flag -} - pub unsafe fn set_style_mask(nswindow: id, nsview: id, mask: NSWindowStyleMask) { trace!("`set_style_mask` {:?} {:?} {:?}", nswindow, nsview, mask); use cocoa::appkit::NSWindow; diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index d91e409bf1..516b54f5f8 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -1,10 +1,7 @@ // This is a pretty close port of the implementation in GLFW: // https://github.com/glfw/glfw/blob/7ef34eb06de54dd9186d3d21a401b2ef819b59e7/src/cocoa_window.m -use std::{ - boxed::Box, collections::VecDeque, os::raw::*, - slice, str, sync::{Mutex, Weak}, -}; +use std::{boxed::Box, collections::VecDeque, os::raw::*, slice, str}; use cocoa::{ appkit::{NSApp, NSEvent, NSEventModifierFlags, NSEventPhase, NSView, NSWindow}, @@ -20,12 +17,9 @@ use { window::WindowId, }; use platform_impl::platform::{ - DEVICE_ID, - event_loop::{ - check_additional_virtual_key_codes, event_mods, modifier_event, - PendingEvents, to_virtual_key_code, - }, - util::{self, Access, IdRef}, ffi::*, window::get_window_id, + app_state::AppState, DEVICE_ID, + event::{check_function_keys, event_mods, modifier_event, to_virtual_keycode}, + util::{self, IdRef}, ffi::*, window::get_window_id, }; #[derive(Default)] @@ -38,17 +32,15 @@ struct Modifiers { struct ViewState { nswindow: id, - pending_events: Weak>, ime_spot: Option<(f64, f64)>, raw_characters: Option, is_key_down: bool, modifiers: Modifiers, } -pub fn new_view(nswindow: id, pending_events: Weak>) -> IdRef { +pub fn new_view(nswindow: id) -> IdRef { let state = ViewState { nswindow, - pending_events, ime_spot: None, raw_characters: None, is_key_down: false, @@ -263,7 +255,6 @@ extern fn init_with_winit(this: &Object, _sel: Sel, state: *mut c_void) -> id { extern fn view_did_move_to_window(this: &Object, _sel: Sel) { trace!("Triggered `viewDidMoveToWindow`"); unsafe { - let state: *mut c_void = *this.get_ivar("winitState"); let rect: NSRect = msg_send![this, visibleRect]; let _: () = msg_send![this, addTrackingRect:rect @@ -417,7 +408,7 @@ extern fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_range: }); } - state.pending_events.access(|pending| pending.queue_events(events)); + AppState::queue_events(events); } } @@ -450,7 +441,7 @@ extern fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) { } }; - state.pending_events.access(|pending| pending.queue_events(events)); + AppState::queue_events(events); } } @@ -479,10 +470,9 @@ extern fn key_down(this: &Object, _sel: Sel, event: id) { // We are checking here for F21-F24 keys, since their keycode // can vary, but we know that they are encoded // in characters property. - let virtual_keycode = to_virtual_key_code(keycode) - .or_else(|| { - check_additional_virtual_key_codes(&state.raw_characters) - }); + let virtual_keycode = to_virtual_keycode(keycode).or_else(|| { + check_function_keys(&state.raw_characters) + }); let scancode = keycode as u32; let is_repeat = msg_send![event, isARepeat]; @@ -510,24 +500,23 @@ extern fn key_down(this: &Object, _sel: Sel, event: id) { Some(string.to_owned()) }; - let pass_along = state.pending_events.access(|pending| { - pending.queue_event(window_event); + let pass_along = { + AppState::queue_event(window_event); // Emit `ReceivedCharacter` for key repeats - if is_repeat && state.is_key_down{ + if is_repeat && state.is_key_down { for character in string.chars() { - let window_event = Event::WindowEvent { + AppState::queue_event(Event::WindowEvent { window_id, event: WindowEvent::ReceivedCharacter(character), - }; - pending.queue_event(window_event); + }); } false } else { true } - }); + }; - if let Some(true) = pass_along { + if pass_along { // Some keys (and only *some*, with no known reason) don't trigger `insertText`, while others do... // So, we don't give repeats the opportunity to trigger that, since otherwise our hack will cause some // keys to generate twice as many characters. @@ -550,9 +539,9 @@ extern fn key_up(this: &Object, _sel: Sel, event: id) { let characters = get_characters(event); let keycode: c_ushort = msg_send![event, keyCode]; - let virtual_keycode = to_virtual_key_code(keycode) + let virtual_keycode = to_virtual_keycode(keycode) .or_else(|| { - check_additional_virtual_key_codes(&characters) + check_function_keys(&characters) }); let scancode = keycode as u32; let window_event = Event::WindowEvent { @@ -568,7 +557,7 @@ extern fn key_up(this: &Object, _sel: Sel, event: id) { }, }; - state.pending_events.access(|pending| pending.queue_event(window_event)); + AppState::queue_event(window_event); } } @@ -616,12 +605,12 @@ extern fn flags_changed(this: &Object, _sel: Sel, event: id) { events.push_back(window_event); } - state.pending_events.access(|pending| for event in events { - pending.queue_event(Event::WindowEvent { + for event in events { + AppState::queue_event(Event::WindowEvent { window_id: WindowId(get_window_id(state.nswindow)), event, }); - }); + } } } @@ -656,7 +645,7 @@ extern fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { let state = &mut *(state_ptr as *mut ViewState); let scancode = 0x2f; - let virtual_keycode = to_virtual_key_code(scancode); + let virtual_keycode = to_virtual_keycode(scancode); debug_assert_eq!(virtual_keycode, Some(VirtualKeyCode::Period)); let event: id = msg_send![NSApp(), currentEvent]; @@ -674,9 +663,7 @@ extern fn cancel_operation(this: &Object, _sel: Sel, _sender: id) { }, }; - state.pending_events.access(|pending| { - pending.queue_event(window_event); - }); + AppState::queue_event(window_event); } } @@ -695,7 +682,7 @@ fn mouse_click(this: &Object, event: id, button: MouseButton, button_state: Elem }, }; - state.pending_events.access(|pending| pending.queue_event(window_event)); + AppState::queue_event(window_event); } } @@ -755,7 +742,7 @@ fn mouse_motion(this: &Object, event: id) { }, }; - state.pending_events.access(|pending| pending.queue_event(window_event)); + AppState::queue_event(window_event); } } @@ -805,10 +792,8 @@ extern fn mouse_entered(this: &Object, _sel: Sel, event: id) { } }; - state.pending_events.access(|pending| { - pending.queue_event(enter_event); - pending.queue_event(move_event); - }); + AppState::queue_event(enter_event); + AppState::queue_event(move_event); } } @@ -823,9 +808,7 @@ extern fn mouse_exited(this: &Object, _sel: Sel, _event: id) { event: WindowEvent::CursorLeft { device_id: DEVICE_ID }, }; - state.pending_events.access(|pending| { - pending.queue_event(window_event); - }); + AppState::queue_event(window_event); } } @@ -864,10 +847,8 @@ extern fn scroll_wheel(this: &Object, _sel: Sel, event: id) { }, }; - state.pending_events.access(|pending| { - pending.queue_event(device_event); - pending.queue_event(window_event); - }); + AppState::queue_event(device_event); + AppState::queue_event(window_event); } } @@ -889,9 +870,7 @@ extern fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { }, }; - state.pending_events.access(|pending| { - pending.queue_event(window_event); - }); + AppState::queue_event(window_event); } } diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 91af369caf..8a42923f12 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -1,6 +1,6 @@ use std::{ collections::VecDeque, f64, os::raw::c_void, - sync::{Arc, atomic::{Ordering, AtomicBool}, Mutex, Weak}, + sync::{Arc, atomic::{Ordering, AtomicBool}, Mutex}, }; use cocoa::{ @@ -22,8 +22,7 @@ use { }; use platform::macos::{ActivationPolicy, WindowExtMacOS}; use platform_impl::platform::{ - {ffi, util::{self, Access, IdRef}}, - event_loop::{EventLoopWindowTarget, PendingEvents, WindowList}, + {ffi, util::{self, IdRef}}, monitor::{self, MonitorHandle}, view::{new_view, set_ime_spot}, window_delegate::{WindowDelegate, WindowDelegateState}, @@ -68,11 +67,8 @@ fn create_app(activation_policy: ActivationPolicy) -> Option { } } -unsafe fn create_view( - nswindow: id, - pending_events: Weak>, -) -> Option { - new_view(nswindow, pending_events).non_nil().map(|nsview| { +unsafe fn create_view(nswindow: id) -> Option { + new_view(nswindow).non_nil().map(|nsview| { nsview.setWantsBestResolutionOpenGLSurface_(YES); // On Mojave, views automatically become layer-backed shortly after being added to @@ -236,7 +232,6 @@ pub struct UnownedWindow { pub nswindow: IdRef, // never changes pub nsview: IdRef, // never changes input_context: IdRef, // never changes - window_list: Weak>, pub shared_state: Mutex, decorations: AtomicBool, cursor_hidden: AtomicBool, @@ -246,8 +241,7 @@ unsafe impl Send for UnownedWindow {} unsafe impl Sync for UnownedWindow {} impl UnownedWindow { - pub fn new( - elw_target: &EventLoopWindowTarget, + pub fn new( mut win_attribs: WindowAttributes, pl_attribs: PlatformSpecificWindowBuilderAttributes, ) -> Result<(Arc, WindowDelegate), CreationError> { @@ -269,9 +263,7 @@ impl UnownedWindow { CreationError::OsError(format!("Couldn't create `NSWindow`")) })?; - let nsview = unsafe { - create_view(*nswindow, Arc::downgrade(&elw_target.pending_events)) - }.ok_or_else(|| { + let nsview = unsafe { create_view(*nswindow) }.ok_or_else(|| { let _: () = unsafe { msg_send![autoreleasepool, drain] }; CreationError::OsError(format!("Couldn't create `NSView`")) })?; @@ -311,7 +303,6 @@ impl UnownedWindow { nsview, nswindow, input_context, - window_list: Arc::downgrade(&elw_target.window_list), shared_state: Mutex::new(win_attribs.into()), decorations: AtomicBool::new(decorations), cursor_hidden: Default::default(), @@ -319,7 +310,6 @@ impl UnownedWindow { let delegate = WindowDelegate::new(WindowDelegateState::new( &window, - elw_target, fullscreen.is_some(), )); @@ -463,7 +453,7 @@ impl UnownedWindow { } unsafe { util::set_style_mask(*self.nswindow, *self.nsview, mask) }; } // Otherwise, we don't change the mask until we exit fullscreen. - trace!("Unlocked shared state in `set_decorations`"); + trace!("Unlocked shared state in `set_resizable`"); } pub fn set_cursor(&self, cursor: MouseCursor) { @@ -528,9 +518,7 @@ impl UnownedWindow { #[inline] pub fn get_hidpi_factor(&self) -> f64 { - unsafe { - NSWindow::backingScaleFactor(*self.nswindow) as f64 - } + unsafe { NSWindow::backingScaleFactor(*self.nswindow) as _ } } #[inline] @@ -794,12 +782,9 @@ impl Drop for UnownedWindow { fn drop(&mut self) { trace!("Dropping `UnownedWindow` ({:?})", self as *mut _); - let id = self.id(); - self.window_list.access(|windows| windows.remove_window(id)); - // nswindow::close uses autorelease // so autorelease pool - let autoreleasepool = unsafe { NSAutoreleasePool::new(nil) }; + let pool = unsafe { NSAutoreleasePool::new(nil) }; // Close the window if it has not yet been closed. let nswindow = *self.nswindow; @@ -807,7 +792,7 @@ impl Drop for UnownedWindow { let _: () = unsafe { msg_send![nswindow, close] }; } - let _: () = unsafe { msg_send![autoreleasepool, drain] }; + let _: () = unsafe { msg_send![pool, drain] }; } } diff --git a/src/platform_impl/macos/window_delegate.rs b/src/platform_impl/macos/window_delegate.rs index af81a029aa..5f5b616e49 100644 --- a/src/platform_impl/macos/window_delegate.rs +++ b/src/platform_impl/macos/window_delegate.rs @@ -1,20 +1,14 @@ -use std::{f64, os::raw::c_void, sync::{Arc, Mutex, Weak}}; +use std::{f64, os::raw::c_void, sync::{Arc, Weak}}; use cocoa::{ - appkit::{self, NSView, NSWindow}, - base::{id, nil}, + appkit::{self, NSView, NSWindow}, base::{id, nil}, foundation::NSAutoreleasePool, }; use objc::{runtime::{Class, Object, Sel, BOOL, YES, NO}, declare::ClassDecl}; -use { - dpi::LogicalSize, - event::{Event, WindowEvent}, - window::WindowId, -}; +use {dpi::LogicalSize, event::{Event, WindowEvent}, window::WindowId}; use platform_impl::platform::{ - event_loop::{EventLoopWindowTarget, PendingEvents, WindowList}, - util::{self, Access, IdRef}, + app_state::AppState, util::{self, IdRef}, window::{get_window_id, UnownedWindow}, }; @@ -23,8 +17,6 @@ pub struct WindowDelegateState { nsview: IdRef, // never changes window: Weak, - pending_events: Weak>, - window_list: Weak>, // TODO: It's possible for delegate methods to be called asynchronously, // causing data races / `RefCell` panics. @@ -41,9 +33,8 @@ pub struct WindowDelegateState { } impl WindowDelegateState { - pub fn new( + pub fn new( window: &Arc, - elw_target: &EventLoopWindowTarget, initial_fullscreen: bool, ) -> Self { let dpi_factor = window.get_hidpi_factor(); @@ -52,8 +43,6 @@ impl WindowDelegateState { nswindow: window.nswindow.clone(), nsview: window.nsview.clone(), window: Arc::downgrade(&window), - pending_events: Arc::downgrade(&elw_target.pending_events), - window_list: Arc::downgrade(&elw_target.window_list), initial_fullscreen, previous_position: None, previous_dpi_factor: dpi_factor, @@ -80,9 +69,7 @@ impl WindowDelegateState { window_id: WindowId(get_window_id(*self.nswindow)), event, }; - trace!("Locked pending events in `emit_event`"); - self.pending_events.access(|pending| pending.queue_event(event)); - trace!("Unlocked pending events in `emit_event`"); + AppState::queue_event(event); } pub fn emit_resize_event(&mut self) { @@ -254,12 +241,7 @@ extern fn window_should_close(this: &Object, _: Sel, _: id) -> BOOL { extern fn window_will_close(this: &Object, _: Sel, _: id) { trace!("Triggered `windowWillClose`"); - with_state(this, |state| { - state.emit_event(WindowEvent::Destroyed); - state.window_list.access(|windows| { - windows.remove_window(get_window_id(*state.nswindow)); - }); - }); + with_state(this, |state| state.emit_event(WindowEvent::Destroyed)); trace!("Completed `windowWillClose`"); } diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 0d0a2efcab..a9ca557705 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -21,12 +21,7 @@ use winapi::um::winnt::{ }; use winapi::um::winuser; -pub fn has_flag(bitset: T, flag: T) -> bool -where T: - Copy + PartialEq + BitAnd -{ - bitset & flag == flag -} +pub use util::has_flag; pub fn wchar_to_string(wchar: &[wchar_t]) -> String { String::from_utf16_lossy(wchar).to_string() diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000000..1ee0765a17 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,11 @@ +use std::ops::BitAnd; + +// Replace with `!` once stable +pub enum Never {} + +pub fn has_flag(bitset: T, flag: T) -> bool +where T: + Copy + PartialEq + BitAnd +{ + bitset & flag == flag +}