Skip to content

feat(glazewm): add monitor_exclusive IPC mode and deprecate hide_empty_workspaces#718

Merged
amnweb merged 6 commits intoamnweb:mainfrom
Louis047:feat/glazewm-monitor-exclusive-property
Feb 14, 2026
Merged

feat(glazewm): add monitor_exclusive IPC mode and deprecate hide_empty_workspaces#718
amnweb merged 6 commits intoamnweb:mainfrom
Louis047:feat/glazewm-monitor-exclusive-property

Conversation

@Louis047
Copy link
Contributor

@Louis047 Louis047 commented Feb 13, 2026

Summary

This PR refactors the GlazeWM Workspaces widget to use GlazeWM IPC as the source and adds monitor_exclusive behavior. Supersedes #679

Implemented

  • Added monitor_exclusive option to GlazeWM workspaces config (default: true).
  • Implemented two IPC-driven render modes:
    • monitor_exclusive: true (default): monitor-local rendering and shows all workspaces present in the current monitor IPC payload (including empty keep_alive workspaces).
    • monitor_exclusive: false: aggregated IPC rendering so active workspace count and global focused workspace are consistent across all monitor bars.
  • Added global scroll switching commands for aggregate mode:
    • focus --next-active-workspace
    • focus --prev-active-workspace
  • Deprecated hide_empty_workspaces (kept in schema/config for backward compatibility, no longer used as runtime visibility control for GlazeWM workspaces).
  • Removed stale persistent_workspaces remnants from the GlazeWM workspaces path.
  • Updated docs and regenerated schema.

Why

Review direction was to avoid YASB-side workspace synthesis/parsing and rely on GlazeWM IPC behavior. This PR aligns with that by using IPC monitor/workspace data for visibility/state.

GlazeWM keep_alive context

keep_alive had IPC/startup/reload edge cases. Related GlazeWM PR:

This PR activates keep_alive workspaces on startup and config reload, improving workspace availability consistency via IPC. But it's not a hard dependency as this can be worked around for now by simply restarting GlazeWM after setting keep_alive for required workspaces. YASB will automatically catch this.

Behavior notes

  • monitor_exclusive: false
    • Shows active IPC workspace set on all bars.
    • Highlights globally focused workspace on all bars.
  • monitor_exclusive: true
    • Keeps monitor-local behavior.
    • Shows current monitor IPC workspaces including empty keep_alive workspaces.
  • hide_empty_workspaces
    • Deprecated and retained in schema for backward compatibility.
    • Visibility is controlled by GlazeWM IPC + keep_alive behavior.

Files changed

  • src/core/widgets/glazewm/workspaces.py
  • src/core/utils/widgets/glazewm/client.py
  • src/core/validation/widgets/glazewm/workspaces.py
  • docs/widgets/(Widget)-GlazeWM-Workspaces.md
  • schema.json

Validation

  • Local compile checks passed for modified Python files.
  • Manual multi-monitor verification completed for:
    • monitor_exclusive: false (global focused highlight + shared active count)
    • monitor_exclusive: true (monitor-local behavior with keep_alive visibility)

@Louis047 Louis047 force-pushed the feat/glazewm-monitor-exclusive-property branch from 94cad29 to 97568b1 Compare February 13, 2026 17:22
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.

Thanks for the PR! Nice addition👍
Checked the functionality and it seems to be working as expected.

  • Checked monitor_exclusive: false in both icon and no icon mode.
  • Checked GlazeWM keep_alive: true on workspaces.
  • Checked the new option with GlazeWM name and display_name.
  • Styles seems to be working fine.

Without any changes my default config looks exactly the same.
Other than proposed changes in the comments I think this is good to go.

@@ -85,20 +80,31 @@ def _activate_workspace(self):
self.glazewm_client.activate_workspace(self.workspace_name)

def _update_status(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

This arrow of death is out of control at this point😅
I think something like this might be better:

def _update_status(self):
    is_populated = self.workspace_window_count > 0
    # 1. Highest Priority: Focused
    if self.is_focused:
        self.status = WorkspaceStatus.FOCUSED_POPULATED if is_populated else WorkspaceStatus.FOCUSED_EMPTY
    # 2. Second Priority: Active (Exclusive + Displayed)
    elif self.monitor_exclusive and self.is_displayed:
        self.status = WorkspaceStatus.ACTIVE_POPULATED if is_populated else WorkspaceStatus.ACTIVE_EMPTY
    # 3. Fallback: Default status
    else:
        self.status = WorkspaceStatus.POPULATED if is_populated else WorkspaceStatus.EMPTY

@@ -255,20 +260,31 @@ def _activate_workspace(self):
self.glazewm_client.activate_workspace(self.workspace_name)

def _update_status(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

Same pattern as in the previous comment

schema.json Outdated
"title": "Hide If Offline",
"type": "boolean"
},
"monitor_exclusive": {
Copy link
Contributor

Choose a reason for hiding this comment

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

Schema is auto-generated. No need to add anything manually.

options:
offline_label: "GlazeWM Offline"
hide_empty_workspaces: true
hide_empty_workspaces: true # deprecated (ignored)
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be removed from the docs

| `focused_populated_label`| string | `'{name}'` | Optional label for the currently focused workspace (has opened windows). Falls back to `active_populated_label` if not set. |
| `focused_empty_label` | string | `'{name}'` | Optional label for the currently focused workspace (has no windows opened). Falls back to `active_empty_label` if not set. |
| `hide_empty_workspaces` | boolean | `true` | Whether to hide empty workspaces. |
| `hide_empty_workspaces` | boolean | `true` | Deprecated. Kept for backward compatibility; visibility is controlled by GlazeWM (`keep_alive`) and monitor data from IPC. |
Copy link
Contributor

Choose a reason for hiding this comment

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

This can be removed from the docs

@Louis047
Copy link
Contributor Author

Thanks for reviewing the PR! I have made the changes you have requested and have tested it. It works.

Please do let me know if any further changes are required 👍

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.

Looks good to me 👍

@amnweb amnweb merged commit c96d504 into amnweb:main Feb 14, 2026
3 checks passed
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.

3 participants