From a55ba8c523ff19fa607a31bac589a55b48db39ad Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 18 Feb 2024 14:54:17 +0000 Subject: [PATCH 1/2] refactor: rename `get_orientation` method to `orientation` --- src/bar.rs | 6 +++--- src/config/impl.rs | 2 +- src/modules/custom/mod.rs | 4 ++-- src/modules/focused.rs | 2 +- src/modules/launcher/item.rs | 4 +--- src/modules/launcher/mod.rs | 2 +- src/modules/sysinfo.rs | 2 +- src/modules/tray/mod.rs | 2 +- src/modules/workspaces.rs | 2 +- 9 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/bar.rs b/src/bar.rs index d15bd737..27af61a9 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -60,7 +60,7 @@ impl Bar { window.set_widget_name(&name); let position = config.position; - let orientation = position.get_orientation(); + let orientation = position.orientation(); let content = gtk::Box::builder() .orientation(orientation) @@ -187,7 +187,7 @@ impl Bar { win.set_layer_shell_margin(gtk_layer_shell::Edge::Left, margin.left); win.set_layer_shell_margin(gtk_layer_shell::Edge::Right, margin.right); - let bar_orientation = position.get_orientation(); + let bar_orientation = position.orientation(); win.set_anchor( gtk_layer_shell::Edge::Top, @@ -351,7 +351,7 @@ fn add_modules( ironbar: &Rc, popup: &Rc>, ) -> Result<()> { - let orientation = info.bar_position.get_orientation(); + let orientation = info.bar_position.orientation(); macro_rules! add_module { ($module:expr, $id:expr) => {{ diff --git a/src/config/impl.rs b/src/config/impl.rs index c60e292d..7b9e65d1 100644 --- a/src/config/impl.rs +++ b/src/config/impl.rs @@ -38,7 +38,7 @@ impl<'de> Deserialize<'de> for MonitorConfig { impl BarPosition { /// Gets the orientation the bar and widgets should use /// based on this position. - pub fn get_orientation(self) -> Orientation { + pub fn orientation(self) -> Orientation { if self == Self::Top || self == Self::Bottom { Orientation::Horizontal } else { diff --git a/src/modules/custom/mod.rs b/src/modules/custom/mod.rs index 6ec70273..b6e97b9f 100644 --- a/src/modules/custom/mod.rs +++ b/src/modules/custom/mod.rs @@ -194,7 +194,7 @@ impl Module for CustomModule { context: WidgetContext, info: &ModuleInfo, ) -> Result> { - let orientation = info.bar_position.get_orientation(); + let orientation = info.bar_position.orientation(); let container = gtk::Box::builder().orientation(orientation).build(); let popup_buttons = Rc::new(RefCell::new(Vec::new())); @@ -236,7 +236,7 @@ impl Module for CustomModule { if let Some(popup) = self.popup { let custom_context = CustomWidgetContext { tx: &tx, - bar_orientation: info.bar_position.get_orientation(), + bar_orientation: info.bar_position.orientation(), icon_theme: info.icon_theme, popup_buttons: Rc::new(RefCell::new(vec![])), }; diff --git a/src/modules/focused.rs b/src/modules/focused.rs index ce288e19..8c32c2bf 100644 --- a/src/modules/focused.rs +++ b/src/modules/focused.rs @@ -113,7 +113,7 @@ impl Module for FocusedModule { ) -> Result> { let icon_theme = info.icon_theme; - let container = gtk::Box::new(info.bar_position.get_orientation(), 5); + let container = gtk::Box::new(info.bar_position.orientation(), 5); let icon = gtk::Image::new(); if self.show_icon { diff --git a/src/modules/launcher/item.rs b/src/modules/launcher/item.rs index d312cd8f..ba4407d1 100644 --- a/src/modules/launcher/item.rs +++ b/src/modules/launcher/item.rs @@ -225,9 +225,7 @@ impl ItemButton { try_send!( tx, - ModuleUpdateEvent::OpenPopupAt( - button.geometry(bar_position.get_orientation()) - ) + ModuleUpdateEvent::OpenPopupAt(button.geometry(bar_position.orientation())) ); } else { try_send!(tx, ModuleUpdateEvent::ClosePopup); diff --git a/src/modules/launcher/mod.rs b/src/modules/launcher/mod.rs index c231cc8e..41a7931f 100644 --- a/src/modules/launcher/mod.rs +++ b/src/modules/launcher/mod.rs @@ -301,7 +301,7 @@ impl Module for LauncherModule { ) -> crate::Result> { let icon_theme = info.icon_theme; - let container = gtk::Box::new(info.bar_position.get_orientation(), 0); + let container = gtk::Box::new(info.bar_position.orientation(), 0); { let container = container.clone(); diff --git a/src/modules/sysinfo.rs b/src/modules/sysinfo.rs index 420d9238..c815110d 100644 --- a/src/modules/sysinfo.rs +++ b/src/modules/sysinfo.rs @@ -188,7 +188,7 @@ impl Module for SysInfoModule { ) -> Result> { let re = Regex::new(r"\{([^}]+)}")?; - let container = gtk::Box::new(info.bar_position.get_orientation(), 10); + let container = gtk::Box::new(info.bar_position.orientation(), 10); let mut labels = Vec::new(); diff --git a/src/modules/tray/mod.rs b/src/modules/tray/mod.rs index 5231e097..cf4a2ff4 100644 --- a/src/modules/tray/mod.rs +++ b/src/modules/tray/mod.rs @@ -89,7 +89,7 @@ impl Module for TrayModule { let container = MenuBar::new(); let direction = self.direction.unwrap_or( - if info.bar_position.get_orientation() == gtk::Orientation::Vertical { + if info.bar_position.orientation() == gtk::Orientation::Vertical { PackDirection::Ttb } else { PackDirection::Ltr diff --git a/src/modules/workspaces.rs b/src/modules/workspaces.rs index 2e9c4ee1..40c30c56 100644 --- a/src/modules/workspaces.rs +++ b/src/modules/workspaces.rs @@ -189,7 +189,7 @@ impl Module for WorkspacesModule { context: WidgetContext, info: &ModuleInfo, ) -> Result> { - let container = gtk::Box::new(info.bar_position.get_orientation(), 0); + let container = gtk::Box::new(info.bar_position.orientation(), 0); let name_map = self.name_map.clone().unwrap_or_default(); let favs = self.favorites.clone(); From a10466e7e9dafd29e80994eccccdd398e9434b95 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sun, 18 Feb 2024 14:55:29 +0000 Subject: [PATCH 2/2] fix(popup): re-position on resize due to content change --- src/bar.rs | 11 ++--- src/ipc/server.rs | 15 +++--- src/modules/mod.rs | 23 ++------- src/popup.rs | 120 ++++++++++++++++++++++++++++++++------------- 4 files changed, 102 insertions(+), 67 deletions(-) diff --git a/src/bar.rs b/src/bar.rs index 27af61a9..49f820a3 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -10,7 +10,6 @@ use gtk::gdk::Monitor; use gtk::prelude::*; use gtk::{Application, ApplicationWindow, IconTheme, Orientation, Window, WindowType}; use gtk_layer_shell::LayerShell; -use std::cell::RefCell; use std::rc::Rc; use std::time::Duration; use tracing::{debug, info}; @@ -18,7 +17,7 @@ use tracing::{debug, info}; #[derive(Debug, Clone)] enum Inner { New { config: Option }, - Loaded { popup: Rc> }, + Loaded { popup: Rc }, } #[derive(Debug, Clone)] @@ -269,7 +268,7 @@ impl Bar { // popup ignores module location so can bodge this for now let popup = Popup::new(&info!(ModuleLocation::Left), config.popup_gap); - let popup = Rc::new(RefCell::new(popup)); + let popup = Rc::new(popup); if let Some(modules) = config.start { let info = info!(ModuleLocation::Left); @@ -315,7 +314,7 @@ impl Bar { &self.monitor_name } - pub fn popup(&self) -> Rc> { + pub fn popup(&self) -> Rc { match &self.inner { Inner::New { .. } => { panic!("Attempted to get popup of uninitialized bar. This is a serious bug!") @@ -339,7 +338,7 @@ fn create_container(name: &str, orientation: Orientation) -> gtk::Box { #[derive(Debug)] struct BarLoadResult { - popup: Rc>, + popup: Rc, } /// Adds modules into a provided GTK box, @@ -349,7 +348,7 @@ fn add_modules( modules: Vec, info: &ModuleInfo, ironbar: &Rc, - popup: &Rc>, + popup: &Rc, ) -> Result<()> { let orientation = info.bar_position.orientation(); diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 4d30ee4d..931a4fa8 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -167,13 +167,13 @@ impl Ipc { match bar { Some(bar) => { let popup = bar.popup(); - let current_widget = popup.borrow().current_widget(); + let current_widget = popup.current_widget(); - popup.borrow_mut().hide(); + popup.hide(); let data = popup - .borrow() .cache + .borrow() .iter() .find(|(_, value)| value.name == name) .map(|(id, value)| (*id, value.content.buttons.first().cloned())); @@ -181,7 +181,6 @@ impl Ipc { match data { Some((id, Some(button))) if current_widget != Some(id) => { let button_id = button.popup_id(); - let mut popup = popup.borrow_mut(); if popup.is_visible() { popup.hide(); @@ -207,11 +206,11 @@ impl Ipc { let popup = bar.popup(); // only one popup per bar, so hide if open for another widget - popup.borrow_mut().hide(); + popup.hide(); let data = popup - .borrow() .cache + .borrow() .iter() .find(|(_, value)| value.name == name) .map(|(id, value)| (*id, value.content.buttons.first().cloned())); @@ -219,7 +218,7 @@ impl Ipc { match data { Some((id, Some(button))) => { let button_id = button.popup_id(); - popup.borrow_mut().show(id, button_id); + popup.show(id, button_id); Response::Ok } @@ -236,7 +235,7 @@ impl Ipc { match bar { Some(bar) => { let popup = bar.popup(); - popup.borrow_mut().hide(); + popup.hide(); Response::Ok } diff --git a/src/modules/mod.rs b/src/modules/mod.rs index a293d0f0..102b4bc0 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::fmt::Debug; use std::rc::Rc; use std::sync::Arc; @@ -215,7 +214,7 @@ pub fn create_module( ironbar: Rc, name: Option, info: &ModuleInfo, - popup: &Rc>, + popup: &Rc, ) -> Result> where TModule: Module, @@ -251,7 +250,7 @@ where .style_context() .add_class(&format!("popup-{module_name}")); - register_popup_content(popup, id, instance_name, popup_content); + popup.register_content(id, instance_name, popup_content); } setup_receiver(tx, ui_rx, popup.clone(), module_name, id); @@ -259,16 +258,6 @@ where Ok(module_parts) } -/// Registers the popup content with the popup. -fn register_popup_content( - popup: &Rc>, - id: usize, - name: String, - popup_content: ModulePopupParts, -) { - popup.borrow_mut().register_content(id, name, popup_content); -} - /// Sets up the bridge channel receiver /// to pick up events from the controller, widget or popup. /// @@ -277,7 +266,7 @@ fn register_popup_content( fn setup_receiver( tx: broadcast::Sender, rx: mpsc::Receiver>, - popup: Rc>, + popup: Rc, name: &'static str, id: usize, ) where @@ -294,7 +283,6 @@ fn setup_receiver( } ModuleUpdateEvent::TogglePopup(button_id) => { debug!("Toggling popup for {} [#{}]", name, id); - let mut popup = popup.borrow_mut(); if popup.is_visible() { popup.hide(); } else { @@ -309,8 +297,6 @@ fn setup_receiver( } ModuleUpdateEvent::OpenPopup(button_id) => { debug!("Opening popup for {} [#{}]", name, id); - - let mut popup = popup.borrow_mut(); popup.hide(); popup.show(id, button_id); @@ -324,7 +310,6 @@ fn setup_receiver( ModuleUpdateEvent::OpenPopupAt(geometry) => { debug!("Opening popup for {} [#{}]", name, id); - let mut popup = popup.borrow_mut(); popup.hide(); popup.show_at(id, geometry); @@ -336,8 +321,6 @@ fn setup_receiver( } ModuleUpdateEvent::ClosePopup => { debug!("Closing popup for {} [#{}]", name, id); - - let mut popup = popup.borrow_mut(); popup.hide(); } } diff --git a/src/popup.rs b/src/popup.rs index c7756f9b..cb1a536c 100644 --- a/src/popup.rs +++ b/src/popup.rs @@ -1,11 +1,13 @@ use glib::Propagation; +use std::cell::RefCell; use std::collections::HashMap; +use std::rc::Rc; use gtk::gdk::Monitor; use gtk::prelude::*; -use gtk::{ApplicationWindow, Orientation}; +use gtk::{ApplicationWindow, Button, Orientation}; use gtk_layer_shell::LayerShell; -use tracing::debug; +use tracing::{debug, trace}; use crate::config::BarPosition; use crate::gtk_helpers::{IronbarGtkExt, WidgetGeometry}; @@ -21,10 +23,10 @@ pub struct PopupCacheValue { #[derive(Debug, Clone)] pub struct Popup { pub window: ApplicationWindow, - pub cache: HashMap, + pub cache: Rc>>, monitor: Monitor, pos: BarPosition, - current_widget: Option, + current_widget: Rc>>, } impl Popup { @@ -33,7 +35,7 @@ impl Popup { /// and an empty `gtk::Box` container. pub fn new(module_info: &ModuleInfo, gap: i32) -> Self { let pos = module_info.bar_position; - let orientation = pos.get_orientation(); + let orientation = pos.orientation(); let win = ApplicationWindow::builder() .application(module_info.app) @@ -104,14 +106,14 @@ impl Popup { Self { window: win, - cache: HashMap::new(), + cache: Rc::new(RefCell::new(HashMap::new())), monitor: module_info.monitor.clone(), pos, - current_widget: None, + current_widget: Rc::new(RefCell::new(None)), } } - pub fn register_content(&mut self, key: usize, name: String, content: ModulePopupParts) { + pub fn register_content(&self, key: usize, name: String, content: ModulePopupParts) { debug!("Registered popup content for #{}", key); for button in &content.buttons { @@ -119,45 +121,94 @@ impl Popup { button.set_tag("popup-id", id); } - self.cache.insert(key, PopupCacheValue { name, content }); + let orientation = self.pos.orientation(); + let monitor = self.monitor.clone(); + let window = self.window.clone(); + + let current_widget = self.current_widget.clone(); + let cache = self.cache.clone(); + + content + .container + .connect_size_allocate(move |container, rect| { + if container.is_visible() { + trace!("Resized: {}x{}", rect.width(), rect.height()); + + if let Some((widget_id, button_id)) = *current_widget.borrow() { + if let Some(PopupCacheValue { content, .. }) = + cache.borrow().get(&widget_id) + { + Self::set_position( + &content.buttons, + button_id, + orientation, + &monitor, + &window, + ); + } + } + } + }); + + self.cache + .borrow_mut() + .insert(key, PopupCacheValue { name, content }); } - pub fn show(&mut self, widget_id: usize, button_id: usize) { + pub fn show(&self, widget_id: usize, button_id: usize) { self.clear_window(); - if let Some(PopupCacheValue { content, .. }) = self.cache.get(&widget_id) { - self.current_widget = Some(widget_id); + if let Some(PopupCacheValue { content, .. }) = self.cache.borrow().get(&widget_id) { + *self.current_widget.borrow_mut() = Some((widget_id, button_id)); content.container.style_context().add_class("popup"); self.window.add(&content.container); self.window.show(); - let button = content - .buttons - .iter() - .find(|b| b.popup_id() == button_id) - .expect("to find valid button"); - - let orientation = self.pos.get_orientation(); - let geometry = button.geometry(orientation); - - self.set_pos(geometry); + Self::set_position( + &content.buttons, + button_id, + self.pos.orientation(), + &self.monitor, + &self.window, + ); } } pub fn show_at(&self, widget_id: usize, geometry: WidgetGeometry) { self.clear_window(); - if let Some(PopupCacheValue { content, .. }) = self.cache.get(&widget_id) { + if let Some(PopupCacheValue { content, .. }) = self.cache.borrow().get(&widget_id) { content.container.style_context().add_class("popup"); self.window.add(&content.container); self.window.show(); - self.set_pos(geometry); + Self::set_pos( + geometry, + self.pos.orientation(), + &self.monitor, + &self.window, + ); } } + fn set_position( + buttons: &[Button], + button_id: usize, + orientation: Orientation, + monitor: &Monitor, + window: &ApplicationWindow, + ) { + let button = buttons + .iter() + .find(|b| b.popup_id() == button_id) + .expect("to find valid button"); + + let geometry = button.geometry(orientation); + Self::set_pos(geometry, orientation, monitor, window); + } + fn clear_window(&self) { let children = self.window.children(); for child in children { @@ -166,8 +217,8 @@ impl Popup { } /// Hides the popover - pub fn hide(&mut self) { - self.current_widget = None; + pub fn hide(&self) { + *self.current_widget.borrow_mut() = None; self.window.hide(); } @@ -177,22 +228,25 @@ impl Popup { } pub fn current_widget(&self) -> Option { - self.current_widget + self.current_widget.borrow().map(|w| w.0) } /// Sets the popup's X/Y position relative to the left or border of the screen /// (depending on orientation). - fn set_pos(&self, geometry: WidgetGeometry) { - let orientation = self.pos.get_orientation(); - - let mon_workarea = self.monitor.workarea(); + fn set_pos( + geometry: WidgetGeometry, + orientation: Orientation, + monitor: &Monitor, + window: &ApplicationWindow, + ) { + let mon_workarea = monitor.workarea(); let screen_size = if orientation == Orientation::Horizontal { mon_workarea.width() } else { mon_workarea.height() }; - let (popup_width, popup_height) = self.window.size(); + let (popup_width, popup_height) = window.size(); let popup_size = if orientation == Orientation::Horizontal { popup_width } else { @@ -217,6 +271,6 @@ impl Popup { gtk_layer_shell::Edge::Top }; - self.window.set_layer_shell_margin(edge, offset as i32); + window.set_layer_shell_margin(edge, offset as i32); } }