From 20f370a51d110c7820319d8c2968ca863c61219b Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 4 Oct 2024 15:57:34 -0700 Subject: [PATCH] feat(bar): dpi-awareness + position hotloading This commit ensures that the komorebi-bar.exe process is DPI aware and applies DPI compensation to viewport.position and viewport.inner size both on launch and on configuration reload. viewport.position changes are now hotloaded wihtout having to restart the process. re #1024 --- Cargo.lock | 7 +++++ komorebi-bar/Cargo.toml | 1 + komorebi-bar/src/bar.rs | 14 +++++---- komorebi-bar/src/main.rs | 63 +++++++++++++++++++++++++++++++++++----- 4 files changed, 72 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 88356659..66aee854 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -501,6 +501,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atomic_float" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" + [[package]] name = "atspi" version = "0.19.0" @@ -2705,6 +2711,7 @@ dependencies = [ name = "komorebi-bar" version = "0.1.30" dependencies = [ + "atomic_float", "chrono", "clap", "color-eyre", diff --git a/komorebi-bar/Cargo.toml b/komorebi-bar/Cargo.toml index 802e79fc..98a564fb 100644 --- a/komorebi-bar/Cargo.toml +++ b/komorebi-bar/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" komorebi-client = { path = "../komorebi-client" } komorebi-themes = { path = "../komorebi-themes" } +atomic_float = "1" chrono = { workspace = true } clap = { workspace = true } color-eyre = { workspace = true } diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index ee6e61bd..d9c0a967 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -4,6 +4,7 @@ use crate::komorebi::Komorebi; use crate::komorebi::KomorebiNotificationState; use crate::widget::BarWidget; use crate::widget::WidgetConfig; +use crate::DPI; use crate::MAX_LABEL_WIDTH; use crossbeam_channel::Receiver; use eframe::egui::Align; @@ -17,6 +18,7 @@ use eframe::egui::FontId; use eframe::egui::Frame; use eframe::egui::Layout; use eframe::egui::Margin; +use eframe::egui::Pos2; use eframe::egui::Style; use eframe::egui::TextStyle; use eframe::egui::Vec2; @@ -145,12 +147,14 @@ impl Komobar { } if let Some(viewport) = &config.viewport { - if let Some(inner_size) = viewport.inner_size { - let mut vec2 = Vec2::new(inner_size.x, inner_size.y * 2.0); - if self.scale_factor != 1.0 { - vec2 = Vec2::new(inner_size.x / self.scale_factor, inner_size.y * 2.0); - } + let dpi = DPI.load(Ordering::SeqCst); + if let Some(position) = viewport.position { + let pos2 = Pos2::new(position.x / dpi, position.y / dpi); + ctx.send_viewport_cmd(ViewportCommand::OuterPosition(pos2)); + } + if let Some(position) = viewport.inner_size { + let vec2 = Vec2::new(position.x / dpi, position.y / dpi); ctx.send_viewport_cmd(ViewportCommand::InnerSize(vec2)); } } diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index 6b350cf3..7474a651 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -14,7 +14,9 @@ mod widget; use crate::bar::Komobar; use crate::config::KomobarConfig; use crate::config::Position; +use atomic_float::AtomicF32; use clap::Parser; +use color_eyre::eyre::bail; use eframe::egui::ViewportBuilder; use font_loader::system_fonts; use hotwatch::EventKind; @@ -25,12 +27,16 @@ use std::io::BufReader; use std::io::Read; use std::path::PathBuf; use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; use tracing_subscriber::EnvFilter; +use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext; +use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; pub static WIDGET_SPACING: f32 = 10.0; pub static MAX_LABEL_WIDTH: AtomicI32 = AtomicI32::new(400); +pub static DPI: AtomicF32 = AtomicF32::new(1.0); #[derive(Parser)] #[clap(author, about, version)] @@ -49,7 +55,39 @@ struct Opts { quickstart: bool, } +macro_rules! as_ptr { + ($value:expr) => { + $value as *mut core::ffi::c_void + }; +} + +pub fn dpi_for_monitor(hmonitor: isize) -> color_eyre::Result { + use windows::Win32::Graphics::Gdi::HMONITOR; + use windows::Win32::UI::HiDpi::GetDpiForMonitor; + use windows::Win32::UI::HiDpi::MDT_EFFECTIVE_DPI; + + let mut dpi_x = u32::default(); + let mut dpi_y = u32::default(); + + unsafe { + match GetDpiForMonitor( + HMONITOR(as_ptr!(hmonitor)), + MDT_EFFECTIVE_DPI, + std::ptr::addr_of_mut!(dpi_x), + std::ptr::addr_of_mut!(dpi_y), + ) { + Ok(_) => {} + Err(error) => bail!(error), + } + } + + #[allow(clippy::cast_precision_loss)] + Ok(dpi_y as f32 / 96.0) +} + fn main() -> color_eyre::Result<()> { + unsafe { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) }?; + let opts: Opts = Opts::parse(); if opts.schema { @@ -157,30 +195,39 @@ fn main() -> color_eyre::Result<()> { &SocketMessage::State, )?)?; + let dpi = dpi_for_monitor(state.monitors.elements()[config.monitor.index].id())?; + DPI.store(dpi, Ordering::SeqCst); + let mut viewport_builder = ViewportBuilder::default() .with_decorations(false) // .with_transparent(config.transparent) .with_taskbar(false) .with_position(Position { - x: state.monitors.elements()[config.monitor.index].size().left as f32, - y: state.monitors.elements()[config.monitor.index].size().top as f32, + x: state.monitors.elements()[config.monitor.index].size().left as f32 / dpi, + y: state.monitors.elements()[config.monitor.index].size().top as f32 / dpi, }) .with_inner_size({ Position { - x: state.monitors.elements()[config.monitor.index].size().right as f32, - y: 20.0, + x: state.monitors.elements()[config.monitor.index].size().right as f32 / dpi, + y: 50.0 / dpi, } }); if let Some(viewport) = &config.viewport { - if let Some(position) = &viewport.position { + if let Some(mut position) = &viewport.position { + position.x /= dpi; + position.y /= dpi; + let b = viewport_builder.clone(); - viewport_builder = b.with_position(*position); + viewport_builder = b.with_position(position); } - if let Some(inner_size) = &viewport.inner_size { + if let Some(mut inner_size) = &viewport.inner_size { + inner_size.x /= dpi; + inner_size.y /= dpi; + let b = viewport_builder.clone(); - viewport_builder = b.with_inner_size(*inner_size); + viewport_builder = b.with_inner_size(inner_size); } }