Skip to content

feat(glazewm): Add global workspace focus highlighting and persistent workspaces#679

Open
Louis047 wants to merge 4 commits intoamnweb:mainfrom
Louis047:feature/glazewm-persistent-workspaces
Open

feat(glazewm): Add global workspace focus highlighting and persistent workspaces#679
Louis047 wants to merge 4 commits intoamnweb:mainfrom
Louis047:feature/glazewm-persistent-workspaces

Conversation

@Louis047
Copy link

@Louis047 Louis047 commented Feb 4, 2026

GlazeWM Workspaces: Global Focus Highlighting & Persistent Workspaces

Summary

This PR adds global workspace focus highlighting and persistent workspaces support to the GlazeWM Workspaces widget, bringing feature parity with Waybar-style workspace indicators.

Problem

Previously, YASB's GlazeWM widget only highlighted the "focused" workspace per-monitor using hasFocus. In multi-monitor setups, this meant:

  • Monitor 1 would highlight workspace 2 (if focused there)
  • Monitor 2 would highlight workspace 3 (if displayed there)

Users expected the truly focused workspace (the one with keyboard focus) to be highlighted on ALL monitor bars simultaneously.

Solution

1. Global Focus Highlighting (Requires GlazeWM PR)

This PR integrates with a new isFocusedWorkspace field utilizes hasFocus exposed by GlazeWM's IPC. This field indicates the globally focused workspace across all monitors.

Changes:

  • client.py: Added is_focused_workspace field to Workspace dataclass, reading from isFocusedWorkspace Uses hasFocus now for checking global focused workspace
  • workspaces.py: Uses is_focused_workspace instead of hasFocus for button highlighting Utilizes hasFocus to highlight the correct globally focused workspace across monitors
  • Applies global focus to ALL workspace buttons across ALL monitor bars

2. Persistent Workspaces

Added Waybar-style persistent workspaces support with two formats:

Count-based (recommended):

persistent_workspaces:
 "*": 9  # Show 9 workspaces on all monitors

Display name mapping:

persistent_workspaces: 
 "1": "Web" 
 "2": "Code"
 "3": "Chat"

The above will be parsed directly from GlazeWM and assigning a new display_name in persistent_workspaces is invalid. Count-based is the recommended option.

Features:

  • Automatically loads display_name from GlazeWM config at startup
  • Caches display names across all widget instances
  • Creates buttons for workspaces even before they're activated

3. Simplified Status Logic

Updated _update_status() to match Waybar behavior:

  • FOCUSED_POPULATED/FOCUSED_EMPTY: Only the globally focused workspace
  • POPULATED/EMPTY: All other workspaces

Removed intermediate ACTIVE_* states for cleaner styling when using global focus.

Files Changed

File Changes
src/core/utils/widgets/glazewm/client.py Added is_focused_workspace field Uses hasFocus for global focused workspaces
src/core/widgets/glazewm/workspaces.py Global focus logic, persistent workspaces, display_name caching
src/core/validation/widgets/glazewm/workspaces.py Updated persistent_workspaces schema
docs/widgets/(Widget)-GlazeWM-Workspaces.md Documentation updates

Configuration

glazewm_workspaces:
  type: "yasb.glazewm_workspaces.GlazewmWorkspacesWidget"
  options:
    persistent_workspaces:
     "*": 9  # Show 9 workspaces globally
    hide_empty_workspaces: false

Dependencies

This PR requires a corresponding change in GlazeWM to expose the isFocusedWorkspace field via IPC.
GlazeWM PR: glzr-io/glazewm#1264
The linked PR isn't necessary

Testing

  1. Run GlazeWM with isFocusedWorkspace support
  2. Configure YASB with
persistent_workspaces:
 "*": 9
  1. Switch between workspaces on different monitors
  2. Verify the focused workspace is highlighted on ALL monitor bars

@Louis047 Louis047 force-pushed the feature/glazewm-persistent-workspaces branch from ed73273 to 50e5f54 Compare February 4, 2026 17:02
… workspaces

- Add is_focused_workspace field to Workspace dataclass
- Read isFocusedWorkspace from GlazeWM IPC for global focus
- Implement persistent_workspaces with count-based format
- Cache display_names from GlazeWM config at startup
- Simplify status logic to FOCUSED/POPULATED/EMPTY states
- Apply global focus highlighting across all monitor bars

Requires: glzr-io/glazewm#1264
@Louis047 Louis047 force-pushed the feature/glazewm-persistent-workspaces branch from 50e5f54 to 0c15ea1 Compare February 4, 2026 17:03
GlazeWM's hasFocus field is already globally unique - only ONE workspace across all monitors can have hasFocus: true. Removed redundant is_focused_workspace field and updated all usages to use the existing focus field.

Changes:

- Removed is_focused_workspace from Workspace dataclass

- Replaced workspace.is_focused_workspace with workspace.focus
@Louis047
Copy link
Author

Louis047 commented Feb 6, 2026

Update on the Dependencies part:

I have raised this issue with the glazewm dev and he confirmed that the dependency PR linked above isn't necessary and as a solution utilizing hasFocus property for YASB did the job as it looks for globally focused workspace by default. Now, I shall confirm that it is safe to merge the PR.

Copy link
Contributor

@Video-Nomad Video-Nomad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain in detail how those persistent workspaces should work and how it compares to just setting every workspace in GlazeWM as keep_alive: true? You can already set custom names there, bind them to monitors, keep them alive even when they are empty, etc. It's all in GlazeWM config, YASB just uses that information.

I still can't grasp the goal of this persistent workspaces change.

Focused and active workspaces are already customizable as mentioned in the code comments. Just set:

.glazewm-workspaces .ws-btn.active_populated,
.glazewm-workspaces .ws-btn.active_empty {
    background: transparent;
}

# Only the globally focused workspace gets FOCUSED status (highlighted)
# Other workspaces just show as POPULATED or EMPTY - no ACTIVE highlighting
# This matches Waybar-style behavior: only truly focused workspace is highlighted
if self.is_focused:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change completely overrides #550
If the goal was to have no highlighting on an active (but unfocused) workspace there's always an option to change .ws-btn.active_populated and .ws-btn.active_empty to something like background: transparent.
No need to destroy the existing functionality completely.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have provided a good explanation for this, and I think it might answer your queries on this line of code 👍

# Only the globally focused workspace gets FOCUSED status (highlighted)
# Other workspaces just show as POPULATED or EMPTY - no ACTIVE highlighting
# This matches Waybar-style behavior: only truly focused workspace is highlighted
if self.is_focused:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue here

_config_loaded: bool = False

@classmethod
def _load_glazewm_config(cls) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is extremely brittle approach. GlazeWM already provides enough data via IPC connection.

@Louis047
Copy link
Author

Louis047 commented Feb 8, 2026

my apologies for not detailing much about the PR and what it exactly addresses, I'll post the explanation and will look into the code review in detail once I get back home

The main purpose of this PR is to replicate the same behavior of persistent workspaces from hyprland with waybar module.

@Louis047
Copy link
Author

Louis047 commented Feb 8, 2026

As for why keep_alive isn't going to be a reliable option (at least for me), as you can see in the screenshots below (One from YASB and the other from Waybar in Hyprland), I have compared two of my monitor bars with keep_alive: True set for 5 workspaces and you can clearly see that there's a discontinuity in both bars as I have already mentioned to you in discord that I have bound workspace 3 to my second monitor and only that workspace is shown in the second monitor bar which proves my point and is one of the core parts for this PR.

If you still don't understand, here's a good explanation:

  • keep_alive: True for 5 workspaces, should show the 5 workspaces which are active now and should show in both
  • One of the workspace (in my case, workspace 3) is bound to the second monitor
  • Workspace order has discontinuity, which shouldn't be the case

Screenshot comparison

With the above configuration (keep_alive: True for 5 workspaces)

image

Here, YASB highlight the currently active focused workspace for each monitor which isn't a good option and keep_alive's purpose is completely useless here as I navigate through the active workspaces with the following commands from GlazeWM:

  # Focus the next/previous active workspace defined in `workspaces` config.
  - commands: ["focus --next-active-workspace"]
    bindings: ["alt+d"]
  - commands: ["focus --prev-active-workspace"]
    bindings: ["alt+a"]

With keep_alive set as True, I have to go through the "active" workspace every time or by accident, which isn't a good idea. My solution does in a way that the workspaces count would still be shown and that I can still navigate through my real active workspaces without going through the empty workspaces still, while the true global focused workspace is highlighted correctly. This is detailed a bit more in the below screenshot.

How it should work and what my current PR does [Screenshot taken from Hyprland with Waybar]

image

As you can see, waybar has the module configuration for hyprland which allows users to have persistent_workspaces that displays in every monitor bars in correct, continuous order unlike how yasb handles glazewm with discontinuity in the order and also that waybar focuses the global focused workspace and is highlighted correctly (in this case, workspace 4) in both bars instead of highlighting the currently focused active workspace for both screens. This is what my PR exactly addresses for GlazeWM workspaces widget.

Here's my workspace configuration for GlazeWM for you to look into:

workspaces:
  - name: "1"
    # display_name: 'I'
    bind_to_monitor: 0
  - name: "2"
    # display_name: 'II'
    bind_to_monitor: 0
  - name: "3"
    # display_name: 'III'
    bind_to_monitor: 1
  - name: "4"
    # display_name: 'IV'
    bind_to_monitor: 0
  - name: "5"
    # display_name: 'V'
    bind_to_monitor: 0
  - name: "6"
    # display_name: 'F'
    bind_to_monitor: 0
  - name: "7"
    # display_name: 'G'
    bind_to_monitor: 1
  - name: "8"
    # display_name: 'H'
    bind_to_monitor: 1
  - name: "9"
    # display_name: 'I'
    bind_to_monitor: 1

I have removed the keep_alive from the config as I don't use for the above main reasons. Hope you understood the issue now and the true purpose of the PR.

@Louis047
Copy link
Author

Louis047 commented Feb 8, 2026

I have checked your comments on the code review and I'm working on it now 👍

@Louis047
Copy link
Author

Louis047 commented Feb 8, 2026

Here's a screenshot of what my PR does for YASB, which exactly replicates the waybar functionality for hyprland's persistent workspaces module:

image

As you can see, irrespective of the workspace bound monitor rules set in glazewm, it highlights the global focused workspace correctly and persistent workspace count is followed as well. Hope you get a clear idea now after reading the above explanation.

@Video-Nomad
Copy link
Contributor

Video-Nomad commented Feb 8, 2026

So the bottom line is:

  1. You wish to have all workspaces shown on all monitors regardless of the monitor binding in GlazeWM. Right now YASB separates them by default.
  2. You wish to switch between populated (not empty) workspaces using GlazeWM command.

So the solutions here are:

  1. Showing all workspaces can indeed be an option in the widget but not through manual config discovery and parsing. GlazeWM already sends all workspaces to YASB when keep_alive: true via IPC. This info can be used to just combine them and show them on all monitors.
  2. GlazeWM lacks the command to move to --next-populated-workspace and --prev-populated-workspace and skip empty workspaces. Right now it will switch through all the workspaces regardless if they are empty or not. This is not a YASB problem. I suggest you to open a PR there or ask for an additional command that will do exactly that:
  # Focus workspaces skipping empty ones
  - commands: ["focus --next-populated-workspace"]
    bindings: ["alt+d"]
  - commands: ["focus --prev-populated-workspace"]
    bindings: ["alt+a"]

@Louis047
Copy link
Author

Louis047 commented Feb 8, 2026

I shall propose an idea based on your views:

  • Add two new properties
    • global_focus_workspace_highlight - this would allow users to highlight only the currently focused workspace across all screens bars for the widget and this would be useful as it won't affect the current default configuration of the widget which follows focused workspace highlight for each monitor separate. This is an opt-in feature so users either choose to use it or not use it.

    • persistent_workspace - This PR but changed to opt-in, with new option enabled: True/False

      Example Configuration

      glazewm_workspaces:
        persistent_workspaces:
          enabled: True
          "*": 9 # Show all workspaces count on ever screen the bar is visible
        global_focus_workspace_highlight: True # Highlights only the true current focused workspace on every screen the bar is visible

I feel that this would make it more modular and the said features optional for users to utilize it without compromising their default YASB config. Let me know of your thoughts on this. This would allow users who love using keep_alive: True from GlazeWM for workspaces and others who loved using waybar and misses some of its features (like me) who just want their bars to show the correct workspace order in every bar and respect the focus highlight in all of their screens where the bars are active.

I'm ready to refactor the current PR with a better approach with your approval 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants