mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
macOS: Dpi overhaul (#997) (and rebase changes)
* 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 (https://github.com/rust-windowing/winit/pull/997\#discussion_r301852354) 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
This commit is contained in:
parent
7b43b0bc94
commit
077ee4d851
|
@ -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"
|
||||
|
|
|
@ -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},
|
||||
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
@ -71,32 +71,32 @@ 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);
|
||||
|
@ -104,26 +104,26 @@ unsafe fn maybe_dispatch_device_event(event: id) {
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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>>,
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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>,
|
||||
}
|
||||
|
@ -97,7 +104,7 @@ 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()
|
||||
}
|
||||
|
||||
|
@ -105,7 +112,7 @@ impl Handler {
|
|||
self.pending_redraw.lock().unwrap()
|
||||
}
|
||||
|
||||
fn waker<'a>(&'a self) -> MutexGuard<'a, EventLoopWaker> {
|
||||
fn waker(&self) -> MutexGuard<'_, EventLoopWaker> {
|
||||
self.waker.lock().unwrap()
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -176,7 +228,7 @@ 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
|
||||
|
@ -184,8 +236,8 @@ impl AppState {
|
|||
// 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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
|
|
@ -6,10 +6,29 @@ use cocoa::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent},
|
||||
platform_impl::platform::DEVICE_ID,
|
||||
dpi::LogicalSize,
|
||||
event::{ElementState, Event, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent},
|
||||
platform_impl::platform::{
|
||||
util::{IdRef, Never},
|
||||
DEVICE_ID,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EventWrapper {
|
||||
StaticEvent(Event<'static, Never>),
|
||||
EventProxy(EventProxy),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum EventProxy {
|
||||
HiDpiFactorChangedProxy {
|
||||
ns_window: IdRef,
|
||||
suggested_size: LogicalSize,
|
||||
hidpi_factor: f64,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn char_to_keycode(c: char) -> Option<VirtualKeyCode> {
|
||||
// We only translate keys that are affected by keyboard layout.
|
||||
//
|
||||
|
@ -256,7 +275,7 @@ pub unsafe fn modifier_event(
|
|||
ns_event: id,
|
||||
keymask: NSEventModifierFlags,
|
||||
was_key_pressed: bool,
|
||||
) -> Option<WindowEvent> {
|
||||
) -> Option<WindowEvent<'static>> {
|
||||
if !was_key_pressed && NSEvent::modifierFlags(ns_event).contains(keymask)
|
||||
|| was_key_pressed && !NSEvent::modifierFlags(ns_event).contains(keymask)
|
||||
{
|
||||
|
|
|
@ -84,7 +84,7 @@ impl<T> EventLoop<T> {
|
|||
|
||||
pub fn run<F>(mut self, callback: F) -> !
|
||||
where
|
||||
F: 'static + FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||
F: 'static + FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||
{
|
||||
self.run_return(callback);
|
||||
process::exit(0);
|
||||
|
@ -92,7 +92,7 @@ impl<T> EventLoop<T> {
|
|||
|
||||
pub fn run_return<F>(&mut self, callback: F)
|
||||
where
|
||||
F: FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||
F: FnMut(Event<'_, T>, &RootWindowTarget<T>, &mut ControlFlow),
|
||||
{
|
||||
unsafe {
|
||||
let pool = NSAutoreleasePool::new(nil);
|
||||
|
|
|
@ -31,6 +31,7 @@ pub const EMPTY_RANGE: ffi::NSRange = ffi::NSRange {
|
|||
length: 0,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct IdRef(id);
|
||||
|
||||
impl IdRef {
|
||||
|
|
|
@ -25,7 +25,7 @@ use crate::{
|
|||
app_state::AppState,
|
||||
event::{
|
||||
char_to_keycode, check_function_keys, event_mods, get_scancode, modifier_event,
|
||||
scancode_to_keycode,
|
||||
scancode_to_keycode, EventWrapper,
|
||||
},
|
||||
ffi::*,
|
||||
util::{self, IdRef},
|
||||
|
@ -512,10 +512,10 @@ extern "C" fn insert_text(this: &Object, _sel: Sel, string: id, _replacement_ran
|
|||
|
||||
let mut events = VecDeque::with_capacity(characters.len());
|
||||
for character in string.chars().filter(|c| !is_corporate_character(*c)) {
|
||||
events.push_back(Event::WindowEvent {
|
||||
events.push_back(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id: WindowId(get_window_id(state.ns_window)),
|
||||
event: WindowEvent::ReceivedCharacter(character),
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
AppState::queue_events(events);
|
||||
|
@ -536,10 +536,10 @@ extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) {
|
|||
// The `else` condition would emit the same character, but I'm keeping this here both...
|
||||
// 1) as a reminder for how `doCommandBySelector` works
|
||||
// 2) to make our use of carriage return explicit
|
||||
events.push_back(Event::WindowEvent {
|
||||
events.push_back(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id: WindowId(get_window_id(state.ns_window)),
|
||||
event: WindowEvent::ReceivedCharacter('\r'),
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
let raw_characters = state.raw_characters.take();
|
||||
if let Some(raw_characters) = raw_characters {
|
||||
|
@ -547,10 +547,10 @@ extern "C" fn do_command_by_selector(this: &Object, _sel: Sel, command: Sel) {
|
|||
.chars()
|
||||
.filter(|c| !is_corporate_character(*c))
|
||||
{
|
||||
events.push_back(Event::WindowEvent {
|
||||
events.push_back(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id: WindowId(get_window_id(state.ns_window)),
|
||||
event: WindowEvent::ReceivedCharacter(character),
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -646,14 +646,14 @@ extern "C" fn key_down(this: &Object, _sel: Sel, event: id) {
|
|||
};
|
||||
|
||||
let pass_along = {
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
// Emit `ReceivedCharacter` for key repeats
|
||||
if is_repeat && state.is_key_down {
|
||||
for character in characters.chars().filter(|c| !is_corporate_character(*c)) {
|
||||
AppState::queue_event(Event::WindowEvent {
|
||||
AppState::queue_event(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::ReceivedCharacter(character),
|
||||
});
|
||||
}));
|
||||
}
|
||||
false
|
||||
} else {
|
||||
|
@ -697,7 +697,7 @@ extern "C" fn key_up(this: &Object, _sel: Sel, event: id) {
|
|||
},
|
||||
};
|
||||
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
}
|
||||
trace!("Completed `keyUp`");
|
||||
}
|
||||
|
@ -747,16 +747,16 @@ extern "C" fn flags_changed(this: &Object, _sel: Sel, event: id) {
|
|||
}
|
||||
|
||||
for event in events {
|
||||
AppState::queue_event(Event::WindowEvent {
|
||||
AppState::queue_event(EventWrapper::StaticEvent(Event::WindowEvent {
|
||||
window_id: WindowId(get_window_id(state.ns_window)),
|
||||
event,
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
AppState::queue_event(Event::DeviceEvent {
|
||||
AppState::queue_event(EventWrapper::StaticEvent(Event::DeviceEvent {
|
||||
device_id: DEVICE_ID,
|
||||
event: DeviceEvent::ModifiersChanged(state.modifiers),
|
||||
});
|
||||
}));
|
||||
}
|
||||
trace!("Completed `flagsChanged`");
|
||||
}
|
||||
|
@ -811,7 +811,7 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
|
|||
},
|
||||
};
|
||||
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
}
|
||||
trace!("Completed `cancelOperation`");
|
||||
}
|
||||
|
@ -831,7 +831,7 @@ fn mouse_click(this: &Object, event: id, button: MouseButton, button_state: Elem
|
|||
},
|
||||
};
|
||||
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -892,7 +892,7 @@ fn mouse_motion(this: &Object, event: id) {
|
|||
},
|
||||
};
|
||||
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -944,8 +944,8 @@ extern "C" fn mouse_entered(this: &Object, _sel: Sel, event: id) {
|
|||
}
|
||||
};
|
||||
|
||||
AppState::queue_event(enter_event);
|
||||
AppState::queue_event(move_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(enter_event));
|
||||
AppState::queue_event(EventWrapper::StaticEvent(move_event));
|
||||
}
|
||||
trace!("Completed `mouseEntered`");
|
||||
}
|
||||
|
@ -963,7 +963,7 @@ extern "C" fn mouse_exited(this: &Object, _sel: Sel, _event: id) {
|
|||
},
|
||||
};
|
||||
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
}
|
||||
trace!("Completed `mouseExited`");
|
||||
}
|
||||
|
@ -1005,8 +1005,8 @@ extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
|
|||
},
|
||||
};
|
||||
|
||||
AppState::queue_event(device_event);
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(device_event));
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
}
|
||||
trace!("Completed `scrollWheel`");
|
||||
}
|
||||
|
@ -1029,7 +1029,7 @@ extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) {
|
|||
},
|
||||
};
|
||||
|
||||
AppState::queue_event(window_event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(window_event));
|
||||
}
|
||||
trace!("Completed `pressureChangeWithEvent`");
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
dpi::{LogicalPosition, LogicalSize},
|
||||
dpi::{
|
||||
LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size, Size::Logical,
|
||||
},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
icon::Icon,
|
||||
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
||||
|
@ -130,12 +132,17 @@ fn create_window(
|
|||
None => None,
|
||||
};
|
||||
let frame = match screen {
|
||||
Some(screen) => appkit::NSScreen::frame(screen),
|
||||
Some(screen) => NSScreen::frame(screen),
|
||||
None => {
|
||||
let (width, height) = attrs
|
||||
.inner_size
|
||||
.map(|logical| (logical.width, logical.height))
|
||||
.unwrap_or_else(|| (800.0, 600.0));
|
||||
let screen = NSScreen::mainScreen(nil);
|
||||
let hidpi_factor = NSScreen::backingScaleFactor(screen) as f64;
|
||||
let (width, height) = match attrs.inner_size {
|
||||
Some(size) => {
|
||||
let logical = size.to_logical(hidpi_factor);
|
||||
(logical.width, logical.height)
|
||||
}
|
||||
None => (800.0, 600.0),
|
||||
};
|
||||
NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(width, height))
|
||||
}
|
||||
};
|
||||
|
@ -292,6 +299,7 @@ pub struct UnownedWindow {
|
|||
pub shared_state: Arc<Mutex<SharedState>>,
|
||||
decorations: AtomicBool,
|
||||
cursor_state: Weak<Mutex<CursorState>>,
|
||||
pub inner_rect: Option<PhysicalSize>,
|
||||
}
|
||||
|
||||
unsafe impl Send for UnownedWindow {}
|
||||
|
@ -328,6 +336,8 @@ impl UnownedWindow {
|
|||
|
||||
let input_context = unsafe { util::create_input_context(*ns_view) };
|
||||
|
||||
let dpi_factor = unsafe { NSWindow::backingScaleFactor(*ns_window) as f64 };
|
||||
|
||||
unsafe {
|
||||
if win_attribs.transparent {
|
||||
ns_window.setOpaque_(NO);
|
||||
|
@ -335,13 +345,14 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
ns_app.activateIgnoringOtherApps_(YES);
|
||||
|
||||
win_attribs
|
||||
.min_inner_size
|
||||
.map(|dim| set_min_inner_size(*ns_window, dim));
|
||||
win_attribs
|
||||
.max_inner_size
|
||||
.map(|dim| set_max_inner_size(*ns_window, dim));
|
||||
win_attribs.min_inner_size.map(|dim| {
|
||||
let logical_dim = dim.to_logical(dpi_factor);
|
||||
set_min_inner_size(*ns_window, logical_dim)
|
||||
});
|
||||
win_attribs.max_inner_size.map(|dim| {
|
||||
let logical_dim = dim.to_logical(dpi_factor);
|
||||
set_max_inner_size(*ns_window, logical_dim)
|
||||
});
|
||||
|
||||
use cocoa::foundation::NSArray;
|
||||
// register for drag and drop operations.
|
||||
|
@ -361,6 +372,9 @@ impl UnownedWindow {
|
|||
let maximized = win_attribs.maximized;
|
||||
let visible = win_attribs.visible;
|
||||
let decorations = win_attribs.decorations;
|
||||
let inner_rect = win_attribs
|
||||
.inner_size
|
||||
.map(|size| size.to_physical(dpi_factor));
|
||||
|
||||
let window = Arc::new(UnownedWindow {
|
||||
ns_view,
|
||||
|
@ -369,6 +383,7 @@ impl UnownedWindow {
|
|||
shared_state: Arc::new(Mutex::new(win_attribs.into())),
|
||||
decorations: AtomicBool::new(decorations),
|
||||
cursor_state,
|
||||
inner_rect,
|
||||
});
|
||||
|
||||
let delegate = new_delegate(&window, fullscreen.is_some());
|
||||
|
@ -425,27 +440,31 @@ impl UnownedWindow {
|
|||
AppState::queue_redraw(RootWindowId(self.id()));
|
||||
}
|
||||
|
||||
pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
||||
pub fn outer_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||
let frame_rect = unsafe { NSWindow::frame(*self.ns_window) };
|
||||
Ok((
|
||||
let position = LogicalPosition::new(
|
||||
frame_rect.origin.x as f64,
|
||||
util::bottom_left_to_top_left(frame_rect),
|
||||
)
|
||||
.into())
|
||||
);
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
Ok(position.to_physical(dpi_factor))
|
||||
}
|
||||
|
||||
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
||||
pub fn inner_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||
let content_rect = unsafe {
|
||||
NSWindow::contentRectForFrameRect_(*self.ns_window, NSWindow::frame(*self.ns_window))
|
||||
};
|
||||
Ok((
|
||||
let position = LogicalPosition::new(
|
||||
content_rect.origin.x as f64,
|
||||
util::bottom_left_to_top_left(content_rect),
|
||||
)
|
||||
.into())
|
||||
);
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
Ok(position.to_physical(dpi_factor))
|
||||
}
|
||||
|
||||
pub fn set_outer_position(&self, position: LogicalPosition) {
|
||||
pub fn set_outer_position(&self, position: Position) {
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
let position = position.to_logical(dpi_factor);
|
||||
let dummy = NSRect::new(
|
||||
NSPoint::new(
|
||||
position.x,
|
||||
|
@ -461,35 +480,50 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner_size(&self) -> LogicalSize {
|
||||
pub fn inner_size(&self) -> PhysicalSize {
|
||||
let view_frame = unsafe { NSView::frame(*self.ns_view) };
|
||||
(view_frame.size.width as f64, view_frame.size.height as f64).into()
|
||||
let logical: LogicalSize =
|
||||
(view_frame.size.width as f64, view_frame.size.height as f64).into();
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
logical.to_physical(dpi_factor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn outer_size(&self) -> LogicalSize {
|
||||
pub fn outer_size(&self) -> PhysicalSize {
|
||||
let view_frame = unsafe { NSWindow::frame(*self.ns_window) };
|
||||
(view_frame.size.width as f64, view_frame.size.height as f64).into()
|
||||
let logical: LogicalSize =
|
||||
(view_frame.size.width as f64, view_frame.size.height as f64).into();
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
logical.to_physical(dpi_factor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_inner_size(&self, size: LogicalSize) {
|
||||
pub fn set_inner_size(&self, size: Size) {
|
||||
unsafe {
|
||||
util::set_content_size_async(*self.ns_window, size);
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
util::set_content_size_async(*self.ns_window, size.to_logical(dpi_factor));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_min_inner_size(&self, dimensions: Option<LogicalSize>) {
|
||||
pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
|
||||
unsafe {
|
||||
let dimensions = dimensions.unwrap_or_else(|| (0, 0).into());
|
||||
set_min_inner_size(*self.ns_window, dimensions);
|
||||
let dimensions = dimensions.unwrap_or(Logical(LogicalSize {
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
}));
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
set_min_inner_size(*self.ns_window, dimensions.to_logical(dpi_factor));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_max_inner_size(&self, dimensions: Option<LogicalSize>) {
|
||||
pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
|
||||
unsafe {
|
||||
let dimensions = dimensions.unwrap_or_else(|| (!0, !0).into());
|
||||
set_max_inner_size(*self.ns_window, dimensions);
|
||||
let dimensions = dimensions.unwrap_or(Logical(LogicalSize {
|
||||
width: std::f32::MAX as f64,
|
||||
height: std::f32::MAX as f64,
|
||||
}));
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
set_max_inner_size(*self.ns_window, dimensions.to_logical(dpi_factor));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,14 +588,14 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_position(
|
||||
&self,
|
||||
cursor_position: LogicalPosition,
|
||||
) -> Result<(), ExternalError> {
|
||||
let window_position = self.inner_position().unwrap();
|
||||
pub fn set_cursor_position(&self, cursor_position: Position) -> Result<(), ExternalError> {
|
||||
let physical_window_position = self.inner_position().unwrap();
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
let window_position = physical_window_position.to_logical(dpi_factor);
|
||||
let logical_cursor_position = cursor_position.to_logical(dpi_factor);
|
||||
let point = appkit::CGPoint {
|
||||
x: (cursor_position.x + window_position.x) as CGFloat,
|
||||
y: (cursor_position.y + window_position.y) as CGFloat,
|
||||
x: (logical_cursor_position.x + window_position.x) as CGFloat,
|
||||
y: (logical_cursor_position.y + window_position.y) as CGFloat,
|
||||
};
|
||||
CGDisplay::warp_mouse_cursor_position(point)
|
||||
.map_err(|e| ExternalError::Os(os_error!(OsError::CGError(e))))?;
|
||||
|
@ -894,7 +928,9 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_ime_position(&self, logical_spot: LogicalPosition) {
|
||||
pub fn set_ime_position(&self, spot: Position) {
|
||||
let dpi_factor = self.hidpi_factor();
|
||||
let logical_spot = spot.to_logical(dpi_factor);
|
||||
unsafe {
|
||||
view::set_ime_position(
|
||||
*self.ns_view,
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::{
|
|||
event::{Event, WindowEvent},
|
||||
platform_impl::platform::{
|
||||
app_state::AppState,
|
||||
event::{EventProxy, EventWrapper},
|
||||
util::{self, IdRef},
|
||||
window::{get_window_id, UnownedWindow},
|
||||
},
|
||||
|
@ -47,20 +48,18 @@ pub struct WindowDelegateState {
|
|||
|
||||
impl WindowDelegateState {
|
||||
pub fn new(window: &Arc<UnownedWindow>, initial_fullscreen: bool) -> Self {
|
||||
let dpi_factor = window.hidpi_factor();
|
||||
|
||||
let hidpi_factor = window.hidpi_factor();
|
||||
let mut delegate_state = WindowDelegateState {
|
||||
ns_window: window.ns_window.clone(),
|
||||
ns_view: window.ns_view.clone(),
|
||||
window: Arc::downgrade(&window),
|
||||
initial_fullscreen,
|
||||
previous_position: None,
|
||||
previous_dpi_factor: dpi_factor,
|
||||
previous_dpi_factor: hidpi_factor,
|
||||
};
|
||||
|
||||
if dpi_factor != 1.0 {
|
||||
delegate_state.emit_event(WindowEvent::HiDpiFactorChanged(dpi_factor));
|
||||
delegate_state.emit_resize_event();
|
||||
if hidpi_factor != 1.0 {
|
||||
delegate_state.emit_static_hidpi_factor_changed_event();
|
||||
}
|
||||
|
||||
delegate_state
|
||||
|
@ -73,17 +72,34 @@ impl WindowDelegateState {
|
|||
self.window.upgrade().map(|ref window| callback(window))
|
||||
}
|
||||
|
||||
pub fn emit_event(&mut self, event: WindowEvent) {
|
||||
pub fn emit_event(&mut self, event: WindowEvent<'static>) {
|
||||
let event = Event::WindowEvent {
|
||||
window_id: WindowId(get_window_id(*self.ns_window)),
|
||||
event,
|
||||
};
|
||||
AppState::queue_event(event);
|
||||
AppState::queue_event(EventWrapper::StaticEvent(event));
|
||||
}
|
||||
|
||||
pub fn emit_static_hidpi_factor_changed_event(&mut self) {
|
||||
let hidpi_factor = self.get_hidpi_factor();
|
||||
if hidpi_factor == self.previous_dpi_factor {
|
||||
return ();
|
||||
};
|
||||
|
||||
self.previous_dpi_factor = hidpi_factor;
|
||||
let wrapper = EventWrapper::EventProxy(EventProxy::HiDpiFactorChangedProxy {
|
||||
ns_window: IdRef::retain(*self.ns_window),
|
||||
suggested_size: self.view_size(),
|
||||
hidpi_factor,
|
||||
});
|
||||
AppState::queue_event(wrapper);
|
||||
}
|
||||
|
||||
pub fn emit_resize_event(&mut self) {
|
||||
let rect = unsafe { NSView::frame(*self.ns_view) };
|
||||
let size = LogicalSize::new(rect.size.width as f64, rect.size.height as f64);
|
||||
let hidpi_factor = self.get_hidpi_factor();
|
||||
let logical_size = LogicalSize::new(rect.size.width as f64, rect.size.height as f64);
|
||||
let size = logical_size.to_physical(hidpi_factor);
|
||||
self.emit_event(WindowEvent::Resized(size));
|
||||
}
|
||||
|
||||
|
@ -97,6 +113,15 @@ impl WindowDelegateState {
|
|||
self.emit_event(WindowEvent::Moved((x, y).into()));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_hidpi_factor(&self) -> f64 {
|
||||
(unsafe { NSWindow::backingScaleFactor(*self.ns_window) }) as f64
|
||||
}
|
||||
|
||||
fn view_size(&self) -> LogicalSize {
|
||||
let ns_size = unsafe { NSView::frame(*self.ns_view).size };
|
||||
LogicalSize::new(ns_size.width as f64, ns_size.height as f64)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_delegate(window: &Arc<UnownedWindow>, initial_fullscreen: bool) -> IdRef {
|
||||
|
@ -140,10 +165,6 @@ lazy_static! {
|
|||
sel!(windowDidMove:),
|
||||
window_did_move as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(windowDidChangeScreen:),
|
||||
window_did_change_screen as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(windowDidChangeBackingProperties:),
|
||||
window_did_change_backing_properties as extern "C" fn(&Object, Sel, id),
|
||||
|
@ -277,29 +298,10 @@ extern "C" fn window_did_move(this: &Object, _: Sel, _: id) {
|
|||
trace!("Completed `windowDidMove:`");
|
||||
}
|
||||
|
||||
extern "C" fn window_did_change_screen(this: &Object, _: Sel, _: id) {
|
||||
trace!("Triggered `windowDidChangeScreen:`");
|
||||
with_state(this, |state| {
|
||||
let dpi_factor = unsafe { NSWindow::backingScaleFactor(*state.ns_window) } as f64;
|
||||
if state.previous_dpi_factor != dpi_factor {
|
||||
state.previous_dpi_factor = dpi_factor;
|
||||
state.emit_event(WindowEvent::HiDpiFactorChanged(dpi_factor));
|
||||
state.emit_resize_event();
|
||||
}
|
||||
});
|
||||
trace!("Completed `windowDidChangeScreen:`");
|
||||
}
|
||||
|
||||
// This will always be called before `window_did_change_screen`.
|
||||
extern "C" fn window_did_change_backing_properties(this: &Object, _: Sel, _: id) {
|
||||
trace!("Triggered `windowDidChangeBackingProperties:`");
|
||||
with_state(this, |state| {
|
||||
let dpi_factor = unsafe { NSWindow::backingScaleFactor(*state.ns_window) } as f64;
|
||||
if state.previous_dpi_factor != dpi_factor {
|
||||
state.previous_dpi_factor = dpi_factor;
|
||||
state.emit_event(WindowEvent::HiDpiFactorChanged(dpi_factor));
|
||||
state.emit_resize_event();
|
||||
}
|
||||
state.emit_static_hidpi_factor_changed_event();
|
||||
});
|
||||
trace!("Completed `windowDidChangeBackingProperties:`");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue