#hyprland #wayland #yambar

app yambar-hyprland-wses

Hyprland workspace listing script for Yambar

1 unstable release

0.1.0 Jul 16, 2023

#983 in Command line utilities

MIT/Apache and GPL-3.0-or-later

16KB
103 lines

Enable Yambar to show Hyprland workspaces.

Yambar doesn't currently have a mechanism for displaying Hyprland workspaces. There is at least one polling script out there that does it, but because it is polling, it feels sluggish and is less efficient than it could be.

This tool uses the Hyprland plugin interface via the hyprland crate to query and display the workspace list, and then listen for changes whenever they happen. It does so in a way that is compatible with the Yambar script module so that a Yambar configuration can visualize an always-up-to-date Hyprland workspace list.

Outputs

The script, when run, outputs the following (using Yambar's script module output format):

workspace_N|string|The Hyprland name of the workspace
workspace_N_windows|int|The number of windows on the workspace
workspace_N_index_on_monitor|int|The index of the workspace on its monitor
workspace_N_monitor|string|The name of the monitor the workspace is on
workspace_N_active|bool|Whether the workspace is active on _a_ monitor
workspace_N_focused|bool|Whether the workspace is active _and_ its monitor has focus
workspace_count|int|The total number of workspaces

Caveats

Because Hyprland doesn't provide a mechanism for querying all workspaces (including empty ones), you'll only see workspaces up to and including the latest populated workspace unless you do some tricks in your Yambar config. The tool does inject workspaces between workspaces that are non-empty (which Hyprland also does not report). This may cause issues for some, I'm not sure. If I'm not mistaken, this may be fundamental to Hyprland's model of workspaces (empty workspaces simply do not exist), so there may not be much to do about this.

Because Yambar's support for plugins is very simple, and its "particles" are fairly limited, the Yambar configuration is quite verbose and repetitive (see below). For some reason it also seems to render the particles before the script module has issued its first tags, so you get a bunch of warnings initially upon launching yambar that then go away.

I don't currently have a multi-monitor setup, so I haven't tested how well this works there. It's probably broken. The tool tries to list out workspaces from left to right based on what monitor they're on, and it tries to highlight workspaces that are active on non-focused monitors, but I don't know if any of those bits currently work. Please let me know!

I haven't set up on-click handlers for the configuration below. Feel free to do so. You'll probably want to invoke

hyprctl dispatch workspace N

with maybe some special handling on multi-monitor setups? If you make something good, please do report back!

Yambar configuration file:

    - script:
        path: /home/yourusernamehere/.cargo/bin/yambar-hyprland-wses
        anchors:
          ws_focused: &ws_focused fba922ff
          ws_active: &ws_active ffaa00ff
          ws_empty: &ws_empty 555555ff
          ws_other: &ws_other bbbbbbff
          # you can use `{workspace_N}` here to use the workspace name
          # assigned by Hyprland instead of hard-coding one here.
          ws_1: &ws_1 "I"
          ws_2: &ws_2 "II"
          ws_3: &ws_3 "III"
          ws_4: &ws_4 "IV"
          ws_5: &ws_5 "V"
          ws_6: &ws_6 "VI"
          ws_7: &ws_7 "VII"
          ws_8: &ws_8 "VIII"
          ws_9: &ws_9 "IX"
        content:
          list:
            spacing: 6
            items:
              - map:
                  default:
                    string: { text: *ws_1, foreground: *ws_other }
                  conditions:
                    workspace_count < 2:
                      # if you replace all of these empty: entries with
                      #
                      #   string: { text: *ws_N, foreground: *ws_empty }
                      #
                      # instead, then you'll always see the full
                      # workspace list. however, you'll be unable to use
                      # `{workspace_N}` as the workspace names in the
                      # anchors list above.
                      empty: {}
                    workspace_1_focused:
                      string: { text: *ws_1, foreground: *ws_focused }
                    workspace_1_active:
                      string: { text: *ws_1, foreground: *ws_active }
                    workspace_1_windows == 0:
                      string: { text: *ws_1, foreground: *ws_empty }
              # All of the maps below are identical to the one above,
              # except with N++.
              - map:
                  default:
                    string: { text: *ws_2, foreground: *ws_other }
                  conditions:
                    workspace_count < 3:
                      empty: {}
                    workspace_2_focused:
                      string: { text: *ws_2, foreground: *ws_focused }
                    workspace_2_active:
                      string: { text: *ws_2, foreground: *ws_active }
                    workspace_2_windows == 0:
                      string: { text: *ws_2, foreground: *ws_empty }
              - map:
                  default:
                    string: { text: *ws_3, foreground: *ws_other }
                  conditions:
                    workspace_count < 4:
                      empty: {}
                    workspace_3_focused:
                      string: { text: *ws_3, foreground: *ws_focused }
                    workspace_3_active:
                      string: { text: *ws_3, foreground: *ws_active }
                    workspace_3_windows == 0:
                      string: { text: *ws_3, foreground: *ws_empty }
              - map:
                  default:
                    string: { text: *ws_4, foreground: *ws_other }
                  conditions:
                    workspace_count < 5:
                      empty: {}
                    workspace_4_focused:
                      string: { text: *ws_4, foreground: *ws_focused }
                    workspace_4_active:
                      string: { text: *ws_4, foreground: *ws_active }
                    workspace_4_windows == 0:
                      string: { text: *ws_4, foreground: *ws_empty }
              - map:
                  default:
                    string: { text: *ws_5, foreground: *ws_other }
                  conditions:
                    workspace_count < 6:
                      empty: {}
                    workspace_5_focused:
                      string: { text: *ws_5, foreground: *ws_focused }
                    workspace_5_active:
                      string: { text: *ws_5, foreground: *ws_active }
                    workspace_5_windows == 0:
                      string: { text: *ws_5, foreground: *ws_empty }
              - map:
                  default:
                    string: { text: *ws_6, foreground: *ws_other }
                  conditions:
                    workspace_count < 7:
                      empty: {}
                    workspace_6_focused:
                      string: { text: *ws_6, foreground: *ws_focused }
                    workspace_6_active:
                      string: { text: *ws_6, foreground: *ws_active }
                    workspace_6_windows == 0:
                      string: { text: *ws_6, foreground: *ws_empty }
              - map:
                  default:
                    string: { text: *ws_7, foreground: *ws_other }
                  conditions:
                    workspace_count < 8:
                      empty: {}
                    workspace_7_focused:
                      string: { text: *ws_7, foreground: *ws_focused }
                    workspace_7_active:
                      string: { text: *ws_7, foreground: *ws_active }
                    workspace_7_windows == 0:
                      string: { text: *ws_7, foreground: *ws_empty }
              - map:
                  default:
                    string: { text: *ws_8, foreground: *ws_other }
                  conditions:
                    workspace_count < 9:
                      empty: {}
                    workspace_8_focused:
                      string: { text: *ws_8, foreground: *ws_focused }
                    workspace_8_active:
                      string: { text: *ws_8, foreground: *ws_active }
                    workspace_8_windows == 0:
                      string: { text: *ws_8, foreground: *ws_empty }
              - map:
                  default:
                    string: { text: *ws_9, foreground: *ws_other }
                  conditions:
                    workspace_count < 10:
                      empty: {}
                    workspace_9_focused:
                      string: { text: *ws_9, foreground: *ws_focused }
                    workspace_9_active:
                      string: { text: *ws_9, foreground: *ws_active }
                    workspace_9_windows == 0:
                      string: { text: *ws_9, foreground: *ws_empty }

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~6–15MB
~169K SLoC