Skip to content

Commit

Permalink
Update HiDpiFactorChanged
Browse files Browse the repository at this point in the history
  • Loading branch information
Osspial committed Jun 13, 2019
1 parent 7b35a7e commit d363fca
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 45 deletions.
4 changes: 3 additions & 1 deletion examples/multithreaded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ fn main() {
window_senders.remove(&window_id);
},
_ => if let Some(tx) = window_senders.get(&window_id) {
tx.send(event).unwrap();
if let Some(event) = event.to_static() {
tx.send(event).unwrap();
}
},
}
}
Expand Down
65 changes: 57 additions & 8 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ use window::WindowId;
use platform_impl;

/// Describes a generic event.
#[derive(Clone, Debug, PartialEq)]
pub enum Event<T> {
#[derive(Debug, PartialEq)]
pub enum Event<'a, T: 'static> {
/// Emitted when the OS sends an event to a winit window.
WindowEvent {
window_id: WindowId,
event: WindowEvent,
event: WindowEvent<'a>,
},
/// Emitted when the OS sends an event to a device.
DeviceEvent {
Expand All @@ -42,8 +42,8 @@ pub enum Event<T> {
Suspended(bool),
}

impl<T> Event<T> {
pub fn map_nonuser_event<U>(self) -> Result<Event<U>, Event<T>> {
impl<'a, T> Event<'a, T> {
pub fn map_nonuser_event<U>(self) -> Result<Event<'a, U>, Event<'a, T>> {
use self::Event::*;
match self {
UserEvent(_) => Err(self),
Expand All @@ -55,6 +55,19 @@ impl<T> Event<T> {
Suspended(suspended) => Ok(Suspended(suspended)),
}
}

pub fn to_static(self) -> Option<Event<'static, T>> {
use self::Event::*;
match self {
WindowEvent{window_id, event} => event.to_static().map(|event| WindowEvent{window_id, event}),
UserEvent(e) => Some(UserEvent(e)),
DeviceEvent{device_id, event} => Some(DeviceEvent{device_id, event}),
NewEvents(cause) => Some(NewEvents(cause)),
EventsCleared => Some(EventsCleared),
LoopDestroyed => Some(LoopDestroyed),
Suspended(suspended) => Some(Suspended(suspended)),
}
}
}

/// Describes the reason the event loop is resuming.
Expand Down Expand Up @@ -84,8 +97,8 @@ pub enum StartCause {
}

/// Describes an event from a `Window`.
#[derive(Clone, Debug, PartialEq)]
pub enum WindowEvent {
#[derive(Debug, PartialEq)]
pub enum WindowEvent<'a> {
/// The size of the window has changed. Contains the client area's new dimensions.
Resized(PhysicalSize),

Expand Down Expand Up @@ -175,8 +188,44 @@ pub enum WindowEvent {
/// * Changing the display's DPI factor (e.g. in Control Panel on Windows).
/// * Moving the window to a display with a different DPI factor.
///
/// After this event callback has been processed, the window will be resized to whatever value
/// is pointed to by the `new_inner_size` reference. By default, this will contain the size suggested
/// by the OS, but it can be changed to any value. If `new_inner_size` is set to `None`, no resizing
/// will occur.
///
/// For more information about DPI in general, see the [`dpi`](dpi/index.html) module.
HiDpiFactorChanged(f64),
HiDpiFactorChanged {
hidpi_factor: f64,
new_inner_size: &'a mut Option<PhysicalSize>
},
}

impl<'a> WindowEvent<'a> {
pub fn to_static(self) -> Option<WindowEvent<'static>> {
use self::WindowEvent::*;
match self {
Resized(size) => Some(Resized(size)),
Moved(position) => Some(Moved(position)),
CloseRequested => Some(CloseRequested),
Destroyed => Some(Destroyed),
DroppedFile(file) => Some(DroppedFile(file)),
HoveredFile(file) => Some(HoveredFile(file)),
HoveredFileCancelled => Some(HoveredFileCancelled),
ReceivedCharacter(c) => Some(ReceivedCharacter(c)),
Focused(focused) => Some(Focused(focused)),
KeyboardInput { device_id, input } => Some(KeyboardInput { device_id, input }),
CursorMoved { device_id, position, modifiers } => Some(CursorMoved { device_id, position, modifiers }),
CursorEntered { device_id } => Some(CursorEntered { device_id }),
CursorLeft { device_id } => Some(CursorLeft { device_id }),
MouseWheel { device_id, delta, phase, modifiers } => Some(MouseWheel { device_id, delta, phase, modifiers }),
MouseInput { device_id, state, button, modifiers } => Some(MouseInput { device_id, state, button, modifiers }),
TouchpadPressure { device_id, pressure, stage } => Some(TouchpadPressure { device_id, pressure, stage }),
AxisMotion { device_id, axis, value } => Some(AxisMotion { device_id, axis, value }),
RedrawRequested => Some(RedrawRequested),
Touch(touch) => Some(Touch(touch)),
HiDpiFactorChanged{..} => None,
}
}
}

/// Identifier of an input device.
Expand Down
2 changes: 1 addition & 1 deletion src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl<T> EventLoop<T> {
/// [`ControlFlow`]: ./enum.ControlFlow.html
#[inline]
pub fn run<F>(self, event_handler: F) -> !
where F: 'static + FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow)
where F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow)
{
self.event_loop.run(event_handler)
}
Expand Down
4 changes: 2 additions & 2 deletions src/platform/desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ pub trait EventLoopExtDesktop {
///
/// You are strongly encouraged to use `run`, unless the use of this is absolutely necessary.
fn run_return<F>(&mut self, event_handler: F)
where F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
where F: FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
}

impl<T> EventLoopExtDesktop for EventLoop<T> {
type UserEvent = T;

fn run_return<F>(&mut self, event_handler: F)
where F: FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow)
where F: FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow)
{
self.event_loop.run_return(event_handler)
}
Expand Down
6 changes: 3 additions & 3 deletions src/platform_impl/windows/drop_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct FileDropHandlerData {
pub interface: IDropTarget,
refcount: AtomicUsize,
window: HWND,
send_event: Box<Fn(Event<()>)>,
send_event: Box<Fn(Event<'static, ()>)>,
cursor_effect: DWORD,
hovered_is_valid: bool, // If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted
}
Expand All @@ -35,7 +35,7 @@ pub struct FileDropHandler {

#[allow(non_snake_case)]
impl FileDropHandler {
pub fn new(window: HWND, send_event: Box<Fn(Event<()>)>) -> FileDropHandler {
pub fn new(window: HWND, send_event: Box<Fn(Event<'static, ()>)>) -> FileDropHandler {
let data = Box::new(FileDropHandlerData {
interface: IDropTarget {
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
Expand Down Expand Up @@ -208,7 +208,7 @@ impl FileDropHandler {
}

impl FileDropHandlerData {
fn send_event(&self, event: Event<()>) {
fn send_event(&self, event: Event<'static, ()>) {
(self.send_event)(event);
}
}
Expand Down
110 changes: 80 additions & 30 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use std::marker::PhantomData;
use parking_lot::Mutex;

use winapi::shared::minwindef::{
BOOL,
DWORD,
HIWORD,
INT,
Expand All @@ -43,7 +44,7 @@ use winapi::um::winnt::{LPCSTR, SHORT};

use window::WindowId as RootWindowId;
use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed};
use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
use dpi::{PhysicalPosition, PhysicalSize};
use event::{DeviceEvent, Touch, TouchPhase, StartCause, KeyboardInput, Event, WindowEvent};
use platform_impl::platform::{event, WindowId, DEVICE_ID, wrap_device_id, util};
use platform_impl::platform::dpi::{
Expand All @@ -57,25 +58,29 @@ use platform_impl::platform::raw_input::{get_raw_input_data, get_raw_mouse_butto
use platform_impl::platform::window::adjust_size;
use platform_impl::platform::window_state::{CursorFlags, WindowFlags, WindowState};

pub(crate) struct SubclassInput<T> {
pub(crate) struct SubclassInput<T: 'static> {
pub window_state: Arc<Mutex<WindowState>>,
pub event_loop_runner: EventLoopRunnerShared<T>,
pub file_drop_handler: FileDropHandler,
}

impl<T> SubclassInput<T> {
unsafe fn send_event(&self, event: Event<T>) {
unsafe fn send_event(&self, event: Event<'static, T>) {
self.event_loop_runner.send_event(event);
}

unsafe fn send_event_unbuffered<'e>(&self, event: Event<'e, T>) -> Result<(), Event<'e, T>>{
self.event_loop_runner.send_event_unbuffered(event)
}
}

struct ThreadMsgTargetSubclassInput<T> {
struct ThreadMsgTargetSubclassInput<T: 'static> {
event_loop_runner: EventLoopRunnerShared<T>,
user_event_receiver: Receiver<T>,
}

impl<T> ThreadMsgTargetSubclassInput<T> {
unsafe fn send_event(&self, event: Event<T>) {
unsafe fn send_event(&self, event: Event<'static, T>) {
self.event_loop_runner.send_event(event);
}
}
Expand All @@ -85,7 +90,7 @@ pub struct EventLoop<T: 'static> {
window_target: RootELW<T>,
}

pub struct EventLoopWindowTarget<T> {
pub struct EventLoopWindowTarget<T: 'static> {
thread_id: DWORD,
trigger_newevents_on_redraw: Arc<AtomicBool>,
thread_msg_target: HWND,
Expand Down Expand Up @@ -126,14 +131,14 @@ impl<T: 'static> EventLoop<T> {
}

pub fn run<F>(mut self, event_handler: F) -> !
where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
where F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow)
{
self.run_return(event_handler);
::std::process::exit(0);
}

pub fn run_return<F>(&mut self, mut event_handler: F)
where F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
where F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow)
{
unsafe{ winuser::IsGUIThread(1); }

Expand Down Expand Up @@ -224,11 +229,11 @@ impl<T> EventLoopWindowTarget<T> {
}

pub(crate) type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
pub(crate) struct ELRShared<T> {
pub(crate) struct ELRShared<T: 'static> {
runner: RefCell<Option<EventLoopRunner<T>>>,
buffer: RefCell<VecDeque<Event<T>>>,
buffer: RefCell<VecDeque<Event<'static, T>>>,
}
pub(crate) struct EventLoopRunner<T> {
pub(crate) struct EventLoopRunner<T: 'static> {
trigger_newevents_on_redraw: Arc<AtomicBool>,
control_flow: ControlFlow,
runner_state: RunnerState,
Expand All @@ -240,7 +245,15 @@ pub(crate) struct EventLoopRunner<T> {
type PanicError = Box<Any + Send + 'static>;

impl<T> ELRShared<T> {
pub(crate) unsafe fn send_event(&self, event: Event<T>) {
pub(crate) unsafe fn send_event(&self, event: Event<'static, T>) {
if let Err(event) = self.send_event_unbuffered(event) {
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
// the event to a buffer to be processed later.
self.buffer.borrow_mut().push_back(event)
}
}

pub(crate) unsafe fn send_event_unbuffered<'e>(&self, event: Event<'e, T>) -> Result<(), Event<'e, T>> {
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
if let Some(ref mut runner) = *runner_ref {
runner.process_event(event);
Expand All @@ -258,13 +271,11 @@ impl<T> ELRShared<T> {
}
}

return;
return Ok(());
}
}

// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
// the event to a buffer to be processed later.
self.buffer.borrow_mut().push_back(event)
Err(event)
}
}

Expand Down Expand Up @@ -759,7 +770,7 @@ pub(crate) fn subclass_window<T>(window: HWND, subclass_input: SubclassInput<T>)
//
// Returning 0 tells the Win32 API that the message has been processed.
// FIXME: detect WM_DWMCOMPOSITIONCHANGED and call DwmEnableBlurBehindWindow if necessary
unsafe extern "system" fn public_window_callback<T>(
unsafe extern "system" fn public_window_callback<T: 'static>(
window: HWND,
msg: UINT,
wparam: WPARAM,
Expand Down Expand Up @@ -1425,27 +1436,66 @@ unsafe extern "system" fn public_window_callback<T>(
new_dpi_factor != old_dpi_factor && window_state.fullscreen.is_none()
};

// This prevents us from re-applying DPI adjustment to the restored size after exiting
// fullscreen (the restored size is already DPI adjusted).
if allow_resize {
// Resize window to the size suggested by Windows.
let rect = &*(lparam as *const RECT);
let style = winuser::GetWindowLongW(window, winuser::GWL_STYLE) as _;
let style_ex = winuser::GetWindowLongW(window, winuser::GWL_EXSTYLE) as _;
let b_menu = !winuser::GetMenu(window).is_null() as BOOL;

// New size as suggested by Windows.
let rect = *(lparam as *const RECT);

// The window rect provided is the window's outer size, not it's inner size. However,
// win32 doesn't provide an `UnadjustWindowRectEx` function to get the client rect from
// the outer rect, so we instead adjust the window rect to get the decoration margins
// and remove them from the outer size.
let margins_horizontal: u32;
let margins_vertical: u32;
{
let mut adjusted_rect = rect;
winuser::AdjustWindowRectExForDpi(
&mut adjusted_rect,
style,
b_menu,
style_ex,
new_dpi_x
);
let margin_left = rect.left - adjusted_rect.left;
let margin_right = adjusted_rect.right - rect.right;
let margin_top = rect.top - adjusted_rect.top;
let margin_bottom = adjusted_rect.bottom - rect.bottom;

margins_horizontal = (margin_left + margin_right) as u32;
margins_vertical = (margin_bottom + margin_top) as u32;
}

let physical_inner_rect = PhysicalSize::new(
(rect.right - rect.left) as u32 - margins_horizontal,
(rect.bottom - rect.top) as u32 - margins_vertical
);

// `allow_resize` prevents us from re-applying DPI adjustment to the restored size after
// exiting fullscreen (the restored size is already DPI adjusted).
let mut new_inner_rect_opt = Some(physical_inner_rect).filter(|_| allow_resize);

let _ = subclass_input.send_event_unbuffered(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: HiDpiFactorChanged {
hidpi_factor: new_dpi_factor,
new_inner_size: &mut new_inner_rect_opt
},
});

if let Some(new_inner_rect) = new_inner_rect_opt {
winuser::SetWindowPos(
window,
ptr::null_mut(),
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
(new_inner_rect.width + margins_horizontal) as _,
(new_inner_rect.height + margins_vertical) as _,
winuser::SWP_NOZORDER | winuser::SWP_NOACTIVATE,
);
}

subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: HiDpiFactorChanged(new_dpi_factor),
});

0
},

Expand All @@ -1464,7 +1514,7 @@ unsafe extern "system" fn public_window_callback<T>(
}
}

unsafe extern "system" fn thread_event_target_callback<T>(
unsafe extern "system" fn thread_event_target_callback<T: 'static>(
window: HWND,
msg: UINT,
wparam: WPARAM,
Expand Down

0 comments on commit d363fca

Please sign in to comment.