From 8cdbe7e083325f41ffa565eaeb63d0841345c8a1 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Fri, 18 Oct 2024 23:58:04 +0100 Subject: [PATCH 1/3] refactor(hyprland): improve logging --- src/clients/compositor/hyprland.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/clients/compositor/hyprland.rs b/src/clients/compositor/hyprland.rs index f7bb09f..063e7b7 100644 --- a/src/clients/compositor/hyprland.rs +++ b/src/clients/compositor/hyprland.rs @@ -119,7 +119,7 @@ impl Client { { Self::send_focus_change(&mut prev_workspace, workspace, &tx); } else { - error!("Unable to locate workspace"); + error!("unable to locate workspace: {workspace_name}"); } }); } @@ -154,6 +154,7 @@ impl Client { event_listener.add_workspace_rename_handler(move |data| { let _lock = lock!(lock); + debug!("Received workspace rename: {data:?}"); send!( tx, From fa6f27d4b9e4ef48d0d2dc3fa80b331b32a7c086 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Sat, 19 Oct 2024 00:07:49 +0100 Subject: [PATCH 2/3] fix(workspaces): rewrite module to fix several small issues Rewrites the module code to be better structured, in a similar pattern to the launcher. The code is now more robust and more maintainable, yay! Fixes #705 Fixes an issue with moving favourite workspaces. Fixes an issue with workspace visible state being incorrect. Fixes an issue where the `inactive` class looked at hidden instead of closed favourites. --- src/clients/compositor/mod.rs | 16 +- src/gtk_helpers.rs | 2 +- src/modules/workspaces.rs | 451 --------------------------- src/modules/workspaces/button.rs | 78 +++++ src/modules/workspaces/button_map.rs | 77 +++++ src/modules/workspaces/mod.rs | 386 +++++++++++++++++++++++ src/modules/workspaces/open_state.rs | 30 ++ 7 files changed, 578 insertions(+), 462 deletions(-) delete mode 100644 src/modules/workspaces.rs create mode 100644 src/modules/workspaces/button.rs create mode 100644 src/modules/workspaces/button_map.rs create mode 100644 src/modules/workspaces/mod.rs create mode 100644 src/modules/workspaces/open_state.rs diff --git a/src/clients/compositor/mod.rs b/src/clients/compositor/mod.rs index 5243fcc..5c92e4e 100644 --- a/src/clients/compositor/mod.rs +++ b/src/clients/compositor/mod.rs @@ -86,29 +86,25 @@ pub struct Workspace { pub visibility: Visibility, } -/// Indicates workspace visibility. Visible workspaces have a boolean flag to indicate if they are also focused. -/// Yes, this is the same signature as Option, but it's impl is a lot more suited for our case. +/// Indicates workspace visibility. +/// Visible workspaces have a boolean flag to indicate if they are also focused. #[derive(Debug, Copy, Clone)] pub enum Visibility { - Visible(bool), + Visible { focused: bool }, Hidden, } impl Visibility { pub fn visible() -> Self { - Self::Visible(false) + Self::Visible { focused: false } } pub fn focused() -> Self { - Self::Visible(true) - } - - pub fn is_visible(self) -> bool { - matches!(self, Self::Visible(_)) + Self::Visible { focused: true } } pub fn is_focused(self) -> bool { - if let Self::Visible(focused) = self { + if let Self::Visible { focused } = self { focused } else { false diff --git a/src/gtk_helpers.rs b/src/gtk_helpers.rs index 5ce9357..de5d8af 100644 --- a/src/gtk_helpers.rs +++ b/src/gtk_helpers.rs @@ -20,7 +20,7 @@ pub struct WidgetGeometry { pub trait IronbarGtkExt { /// Adds a new CSS class to the widget. fn add_class(&self, class: &str); - /// Removes a CSS class to the widget. + /// Removes a CSS class from the widget fn remove_class(&self, class: &str); /// Gets the geometry for the widget fn geometry(&self, orientation: Orientation) -> WidgetGeometry; diff --git a/src/modules/workspaces.rs b/src/modules/workspaces.rs deleted file mode 100644 index 039d969..0000000 --- a/src/modules/workspaces.rs +++ /dev/null @@ -1,451 +0,0 @@ -use crate::clients::compositor::{Visibility, Workspace, WorkspaceClient, WorkspaceUpdate}; -use crate::config::CommonConfig; -use crate::gtk_helpers::IronbarGtkExt; -use crate::image::new_icon_button; -use crate::modules::{Module, ModuleInfo, ModuleParts, ModuleUpdateEvent, WidgetContext}; -use crate::{glib_recv, module_impl, send_async, spawn, try_send, Ironbar}; -use color_eyre::{Report, Result}; -use gtk::prelude::*; -use gtk::{Button, IconTheme}; -use serde::Deserialize; -use std::cmp::Ordering; -use std::collections::{HashMap, HashSet}; -use tokio::sync::mpsc::{Receiver, Sender}; -use tracing::{debug, trace, warn}; - -#[derive(Debug, Deserialize, Clone, Copy, Eq, PartialEq)] -#[serde(rename_all = "snake_case")] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -pub enum SortOrder { - /// Shows workspaces in the order they're added - Added, - /// Shows workspaces in numeric order. - /// Named workspaces are added to the end in alphabetical order. - Alphanumeric, -} - -impl Default for SortOrder { - fn default() -> Self { - Self::Alphanumeric - } -} - -#[derive(Debug, Deserialize, Clone)] -#[serde(untagged)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -pub enum Favorites { - ByMonitor(HashMap>), - Global(Vec), -} - -impl Default for Favorites { - fn default() -> Self { - Self::Global(vec![]) - } -} - -#[derive(Debug, Deserialize, Clone)] -#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] -pub struct WorkspacesModule { - /// Map of actual workspace names to custom names. - /// - /// Custom names can be [images](images). - /// - /// If a workspace is not present in the map, - /// it will fall back to using its actual name. - name_map: Option>, - - /// Workspaces which should always be shown. - /// This can either be an array of workspace names, - /// or a map of monitor names to arrays of workspace names. - /// - /// **Default**: `{}` - /// - /// # Example - /// - /// ```corn - /// // array format - /// { - /// type = "workspaces" - /// favorites = ["1", "2", "3"] - /// } - /// - /// // map format - /// { - /// type = "workspaces" - /// favorites.DP-1 = ["1", "2", "3"] - /// favorites.DP-2 = ["4", "5", "6"] - /// } - /// ``` - #[serde(default)] - favorites: Favorites, - - /// A list of workspace names to never show. - /// - /// This may be useful for scratchpad/special workspaces, for example. - /// - /// **Default**: `[]` - #[serde(default)] - hidden: Vec, - - /// Whether to display workspaces from all monitors. - /// When false, only shows workspaces on the current monitor. - /// - /// **Default**: `false` - #[serde(default = "crate::config::default_false")] - all_monitors: bool, - - /// The method used for sorting workspaces. - /// `added` always appends to the end, `alphanumeric` sorts by number/name. - /// - /// **Valid options**: `added`, `alphanumeric` - ///
- /// **Default**: `alphanumeric` - #[serde(default)] - sort: SortOrder, - - /// The size to render icons at (image icons only). - /// - /// **Default**: `32` - #[serde(default = "default_icon_size")] - icon_size: i32, - - /// See [common options](module-level-options#common-options). - #[serde(flatten)] - pub common: Option, -} - -const fn default_icon_size() -> i32 { - 32 -} - -/// Creates a button from a workspace -fn create_button( - name: &str, - visibility: Visibility, - name_map: &HashMap, - icon_theme: &IconTheme, - icon_size: i32, - tx: &Sender, -) -> Button { - let label = name_map.get(name).map_or(name, String::as_str); - - let button = new_icon_button(label, icon_theme, icon_size); - button.set_widget_name(name); - - button.add_class("item"); - - if visibility.is_visible() { - button.add_class("visible"); - } - - if visibility.is_focused() { - button.add_class("focused"); - } - - if !visibility.is_visible() { - button.add_class("inactive"); - } - - { - let tx = tx.clone(); - let name = name.to_string(); - button.connect_clicked(move |button| { - if !button.style_context().has_class("focused") { - try_send!(tx, name.clone()); - } - }); - } - - button -} - -fn reorder_workspaces(container: >k::Box) { - let mut buttons = container - .children() - .into_iter() - .map(|child| { - let label = child - .downcast_ref::