On X11, reload DPI on PropertyChange
Signed-off-by: John Nunley <dev@notgull.net> Fixes #1228.
This commit is contained in:
parent
81a1d9c396
commit
b3c87caa7c
3 changed files with 97 additions and 67 deletions
|
|
@ -13,6 +13,7 @@ Unreleased` header.
|
||||||
|
|
||||||
- Fix crash when running iOS app on macOS.
|
- Fix crash when running iOS app on macOS.
|
||||||
- On X11, check common alternative cursor names when loading cursor.
|
- On X11, check common alternative cursor names when loading cursor.
|
||||||
|
- On X11, reload the DPI after a property change event.
|
||||||
- On Windows, fix so `drag_window` and `drag_resize_window` can be called from another thread.
|
- On Windows, fix so `drag_window` and `drag_resize_window` can be called from another thread.
|
||||||
- On Windows, fix `set_control_flow` in `AboutToWait` not being taken in account.
|
- On Windows, fix `set_control_flow` in `AboutToWait` not being taken in account.
|
||||||
- On macOS, send a `Resized` event after each `ScaleFactorChanged` event.
|
- On macOS, send a `Resized` event after each `ScaleFactorChanged` event.
|
||||||
|
|
|
||||||
|
|
@ -570,6 +570,14 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
event: WindowEvent::Destroyed,
|
event: WindowEvent::Destroyed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
ffi::PropertyNotify => {
|
||||||
|
let xev: &ffi::XPropertyEvent = xev.as_ref();
|
||||||
|
let atom = xev.atom as xproto::Atom;
|
||||||
|
|
||||||
|
if atom == xproto::Atom::from(xproto::AtomEnum::RESOURCE_MANAGER) {
|
||||||
|
self.process_dpi_change(&mut callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ffi::VisibilityNotify => {
|
ffi::VisibilityNotify => {
|
||||||
let xev: &ffi::XVisibilityEvent = xev.as_ref();
|
let xev: &ffi::XVisibilityEvent = xev.as_ref();
|
||||||
|
|
@ -1306,72 +1314,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if event_type == self.randr_event_offset as c_int {
|
if event_type == self.randr_event_offset as c_int {
|
||||||
// In the future, it would be quite easy to emit monitor hotplug events.
|
self.process_dpi_change(&mut callback);
|
||||||
let prev_list = wt.xconn.invalidate_cached_monitor_list();
|
|
||||||
if let Some(prev_list) = prev_list {
|
|
||||||
let new_list = wt
|
|
||||||
.xconn
|
|
||||||
.available_monitors()
|
|
||||||
.expect("Failed to get monitor list");
|
|
||||||
for new_monitor in new_list {
|
|
||||||
// Previous list may be empty, in case of disconnecting and
|
|
||||||
// reconnecting the only one monitor. We still need to emit events in
|
|
||||||
// this case.
|
|
||||||
let maybe_prev_scale_factor = prev_list
|
|
||||||
.iter()
|
|
||||||
.find(|prev_monitor| prev_monitor.name == new_monitor.name)
|
|
||||||
.map(|prev_monitor| prev_monitor.scale_factor);
|
|
||||||
if Some(new_monitor.scale_factor) != maybe_prev_scale_factor {
|
|
||||||
for (window_id, window) in wt.windows.borrow().iter() {
|
|
||||||
if let Some(window) = window.upgrade() {
|
|
||||||
// Check if the window is on this monitor
|
|
||||||
let monitor =
|
|
||||||
window.shared_state_lock().last_monitor.clone();
|
|
||||||
if monitor.name == new_monitor.name {
|
|
||||||
let (width, height) = window.inner_size_physical();
|
|
||||||
let (new_width, new_height) = window.adjust_for_dpi(
|
|
||||||
// If we couldn't determine the previous scale
|
|
||||||
// factor (e.g., because all monitors were closed
|
|
||||||
// before), just pick whatever the current monitor
|
|
||||||
// has set as a baseline.
|
|
||||||
maybe_prev_scale_factor
|
|
||||||
.unwrap_or(monitor.scale_factor),
|
|
||||||
new_monitor.scale_factor,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
&window.shared_state_lock(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let window_id = crate::window::WindowId(*window_id);
|
|
||||||
let old_inner_size = PhysicalSize::new(width, height);
|
|
||||||
let inner_size = Arc::new(Mutex::new(
|
|
||||||
PhysicalSize::new(new_width, new_height),
|
|
||||||
));
|
|
||||||
callback(Event::WindowEvent {
|
|
||||||
window_id,
|
|
||||||
event: WindowEvent::ScaleFactorChanged {
|
|
||||||
scale_factor: new_monitor.scale_factor,
|
|
||||||
inner_size_writer: InnerSizeWriter::new(
|
|
||||||
Arc::downgrade(&inner_size),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let new_inner_size = *inner_size.lock().unwrap();
|
|
||||||
drop(inner_size);
|
|
||||||
|
|
||||||
if new_inner_size != old_inner_size {
|
|
||||||
let (new_width, new_height) = new_inner_size.into();
|
|
||||||
window.request_inner_size_physical(
|
|
||||||
new_width, new_height,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1464,6 +1407,45 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_dpi_change<F>(&self, callback: &mut F)
|
||||||
|
where
|
||||||
|
F: FnMut(Event<T>),
|
||||||
|
{
|
||||||
|
let wt = get_xtarget(&self.target);
|
||||||
|
|
||||||
|
// In the future, it would be quite easy to emit monitor hotplug events.
|
||||||
|
let prev_list = {
|
||||||
|
let prev_list = wt.xconn.invalidate_cached_monitor_list();
|
||||||
|
match prev_list {
|
||||||
|
Some(prev_list) => prev_list,
|
||||||
|
None => return,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_list = wt
|
||||||
|
.xconn
|
||||||
|
.available_monitors()
|
||||||
|
.expect("Failed to get monitor list");
|
||||||
|
for new_monitor in new_list {
|
||||||
|
// Previous list may be empty, in case of disconnecting and
|
||||||
|
// reconnecting the only one monitor. We still need to emit events in
|
||||||
|
// this case.
|
||||||
|
let maybe_prev_scale_factor = prev_list
|
||||||
|
.iter()
|
||||||
|
.find(|prev_monitor| prev_monitor.name == new_monitor.name)
|
||||||
|
.map(|prev_monitor| prev_monitor.scale_factor);
|
||||||
|
if Some(new_monitor.scale_factor) != maybe_prev_scale_factor {
|
||||||
|
for window in wt.windows.borrow().iter().filter_map(|(_, w)| w.upgrade()) {
|
||||||
|
window.refresh_dpi_for_monitor(
|
||||||
|
&new_monitor,
|
||||||
|
maybe_prev_scale_factor,
|
||||||
|
&mut *callback,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchPhase) -> bool {
|
fn is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchPhase) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use x11rb::{
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
|
event::{Event, InnerSizeWriter, WindowEvent},
|
||||||
event_loop::AsyncRequestSerial,
|
event_loop::AsyncRequestSerial,
|
||||||
platform_impl::{
|
platform_impl::{
|
||||||
x11::{atoms::*, MonitorHandle as X11MonitorHandle, WakeSender, X11Error},
|
x11::{atoms::*, MonitorHandle as X11MonitorHandle, WakeSender, X11Error},
|
||||||
|
|
@ -276,7 +277,8 @@ impl UnownedWindow {
|
||||||
| EventMask::KEYMAP_STATE
|
| EventMask::KEYMAP_STATE
|
||||||
| EventMask::BUTTON_PRESS
|
| EventMask::BUTTON_PRESS
|
||||||
| EventMask::BUTTON_RELEASE
|
| EventMask::BUTTON_RELEASE
|
||||||
| EventMask::POINTER_MOTION;
|
| EventMask::POINTER_MOTION
|
||||||
|
| EventMask::PROPERTY_CHANGE;
|
||||||
|
|
||||||
aux = aux.event_mask(event_mask).border_pixel(0);
|
aux = aux.event_mask(event_mask).border_pixel(0);
|
||||||
|
|
||||||
|
|
@ -923,6 +925,51 @@ impl UnownedWindow {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refresh the API for the given monitor.
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn refresh_dpi_for_monitor<T: 'static>(
|
||||||
|
&self,
|
||||||
|
new_monitor: &X11MonitorHandle,
|
||||||
|
maybe_prev_scale_factor: Option<f64>,
|
||||||
|
mut callback: impl FnMut(Event<T>),
|
||||||
|
) {
|
||||||
|
// Check if the self is on this monitor
|
||||||
|
let monitor = self.shared_state_lock().last_monitor.clone();
|
||||||
|
if monitor.name == new_monitor.name {
|
||||||
|
let (width, height) = self.inner_size_physical();
|
||||||
|
let (new_width, new_height) = self.adjust_for_dpi(
|
||||||
|
// If we couldn't determine the previous scale
|
||||||
|
// factor (e.g., because all monitors were closed
|
||||||
|
// before), just pick whatever the current monitor
|
||||||
|
// has set as a baseline.
|
||||||
|
maybe_prev_scale_factor.unwrap_or(monitor.scale_factor),
|
||||||
|
new_monitor.scale_factor,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
&self.shared_state_lock(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let window_id = crate::window::WindowId(self.id());
|
||||||
|
let old_inner_size = PhysicalSize::new(width, height);
|
||||||
|
let inner_size = Arc::new(Mutex::new(PhysicalSize::new(new_width, new_height)));
|
||||||
|
callback(Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::ScaleFactorChanged {
|
||||||
|
scale_factor: new_monitor.scale_factor,
|
||||||
|
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&inner_size)),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let new_inner_size = *inner_size.lock().unwrap();
|
||||||
|
drop(inner_size);
|
||||||
|
|
||||||
|
if new_inner_size != old_inner_size {
|
||||||
|
let (new_width, new_height) = new_inner_size.into();
|
||||||
|
self.request_inner_size_physical(new_width, new_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_minimized_inner(&self, minimized: bool) -> Result<VoidCookie<'_>, X11Error> {
|
fn set_minimized_inner(&self, minimized: bool) -> Result<VoidCookie<'_>, X11Error> {
|
||||||
let atoms = self.xconn.atoms();
|
let atoms = self.xconn.atoms();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue