Skip to content

Commit

Permalink
macOS: Dpi overhaul (#997) (and rebase changes)
Browse files Browse the repository at this point in the history
* WIP - Make EL2 DPI changes and implement on Windows (#895)

* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static

* fix app_state errors

* fixes hidpi related errors in window_delegate

* fix bad merge

* dpi_factor edits in window_delegate

* fixes type and lifetime errors in window and window_delegate

* applies fmt

* complies with @aleksijuvani requested changes

* modifies Handler lifetimes

* fixes lifetime isues, adds propper handling for HiDpiChanged

* applies fmt

* restore original lifetimes

* solution is somewhere out there

* applies fmt

* pass as references

* resolves issue with HANDLER

* crate visible type error

* fixes visibility issues

* applies fmt

* deals with warnings

* simplifies new_inner_size setting algorthm

* moves proxy instead of referencing it and removes double deref from proxy.ns_window

* makes @Osspial tests (#997) pass

* complies with @aleksijuvani suggested changes

* makes max window size std::f32::MAX

Changes from rebasing:

* fixes compile errors

* applies fmt

* reimplements HiDpiFactorChanged after #1173 merge

* uses EventWrappers
  • Loading branch information
vbogaevsky authored and Osspial committed Jan 5, 2020
1 parent 7b43b0b commit 077ee4d
Show file tree
Hide file tree
Showing 10 changed files with 273 additions and 153 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ cocoa = "0.19.1"
core-foundation = "0.6"
core-graphics = "0.17.3"
dispatch = "0.1.4"
objc = "0.2.3"
objc = "0.2.6"

[target.'cfg(target_os = "macos")'.dependencies.core-video-sys]
version = "0.1.3"
Expand Down
20 changes: 13 additions & 7 deletions examples/multithreaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ fn main() {
use std::{collections::HashMap, sync::mpsc, thread, time::Duration};

use winit::{
dpi::{PhysicalPosition, PhysicalSize},
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::{CursorIcon, Fullscreen, WindowBuilder},
Expand Down Expand Up @@ -122,12 +122,18 @@ fn main() {
),
false => WINDOW_SIZE,
}),
W => window
.set_cursor_position(PhysicalPosition::new(
WINDOW_SIZE.width as f64 / 2.0,
WINDOW_SIZE.height as f64 / 2.0,
))
.unwrap(),
W => {
if let Size::Physical(size) = WINDOW_SIZE.into() {
window
.set_cursor_position(Position::Physical(
PhysicalPosition::new(
size.width as f64 / 2.0,
size.height as f64 / 2.0,
),
))
.unwrap()
}
}
Z => {
window.set_visible(false);
thread::sleep(Duration::from_secs(1));
Expand Down
22 changes: 11 additions & 11 deletions src/platform_impl/macos/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use objc::{

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

pub struct AppClass(pub *const Class);
Expand Down Expand Up @@ -71,59 +71,59 @@ unsafe fn maybe_dispatch_device_event(event: id) {
let delta_y = event.deltaY() as f64;

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

if delta_y != 0.0 {
events.push_back(Event::DeviceEvent {
events.push_back(EventWrapper::StaticEvent(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 {
events.push_back(EventWrapper::StaticEvent(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::MouseMotion {
delta: (delta_x, delta_y),
},
});
}));
}

AppState::queue_events(events);
}
appkit::NSLeftMouseDown | appkit::NSRightMouseDown | appkit::NSOtherMouseDown => {
let mut events = VecDeque::with_capacity(1);

events.push_back(Event::DeviceEvent {
events.push_back(EventWrapper::StaticEvent(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::Button {
button: event.buttonNumber() as u32,
state: ElementState::Pressed,
},
});
}));

AppState::queue_events(events);
}
appkit::NSLeftMouseUp | appkit::NSRightMouseUp | appkit::NSOtherMouseUp => {
let mut events = VecDeque::with_capacity(1);

events.push_back(Event::DeviceEvent {
events.push_back(EventWrapper::StaticEvent(Event::DeviceEvent {
device_id: DEVICE_ID,
event: DeviceEvent::Button {
button: event.buttonNumber() as u32,
state: ElementState::Released,
},
});
}));

AppState::queue_events(events);
}
Expand Down
116 changes: 86 additions & 30 deletions src/platform_impl/macos/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,21 @@ use std::{
};

use cocoa::{
appkit::NSApp,
appkit::{NSApp, NSWindow},
base::nil,
foundation::{NSAutoreleasePool, NSString},
foundation::{NSAutoreleasePool, NSSize, NSString},
};

use crate::{
event::{Event, StartCause},
dpi::LogicalSize,
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoopWindowTarget as RootWindowTarget},
platform_impl::platform::{observer::EventLoopWaker, util::Never},
platform_impl::platform::{
event::{EventProxy, EventWrapper},
observer::EventLoopWaker,
util::{IdRef, Never},
window::get_window_id,
},
window::WindowId,
};
use objc::runtime::Object;
Expand All @@ -29,8 +35,8 @@ lazy_static! {
static ref HANDLER: Handler = Default::default();
}

impl Event<Never> {
fn userify<T: 'static>(self) -> Event<T> {
impl<'a, Never> Event<'a, Never> {
fn userify<T: 'static>(self) -> Event<'a, T> {
self.map_nonuser_event()
// `Never` can't be constructed, so the `UserEvent` variant can't
// be present here.
Expand All @@ -39,12 +45,13 @@ impl Event<Never> {
}

pub trait EventHandler: Debug {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
// Not sure probably it should accept Event<'static, Never>
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<T: 'static> {
callback: Box<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>,
callback: Box<dyn FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow)>,
will_exit: bool,
window_target: Rc<RootWindowTarget<T>>,
}
Expand All @@ -59,7 +66,7 @@ impl<T> Debug for EventLoopHandler<T> {
}

impl<T> EventHandler for EventLoopHandler<T> {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
fn handle_nonuser_event(&mut self, event: Event<'_, Never>, control_flow: &mut ControlFlow) {
(self.callback)(event.userify(), &self.window_target, control_flow);
self.will_exit |= *control_flow == ControlFlow::Exit;
if self.will_exit {
Expand Down Expand Up @@ -88,7 +95,7 @@ struct Handler {
control_flow_prev: Mutex<ControlFlow>,
start_time: Mutex<Option<Instant>>,
callback: Mutex<Option<Box<dyn EventHandler>>>,
pending_events: Mutex<VecDeque<Event<Never>>>,
pending_events: Mutex<VecDeque<EventWrapper>>,
pending_redraw: Mutex<Vec<WindowId>>,
waker: Mutex<EventLoopWaker>,
}
Expand All @@ -97,15 +104,15 @@ unsafe impl Send for Handler {}
unsafe impl Sync for Handler {}

impl Handler {
fn events<'a>(&'a self) -> MutexGuard<'a, VecDeque<Event<Never>>> {
fn events(&self) -> MutexGuard<'_, VecDeque<EventWrapper>> {
self.pending_events.lock().unwrap()
}

fn redraw<'a>(&'a self) -> MutexGuard<'a, Vec<WindowId>> {
self.pending_redraw.lock().unwrap()
}

fn waker<'a>(&'a self) -> MutexGuard<'a, EventLoopWaker> {
fn waker(&self) -> MutexGuard<'_, EventLoopWaker> {
self.waker.lock().unwrap()
}

Expand Down Expand Up @@ -141,7 +148,7 @@ impl Handler {
*self.start_time.lock().unwrap() = Some(Instant::now());
}

fn take_events(&self) -> VecDeque<Event<Never>> {
fn take_events(&self) -> VecDeque<EventWrapper> {
mem::replace(&mut *self.events(), Default::default())
}

Expand All @@ -157,9 +164,14 @@ impl Handler {
self.in_callback.store(in_callback, Ordering::Release);
}

fn handle_nonuser_event(&self, event: Event<Never>) {
fn handle_nonuser_event(&self, wrapper: EventWrapper) {
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
callback.handle_nonuser_event(event, &mut *self.control_flow.lock().unwrap());
match wrapper {
EventWrapper::StaticEvent(event) => {
callback.handle_nonuser_event(event, &mut *self.control_flow.lock().unwrap())
}
EventWrapper::EventProxy(proxy) => self.handle_proxy(proxy, callback),
}
}
}

Expand All @@ -168,6 +180,46 @@ impl Handler {
callback.handle_user_events(&mut *self.control_flow.lock().unwrap());
}
}

fn handle_hidpi_factor_changed_event(
&self,
callback: &mut Box<dyn EventHandler + 'static>,
ns_window: IdRef,
suggested_size: LogicalSize,
hidpi_factor: f64,
) {
let size = suggested_size.to_physical(hidpi_factor);
let new_inner_size = &mut Some(size);
let event = Event::WindowEvent {
window_id: WindowId(get_window_id(*ns_window)),
event: WindowEvent::HiDpiFactorChanged {
hidpi_factor,
new_inner_size,
},
};

callback.handle_nonuser_event(event, &mut *self.control_flow.lock().unwrap());

let physical_size = new_inner_size.unwrap_or(size);
let logical_size = physical_size.to_logical(hidpi_factor);
let size = NSSize::new(logical_size.width, logical_size.height);
unsafe { NSWindow::setContentSize_(*ns_window, size) };
}

fn handle_proxy(&self, proxy: EventProxy, callback: &mut Box<dyn EventHandler + 'static>) {
match proxy {
EventProxy::HiDpiFactorChangedProxy {
ns_window,
suggested_size,
hidpi_factor,
} => self.handle_hidpi_factor_changed_event(
callback,
ns_window,
suggested_size,
hidpi_factor,
),
}
}
}

pub enum AppState {}
Expand All @@ -176,16 +228,16 @@ impl AppState {
// This function extends lifetime of `callback` to 'static as its side effect
pub unsafe fn set_callback<F, T>(callback: F, window_target: Rc<RootWindowTarget<T>>)
where
F: FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
{
*HANDLER.callback.lock().unwrap() = Some(Box::new(EventLoopHandler {
// This transmute is always safe, in case it was reached through `run`, since our
// lifetime will be already 'static. In other cases caller should ensure that all data
// they passed to callback will actually outlive it, some apps just can't move
// everything to event loop, so this is something that they should care about.
callback: mem::transmute::<
Box<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow)>,
>(Box::new(callback)),
will_exit: false,
window_target,
Expand All @@ -194,7 +246,7 @@ impl AppState {

pub fn exit() {
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::LoopDestroyed);
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::LoopDestroyed));
HANDLER.set_in_callback(false);
HANDLER.callback.lock().unwrap().take();
}
Expand All @@ -203,7 +255,9 @@ impl AppState {
HANDLER.set_ready();
HANDLER.waker().start();
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::NewEvents(StartCause::Init));
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::NewEvents(
StartCause::Init,
)));
HANDLER.set_in_callback(false);
}

Expand Down Expand Up @@ -234,7 +288,7 @@ impl AppState {
ControlFlow::Exit => StartCause::Poll, //panic!("unexpected `ControlFlow::Exit`"),
};
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::NewEvents(cause));
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::NewEvents(cause)));
HANDLER.set_in_callback(false);
}

Expand All @@ -246,18 +300,18 @@ impl AppState {
}
}

pub fn queue_event(event: Event<Never>) {
pub fn queue_event(wrapper: EventWrapper) {
if !unsafe { msg_send![class!(NSThread), isMainThread] } {
panic!("Event queued from different thread: {:#?}", event);
panic!("Event queued from different thread: {:#?}", wrapper);
}
HANDLER.events().push_back(event);
HANDLER.events().push_back(wrapper);
}

pub fn queue_events(mut events: VecDeque<Event<Never>>) {
pub fn queue_events(mut wrappers: VecDeque<EventWrapper>) {
if !unsafe { msg_send![class!(NSThread), isMainThread] } {
panic!("Events queued from different thread: {:#?}", events);
panic!("Events queued from different thread: {:#?}", wrappers);
}
HANDLER.events().append(&mut events);
HANDLER.events().append(&mut wrappers);
}

pub fn cleared() {
Expand All @@ -270,11 +324,13 @@ impl AppState {
for event in HANDLER.take_events() {
HANDLER.handle_nonuser_event(event);
}
HANDLER.handle_nonuser_event(Event::MainEventsCleared);
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::MainEventsCleared));
for window_id in HANDLER.should_redraw() {
HANDLER.handle_nonuser_event(Event::RedrawRequested(window_id));
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::RedrawRequested(
window_id,
)));
}
HANDLER.handle_nonuser_event(Event::RedrawEventsCleared);
HANDLER.handle_nonuser_event(EventWrapper::StaticEvent(Event::RedrawEventsCleared));
HANDLER.set_in_callback(false);
}
if HANDLER.should_exit() {
Expand Down
Loading

0 comments on commit 077ee4d

Please sign in to comment.