On X11, reload DPI on PropertyChange

Signed-off-by: John Nunley <dev@notgull.net>
Fixes #1228.
This commit is contained in:
John Nunley 2023-11-24 00:14:06 -08:00 committed by GitHub
parent 81a1d9c396
commit b3c87caa7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 97 additions and 67 deletions

View file

@ -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 {