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.
|
||||
- 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 `set_control_flow` in `AboutToWait` not being taken in account.
|
||||
- On macOS, send a `Resized` event after each `ScaleFactorChanged` event.
|
||||
|
|
|
|||
|
|
@ -570,6 +570,14 @@ impl<T: 'static> EventProcessor<T> {
|
|||
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 => {
|
||||
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 {
|
||||
// In the future, it would be quite easy to emit monitor hotplug events.
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.process_dpi_change(&mut callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use x11rb::{
|
|||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
event::{Event, InnerSizeWriter, WindowEvent},
|
||||
event_loop::AsyncRequestSerial,
|
||||
platform_impl::{
|
||||
x11::{atoms::*, MonitorHandle as X11MonitorHandle, WakeSender, X11Error},
|
||||
|
|
@ -276,7 +277,8 @@ impl UnownedWindow {
|
|||
| EventMask::KEYMAP_STATE
|
||||
| EventMask::BUTTON_PRESS
|
||||
| EventMask::BUTTON_RELEASE
|
||||
| EventMask::POINTER_MOTION;
|
||||
| EventMask::POINTER_MOTION
|
||||
| EventMask::PROPERTY_CHANGE;
|
||||
|
||||
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> {
|
||||
let atoms = self.xconn.atoms();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue