Skip to content

Commit

Permalink
Reload DPI on PropertyChange
Browse files Browse the repository at this point in the history
Supersedes #2874, fixes #1228

Signed-off-by: John Nunley <[email protected]>
  • Loading branch information
notgull committed Nov 12, 2023
1 parent 1414060 commit cb0679b
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 67 deletions.
144 changes: 78 additions & 66 deletions src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -1464,6 +1407,75 @@ 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 = 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);
}
}
}
}
}
}
}
}
}

fn is_first_touch(first: &mut Option<u64>, num: &mut u32, id: u64, phase: TouchPhase) -> bool {
Expand Down
3 changes: 2 additions & 1 deletion src/platform_impl/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,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);

Expand Down

0 comments on commit cb0679b

Please sign in to comment.