From ede7e846f483d189d26c62c674fd391bb63ce3d7 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sat, 5 Aug 2023 22:25:06 -0700 Subject: [PATCH] x11: respect config.dpi_by_screen Maintain a cache of the positions of the various named screens, and use that to resolve the screen of the current window, and from there we can resolve the correct dpi_by_screen screen. Make dpi and dpi_by_screen config changes generate a resize event with the updated dpi. refs: #4096 --- window/src/os/x11/connection.rs | 32 ++++++++++++++++++++++ window/src/os/x11/window.rs | 47 +++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/window/src/os/x11/connection.rs b/window/src/os/x11/connection.rs index f6f22ad07..1e0f1ecdb 100644 --- a/window/src/os/x11/connection.rs +++ b/window/src/os/x11/connection.rs @@ -63,6 +63,7 @@ pub struct XConnection { pub(crate) has_randr: bool, pub(crate) atom_names: RefCell>, pub(crate) supported: RefCell>, + pub(crate) screens: RefCell>, } impl std::ops::Deref for XConnection { @@ -481,6 +482,21 @@ impl XConnection { } } + pub(crate) fn get_cached_screens(&self) -> anyhow::Result { + { + let screens = self.screens.borrow(); + if let Some(cached) = screens.as_ref() { + return Ok(cached.clone()); + } + } + + let screens = self.screens()?; + + self.screens.borrow_mut().replace(screens.clone()); + + Ok(screens) + } + fn process_xcb_event(&self, event: &xcb::Event) -> anyhow::Result<()> { match event { // Following stuff is not obvious at all. @@ -497,6 +513,11 @@ impl XConnection { xcb::Event::Dri2(dri2::Event::InvalidateBuffers(ev)) => unsafe { self.rewire_event(ev.as_raw()) }, + xcb::Event::RandR(randr) => { + log::trace!("{randr:?}"); + // Clear our cache + self.screens.borrow_mut().take(); + } _ => {} } @@ -651,6 +672,16 @@ impl XConnection { let root = screen.root(); + if has_randr { + conn.check_request(conn.send_request_checked(&xcb::randr::SelectInput { + window: root, + enable: xcb::randr::NotifyMask::SCREEN_CHANGE + | xcb::randr::NotifyMask::PROVIDER_CHANGE + | xcb::randr::NotifyMask::RESOURCE_CHANGE, + })) + .context("XRANDR::SelectInput")?; + } + let xrm = crate::x11::xrm::parse_root_resource_manager(&conn, root).unwrap_or(HashMap::new()); @@ -723,6 +754,7 @@ impl XConnection { has_randr, atom_names: RefCell::new(HashMap::new()), supported: RefCell::new(HashSet::new()), + screens: RefCell::new(None), }); { diff --git a/window/src/os/x11/window.rs b/window/src/os/x11/window.rs index d8da4070f..0c706dac8 100644 --- a/window/src/os/x11/window.rs +++ b/window/src/os/x11/window.rs @@ -5,7 +5,8 @@ use crate::os::{xkeysyms, Connection, Window}; use crate::{ Appearance, Clipboard, DeadKeyStatus, Dimensions, MouseButtons, MouseCursor, MouseEvent, MouseEventKind, MousePress, Point, Rect, RequestedWindowGeometry, ResolvedGeometry, - ScreenPoint, WindowDecorations, WindowEvent, WindowEventSender, WindowOps, WindowState, + ScreenPoint, ScreenRect, WindowDecorations, WindowEvent, WindowEventSender, WindowOps, + WindowState, }; use anyhow::{anyhow, Context as _}; use async_trait::async_trait; @@ -427,7 +428,43 @@ impl XWindowInner { let conn = self.conn(); self.update_ime_position(); - let dpi = conn.default_dpi(); + let mut dpi = conn.default_dpi(); + + if !self.config.dpi_by_screen.is_empty() { + let coords = conn + .send_and_wait_request(&xcb::x::TranslateCoordinates { + src_window: self.window_id, + dst_window: conn.root, + src_x: 0, + src_y: 0, + }) + .context("querying window coordinates")?; + let screens = conn.get_cached_screens()?; + let window_rect: ScreenRect = euclid::rect( + coords.dst_x().into(), + coords.dst_y().into(), + width as isize, + height as isize, + ); + let screen = screens + .by_name + .values() + .filter_map(|screen| { + screen + .rect + .intersection(&window_rect) + .map(|r| (screen, r.area())) + }) + .max_by_key(|s| s.1) + .ok_or_else(|| anyhow::anyhow!("window is not in any screen"))? + .0; + + if let Some(value) = self.config.dpi_by_screen.get(&screen.name).copied() { + dpi = value; + } else if let Some(value) = self.config.dpi { + dpi = value; + } + } if width == self.width && height == self.height && dpi == self.dpi { // Effectively unchanged; perhaps it was simply moved? @@ -1306,8 +1343,14 @@ impl XWindowInner { } fn config_did_change(&mut self, config: &ConfigHandle) { + let dpi_changed = + self.config.dpi != config.dpi || self.config.dpi_by_screen != config.dpi_by_screen; self.config = config.clone(); let _ = self.adjust_decorations(config.window_decorations); + + if dpi_changed { + let _ = self.configure_notify("config reload", self.width, self.height); + } } fn net_wm_moveresize(&mut self, x_root: u32, y_root: u32, direction: u32, button: u32) {