Waybar icon indicating copy to clipboard operation
Waybar copied to clipboard

wlr/workspace: port to ext-workspace-v1 for labwc support

Open jp7677 opened this issue 8 months ago • 25 comments

This PR allows to use wlr/workspaces with labwc >= 0.8.3. This is more or less a follow up to https://github.com/Alexays/Waybar/pull/3481 and based on https://github.com/labwc/labwc/pull/2365

Additional to labwc, this PR also enables workspaces for niri with https://github.com/YaLTeR/niri/pull/1800

~The heavy lifting is done in this PR, it works with labwc, but it doesn't take protocol differences between the two version into account. The last commit is a hack because workspace creation is too late and doesn't get the initial state (same reason why not the name, but the workspace id appears).~ This is now a complete reimplementation and has seen testing from multiple configurations and compositors, see discussions below. wayland-protocols dependency needs to be >=1.39 for this module to be built.

The big outstanding question is the module name and location. The new upstream workspaces protocol is no longer Wlroots specific, so wlr/workspaces is probably not the best choice.

Obligatory screenshot:

Screenshot

Closes https://github.com/Alexays/Waybar/issues/3967

Note that for CI to fully succeed, https://github.com/Alexays/Waybar/pull/4094 has to land first.

jp7677 avatar Mar 30 '25 16:03 jp7677

I reworked the code to move the workspace creation to the manager to be in line with the protocol. As a result the initial state hack is gone and state/name are properly picked up from labwc. I haven't tested with a multi monitor setup, but the current version works nicely for me i.c.w. labwc. That said, I have a hard time figuring out how features like persistent-workspaces or all-ouputs are supposed to work (both functionality and code-wise). Both are very likely broken with this PR. I'm also not sure if those features still makes sense with the protocol update. May be those features should be dropped? Or may be it makes more sense to start fresh, eventually as a new module? ~Leaving this for now for some feedback about the general direction.~

jp7677 avatar Apr 04 '25 12:04 jp7677

May be those features should be dropped? Or may be it makes more sense to start fresh, eventually as a new module?

The last commit re-implements the module from scratch. I'm quite happy with the result. All config options should still work with the exception of "persistent-workspaces". I did not took this over because of above mentioned reasons.

From my perspective this is ready for testing and of course still ready for general feedback on the direction and how this should fit in.

TODO:

  • [x] Do not bump the required wayland-protocol version, but build the workspaces module conditionally based on the detected version
  • [x] Tweak documentation
  • [x] Squash commits
  • [x] Testing (limited, from developers perspective)

jp7677 avatar Apr 10 '25 15:04 jp7677

I'm happy with how this PR turned out and all things that needs to be done in my opinion are done. Ready for review!

The main question still remains though: should this be a new module (since the protocol is no longer wlr specific) or, what this PR is, an in-place port.

jp7677 avatar Apr 11 '25 06:04 jp7677

Any info on whether this will be merged?

I compiled waybar with the workspace patch and it works great with labwc, at least for my simple usecase of a desktop with a single monitor and a laptop, both with virtual desktops.

Alanon202 avatar Apr 22 '25 12:04 Alanon202

Thanks for firing up CI. The meson magic should be good now, also linting for the files this PR touches. Let's if CI agrees ;)

If you want, I can also add a few separate commits for fixing the formatting in other modules so that CI will become completely green.

Edit: Missed a few & and * aligns, hopefully now good.

jp7677 avatar Apr 25 '25 11:04 jp7677

very nice!! its builds on gentoo against 0.12.0 but one tiny issue and its to do with the unicode symbols for workspaces

entry in the config: 2025-04-27_11-04-1745749493

running wayland: 2025-04-27_11-04-1745749527

it using the "default" icon throughout

eeyrjmr avatar Apr 27 '25 10:04 eeyrjmr

very nice!! its builds on gentoo against 0.12.0 but one tiny issue and its to do with the unicode symbols for workspaces

You need to use the names of the workspaces in the configuration section, not the id. With a default labwc setup this looks like this:

        "format-icons": {
                "Workspace 1": "",
                "Workspace 2": "",
                "Workspace 3": "",
                "Workspace 4": "",
                "Workspace 5": "",
                "active": "",
                "default": ""
        },

I've changed the documentation section in this PR accordingly, so thanks for pointing this out.

jp7677 avatar Apr 27 '25 10:04 jp7677

that works! thankyou!!

eeyrjmr avatar Apr 27 '25 10:04 eeyrjmr

First - thx for this @jp7677! - tested out this patch set today and see 2 noticeable issues atm

  1. When using multiple outputs/monitors (extend, not clone), no matter if sort-by-id is set (with all other sort options = false) and all-outputs = true, the sort-by-id appears to only take effect on a single output while the other(s) retain sort-by-name
  2. When changing output configurations (e.g. kanshi, wlr-randr) and what appeared to be resume from swayidle while waybar is using wlr/workspaces, waybar will segfault (few backtraces below)
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000000000055c1da in sigc::internal::signal_emit0<void, sigc::nil>::emit (impl=0x3100000000) at /usr/include/sigc++-2.0/sigc++/signal.h:786
786	     if (!impl || impl->slots_.empty()) return;
[Current thread is 1 (Thread 0x7fd2a957f980 (LWP 19200))]
(gdb) bt
#0  0x000000000055c1da in sigc::internal::signal_emit0<void, sigc::nil>::emit (impl=0x3100000000) at /usr/include/sigc++-2.0/sigc++/signal.h:786
#1  0x00007fd2ab7d1bd9 in Glib::DispatchNotifier::pipe_io_handler(Glib::IOCondition) () at /usr/lib64/libglibmm-2.4.so.1
#2  0x00007fd2ab7d3fec in Glib::IOSource::dispatch(sigc::slot_base*) () at /usr/lib64/libglibmm-2.4.so.1
#3  0x00007fd2ab7d3ba7 in Glib::Source::dispatch_vfunc(_GSource*, int (*)(void*), void*) () at /usr/lib64/libglibmm-2.4.so.1
#4  0x00007fd2ab60e7c5 in ??? () at /usr/lib64/libglib-2.0.so.0
#5  0x00007fd2ab6107b7 in ??? () at /usr/lib64/libglib-2.0.so.0
#6  0x00007fd2ab610ebc in g_main_context_iteration () at /usr/lib64/libglib-2.0.so.0
#7  0x00007fd2ab8ed78d in g_application_run () at /usr/lib64/libgio-2.0.so.0
#8  0x000000000047eeb2 in waybar::Client::main (this=this@entry=0x15b52a10, argc=<optimized out>, argc@entry=1, argv=<optimized out>, argv@entry=0x7ffdbc85eb38) at /usr/include/glibmm-2.4/glibmm/refptr.h:259
#9  0x0000000000472464 in main (argc=1, argv=0x7ffdbc85eb38) at ../src/main.cpp:107
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007fb04fa8ea05 in Glib::DispatchNotifier::send_notification(Glib::Dispatcher*) () from /usr/lib64/libglibmm-2.4.so.1
[Current thread is 1 (Thread 0x7fb04c56e980 (LWP 19959))]
(gdb) bt
#0  0x00007fb04fa8ea05 in Glib::DispatchNotifier::send_notification(Glib::Dispatcher*) () at /usr/lib64/libglibmm-2.4.so.1
#1  0x00000000004ff689 in waybar::modules::wlr::WorkspaceManager::handle_done (this=<optimized out>) at ../src/modules/wlr/workspace_manager.cpp:120
#2  0x0000000000505bc2 in waybar::modules::wlr::workspace_manager_handle_done (data=<optimized out>, _=<optimized out>) at ../src/modules/wlr/workspace_manager_binding.cpp:45
#3  0x00007fb04e1260ca in ??? () at /usr/lib64/libffi.so.8
#4  0x00007fb04e125600 in ??? () at /usr/lib64/libffi.so.8
#5  0x00007fb04e125cbd in ffi_call () at /usr/lib64/libffi.so.8
#6  0x00007fb04fc61851 in ??? () at /usr/lib64/libwayland-client.so.0
#7  0x00007fb04fc5dbbf in ??? () at /usr/lib64/libwayland-client.so.0
#8  0x00007fb04fc5eddb in wl_display_dispatch_queue_pending () at /usr/lib64/libwayland-client.so.0
#9  0x00007fb04e9676c4 in ??? () at /usr/lib64/libgdk-3.so.0
#10 0x00007fb04e92f050 in gdk_display_get_event () at /usr/lib64/libgdk-3.so.0
#11 0x00007fb04e9673e2 in ??? () at /usr/lib64/libgdk-3.so.0
#12 0x00007fb04e5917c5 in ??? () at /usr/lib64/libglib-2.0.so.0
#13 0x00007fb04e5937b7 in ??? () at /usr/lib64/libglib-2.0.so.0
#14 0x00007fb04e593ebc in g_main_context_iteration () at /usr/lib64/libglib-2.0.so.0
#15 0x00007fb04e7df78d in g_application_run () at /usr/lib64/libgio-2.0.so.0
#16 0x000000000047eeb2 in waybar::Client::main (this=this@entry=0x105bda10, argc=<optimized out>, argc@entry=1, argv=<optimized out>, argv@entry=0x7ffdc9b0f8c8) at /usr/include/glibmm-2.4/glibmm/refptr.h:259
#17 0x0000000000472464 in main (argc=1, argv=0x7ffdc9b0f8c8) at ../src/main.cpp:107

earies avatar May 10 '25 22:05 earies

When changing output configurations (e.g. kanshi, wlr-randr) and what appeared to be resume from swayidle while waybar is using wlr/workspaces, waybar will segfault (few backtraces below)

Thanks a lot for raising this. Seems that I had a small misunderstanding how the Waybar WorkspaceManager is supposed to work. I could reproduce this with unplugging/plugging a second monitor. I've reworked deconstruction and it should be good now. Could you please retest and report back?

When using multiple outputs/monitors (extend, not clone), no matter if sort-by-id is set (with all other sort options = false) and all-outputs = true, the sort-by-id appears to only take effect on a single output while the other(s) retain sort-by-name

Am I assuming correctly that you are using labwc? Could you please share the desktop part of your labwc desktop configuration and the wlr/workspaces part of your waybar config? The sorting works fine here, lets see if I can reproduce with your configuration.

Note though that all-outputs doesn't matter for labwc since workspaces in labwc are global and not per output, so each output already gets all workspace assigned to. Also note that labwc doesn't send IDs for workspaces, only names, as a fallback an internal Waybar counter is used. So setting workspace names in the labwc configuration and using sort-by-name is the clearest approach. That said, I've also reworked the ID/name fallback in Waybar, those should be identical now for each output (since the counter is no longer global but per WorkspaceManager). Please let me know if that improves what you are seeing.

PS: You can show both name and ID with e.g. "format": "{name} ({id})", may be that helps to identify whats going on.

jp7677 avatar May 11 '25 13:05 jp7677

I've reworked deconstruction and it should be good now. Could you please retest and report back?

Much better now - so far so good testing a few hotplug situations w/ multiple monitors

Am I assuming correctly that you are using labwc?

Yes, sorry - testing performed against commit https://github.com/labwc/labwc/commit/cb58156904ec3e3401c8600b784485c36b978716

Could you please share the desktop part of your labwc desktop configuration

  <desktops>
    <popupTime>300</popupTime>
    <number>12</number>
    <names>
      <name>1</name>
      <name>2</name>
      <name>3</name>
      <name>4</name>
      <name>5</name>
      <name>6</name>
      <name>7</name>
      <name>8</name>
      <name>9</name>
      <name>10</name>
      <name>11</name>
      <name>12</name>
    </names>
  </desktops>

As you can see above, the workspace "names" are integers but the prior ordering issue I was encountering was string sorting on one output (e.g. 1, 10, 11, 12, 2, 3, 4, ....)

Now, I observe both outputs with the same ordering. Commenting out all "sort" options gives the desired behavior but flipping any of below to true will result in the described above behavior

    "wlr/workspaces": {
        "format": "   {name}   ",
        "on-click": "activate",
        "format-icons": {
            "active": "🔳",
            "default": "⬜",
            "urgent": "🟥"
        }
        //"all-outputs": true,
        //"sort-by-coordinates": false,
        //"sort-by-name": false,
        //"sort-by-id": true
    },

20250511-094337

earies avatar May 11 '25 15:05 earies

Much better now - so far so good testing a few hotplug situations w/ multiple monitors

Nice!

Now, I observe both outputs with the same ordering. Commenting out all "sort" options gives the desired behavior but flipping any of below to true will result in the described above behavior

Ah right, the workspace ID and name are both strings, thus string sorting and not number sorting is applied. Only when no sorting is set, it falls back to sort by an internal ID which is an integer (https://github.com/jp7677/Waybar/blob/ext-workspaces/src/modules/wlr/workspace_manager.cpp#L158 ).
What is wise? I can stick to the old implementation and change sort-by-id to actually do sort-by-name-numerically which would work nicely since labwc doesn't send ID's. That said, since the protocol defines ID and name, having sort-by-id to not do sort by ID can also be confusing.

PS: I guess this works for you?

Patch

diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp
index 9c88f210..b339f7e6 100644
--- a/src/modules/wlr/workspace_manager.cpp
+++ b/src/modules/wlr/workspace_manager.cpp
@@ -158,7 +158,10 @@ void WorkspaceManager::update() {
   if (sort_by_id_ || sort_by_name_ || sort_by_coordinates_) {
     std::sort(workspaces_.begin(), workspaces_.end(), [&](const auto &w1, const auto &w2) {
       if (sort_by_id_) {
-        return w1->workspace_id() < w2->workspace_id();
+        // the idea is that phonetic compare can be applied
+        // just to numbers with same number of digits
+        return w1->name().size() < w2->name().size() ||
+               (w1->name().size() == w2->name().size() && w1->name() < w2->name());
       }
       if (sort_by_name_) {
         return w1->name() < w2->name();

PPS: I've pushed a commit (now squashed) that detects if numeric sorting should be applied for both name and workspace ID. In your case all sort settings except coordinates should yield numeric sorting.

jp7677 avatar May 11 '25 16:05 jp7677

PPS: I've pushed a commit (can be squashed later) that detects if numeric sorting should be applied for both name and workspace ID. In your case all sort settings except coordinates should yield numeric sorting.

Thx - latest commits LGTM (note: "sort-by-coordinates": true w/ all others set to false still appears to preserve numeric sorting of workspace names)

earies avatar May 11 '25 22:05 earies

PPS: I've pushed a commit (can be squashed later) that detects if numeric sorting should be applied for both name and workspace ID. In your case all sort settings except coordinates should yield numeric sorting.

Thx - latest commits LGTM (note: "sort-by-coordinates": true w/ all others set to false still appears to preserve numeric sorting of workspace names)

Nice. I did a last optimization, sort only when needed, but this shouldn't change anything. W.r.t. coordinates, labwc doesn't send coordinates, so in that case ordering falls back again to internal ID, which is order by creation which matches numeric sorting in your case.

jp7677 avatar May 12 '25 04:05 jp7677

@Alexays Any chance that you could fire up CI again? Thanks!

jp7677 avatar May 24 '25 05:05 jp7677

@Alexays Gentle ping.

jp7677 avatar Jun 09 '25 06:06 jp7677

Hi, I'm implementing ext-workspace in niri: https://github.com/YaLTeR/niri/pull/1800

I tested this PR, seems to work well, except for one problem: the bar only shows workspaces for one of the outputs (either my first or my second output), even with "all-outputs": true. It behaves as if it's not aware of workspaces on other outputs.

Suggested config:

    "wlr/workspaces": {
        "sort-by-name": false,
        "sort-by-coordinates": true,
        "on-click": "activate"
    },

Wayland debug log with two outputs:

└─ WAYLAND_DEBUG=1 ~/source/cpp/Waybar/build/waybar 2>| grep -E '(workspace|wl_output)'
[3780157.365] {Default Queue} wl_registry#2.global(29, "ext_workspace_manager_v1", 1)
[3780157.403] {Default Queue} wl_registry#2.global(43, "wl_output", 4)
[3780157.405] {Default Queue}  -> wl_registry#2.bind(43, "wl_output", 2, new id [unknown]#19)
[3780157.437] {Default Queue}  -> zxdg_output_manager_v1#8.get_xdg_output(new id zxdg_output_v1#20, wl_output#19)
[3780157.443] {Default Queue} wl_registry#2.global(44, "wl_output", 4)
[3780157.445] {Default Queue}  -> wl_registry#2.bind(44, "wl_output", 2, new id [unknown]#22)
[3780157.452] {Default Queue}  -> zxdg_output_manager_v1#8.get_xdg_output(new id zxdg_output_v1#23, wl_output#22)
[3780165.700] {Default Queue} wl_output#19.geometry(0, 0, 700, 390, 0, "Acer Technologies", "XV320QU LV", 0)
[3780165.706] {Default Queue} wl_output#19.mode(3, 2560, 1440, 170071)
[3780165.709] {Default Queue} wl_output#19.scale(1)
[3780165.711] {Default Queue} wl_output#19.done()
[3780165.726] {Default Queue} wl_output#19.done()
[3780165.731] {Default Queue} wl_output#22.geometry(2560, 0, 600, 340, 0, "Dell Inc.", "Dell S2716DG", 0)
[3780165.735] {Default Queue} wl_output#22.mode(3, 2560, 1440, 143998)
[3780165.738] {Default Queue} wl_output#22.scale(1)
[3780165.739] {Default Queue} wl_output#22.done()
[3780165.749] {Default Queue} wl_output#22.done()
[2025-06-14 17:21:35.524] [info] Using configuration file /var/home/yalter/.config/waybar/config.jsonc
[2025-06-14 17:21:35.526] [info] Using CSS file /var/home/yalter/.config/waybar/style.css
[3780184.732] {Default Queue} wl_registry#34.global(29, "ext_workspace_manager_v1", 1)
[3780184.755] {Default Queue} wl_registry#34.global(43, "wl_output", 4)
[3780184.756] {Default Queue} wl_registry#34.global(44, "wl_output", 4)
[3780185.066] {Default Queue} wl_registry#35.global(29, "ext_workspace_manager_v1", 1)
[3780185.093] {Default Queue} wl_registry#35.global(43, "wl_output", 4)
[3780185.096] {Default Queue} wl_registry#35.global(44, "wl_output", 4)
[3780185.108] {Default Queue}  -> zxdg_output_manager_v1#36.get_xdg_output(new id zxdg_output_v1#38, wl_output#19)
[3780185.114] {Default Queue}  -> zxdg_output_manager_v1#36.get_xdg_output(new id zxdg_output_v1#41, wl_output#22)
[2025-06-14 17:21:35.530] [info] Niri IPC starting
[3780187.176] {Default Queue} wl_output#19.done()
[3780187.467] {Default Queue} wl_output#22.done()
[3780188.830] {Default Queue} wl_registry#42.global(29, "ext_workspace_manager_v1", 1)
[3780188.832] {Default Queue}  -> wl_registry#42.bind(29, "ext_workspace_manager_v1", 1, new id [unknown]#41)
[3780188.856] {Default Queue} wl_registry#42.global(43, "wl_output", 4)
[3780188.858] {Default Queue} wl_registry#42.global(44, "wl_output", 4)
[3780188.916] {Default Queue} wl_registry#44.global(29, "ext_workspace_manager_v1", 1)
[3780188.918] {Default Queue}  -> wl_registry#44.bind(29, "ext_workspace_manager_v1", 1, new id [unknown]#43)
[3780188.942] {Default Queue} wl_registry#44.global(43, "wl_output", 4)
[3780188.943] {Default Queue} wl_registry#44.global(44, "wl_output", 4)
[2025-06-14 17:21:35.534] [warning] No batteries.
[3780204.622] {Default Queue}  -> zwlr_layer_shell_v1#40.get_layer_surface(new id zwlr_layer_surface_v1#38, wl_surface#45, wl_output#22, 2, "waybar")
[3780206.412] {Default Queue} ext_workspace_manager_v1#41.workspace(new id ext_workspace_handle_v1#4278190080)
[3780206.561] {Default Queue} ext_workspace_handle_v1#4278190080.name("2")
[3780206.566] {Default Queue} ext_workspace_handle_v1#4278190080.coordinates(array[8])
[3780206.569] {Default Queue} ext_workspace_handle_v1#4278190080.state(0)
[3780206.571] {Default Queue} ext_workspace_handle_v1#4278190080.capabilities(9)
[3780206.573] {Default Queue} ext_workspace_manager_v1#41.workspace(new id ext_workspace_handle_v1#4278190081)
[3780206.600] {Default Queue} ext_workspace_handle_v1#4278190081.name("1")
[3780206.604] {Default Queue} ext_workspace_handle_v1#4278190081.coordinates(array[8])
[3780206.605] {Default Queue} ext_workspace_handle_v1#4278190081.state(0)
[3780206.607] {Default Queue} ext_workspace_handle_v1#4278190081.capabilities(9)
[3780206.609] {Default Queue} ext_workspace_manager_v1#41.workspace(new id ext_workspace_handle_v1#4278190082)
[3780206.632] {Default Queue} ext_workspace_handle_v1#4278190082.id("browser")
[3780206.635] {Default Queue} ext_workspace_handle_v1#4278190082.name("browser")
[3780206.637] {Default Queue} ext_workspace_handle_v1#4278190082.coordinates(array[8])
[3780206.638] {Default Queue} ext_workspace_handle_v1#4278190082.state(1)
[3780206.640] {Default Queue} ext_workspace_handle_v1#4278190082.capabilities(9)
[3780206.642] {Default Queue} ext_workspace_manager_v1#41.workspace(new id ext_workspace_handle_v1#4278190083)
[3780206.663] {Default Queue} ext_workspace_handle_v1#4278190083.id("discord")
[3780206.666] {Default Queue} ext_workspace_handle_v1#4278190083.name("discord")
[3780206.668] {Default Queue} ext_workspace_handle_v1#4278190083.coordinates(array[8])
[3780206.670] {Default Queue} ext_workspace_handle_v1#4278190083.state(1)
[3780206.672] {Default Queue} ext_workspace_handle_v1#4278190083.capabilities(9)
[3780206.673] {Default Queue} ext_workspace_manager_v1#41.workspace(new id ext_workspace_handle_v1#4278190084)
[3780206.704] {Default Queue} ext_workspace_handle_v1#4278190084.id("chat")
[3780206.707] {Default Queue} ext_workspace_handle_v1#4278190084.name("chat")
[3780206.709] {Default Queue} ext_workspace_handle_v1#4278190084.coordinates(array[8])
[3780206.710] {Default Queue} ext_workspace_handle_v1#4278190084.state(0)
[3780206.712] {Default Queue} ext_workspace_handle_v1#4278190084.capabilities(9)
[3780206.714] {Default Queue} ext_workspace_manager_v1#41.workspace_group(new id ext_workspace_group_handle_v1#4278190085)
[3780206.716] {Default Queue} ext_workspace_group_handle_v1#4278190085.capabilities(0)
[3780206.718] {Default Queue} ext_workspace_group_handle_v1#4278190085.output_enter(wl_output#19)
[3780206.720] {Default Queue} ext_workspace_group_handle_v1#4278190085.workspace_enter(ext_workspace_handle_v1#4278190081)
[3780206.721] {Default Queue} ext_workspace_group_handle_v1#4278190085.workspace_enter(ext_workspace_handle_v1#4278190082)
[3780206.723] {Default Queue} ext_workspace_manager_v1#41.workspace_group(new id ext_workspace_group_handle_v1#4278190086)
[3780206.725] {Default Queue} ext_workspace_group_handle_v1#4278190086.capabilities(0)
[3780206.727] {Default Queue} ext_workspace_group_handle_v1#4278190086.output_enter(wl_output#22)
[3780206.729] {Default Queue} ext_workspace_group_handle_v1#4278190086.workspace_enter(ext_workspace_handle_v1#4278190080)
[3780206.730] {Default Queue} ext_workspace_group_handle_v1#4278190086.workspace_enter(ext_workspace_handle_v1#4278190083)
[3780206.732] {Default Queue} ext_workspace_group_handle_v1#4278190086.workspace_enter(ext_workspace_handle_v1#4278190084)
[3780206.734] {Default Queue} ext_workspace_manager_v1#41.done()
[3780206.737] {Default Queue} ext_workspace_manager_v1#43.workspace(new id ext_workspace_handle_v1#4278190087)
[3780206.760] {Default Queue} ext_workspace_handle_v1#4278190087.name("2")
[3780206.762] {Default Queue} ext_workspace_handle_v1#4278190087.coordinates(array[8])
[3780206.764] {Default Queue} ext_workspace_handle_v1#4278190087.state(0)
[3780206.766] {Default Queue} ext_workspace_handle_v1#4278190087.capabilities(9)
[3780206.768] {Default Queue} ext_workspace_manager_v1#43.workspace(new id ext_workspace_handle_v1#4278190088)
[3780206.788] {Default Queue} ext_workspace_handle_v1#4278190088.name("1")
[3780206.792] {Default Queue} ext_workspace_handle_v1#4278190088.coordinates(array[8])
[3780206.794] {Default Queue} ext_workspace_handle_v1#4278190088.state(0)
[3780206.796] {Default Queue} ext_workspace_handle_v1#4278190088.capabilities(9)
[3780206.798] {Default Queue} ext_workspace_manager_v1#43.workspace(new id ext_workspace_handle_v1#4278190089)
[3780206.818] {Default Queue} ext_workspace_handle_v1#4278190089.id("browser")
[3780206.820] {Default Queue} ext_workspace_handle_v1#4278190089.name("browser")
[3780206.822] {Default Queue} ext_workspace_handle_v1#4278190089.coordinates(array[8])
[3780206.824] {Default Queue} ext_workspace_handle_v1#4278190089.state(1)
[3780206.825] {Default Queue} ext_workspace_handle_v1#4278190089.capabilities(9)
[3780206.827] {Default Queue} ext_workspace_manager_v1#43.workspace(new id ext_workspace_handle_v1#4278190090)
[3780206.855] {Default Queue} ext_workspace_handle_v1#4278190090.id("discord")
[3780206.857] {Default Queue} ext_workspace_handle_v1#4278190090.name("discord")
[3780206.859] {Default Queue} ext_workspace_handle_v1#4278190090.coordinates(array[8])
[3780206.861] {Default Queue} ext_workspace_handle_v1#4278190090.state(1)
[3780206.862] {Default Queue} ext_workspace_handle_v1#4278190090.capabilities(9)
[3780206.864] {Default Queue} ext_workspace_manager_v1#43.workspace(new id ext_workspace_handle_v1#4278190091)
[3780206.883] {Default Queue} ext_workspace_handle_v1#4278190091.id("chat")
[3780206.886] {Default Queue} ext_workspace_handle_v1#4278190091.name("chat")
[3780206.888] {Default Queue} ext_workspace_handle_v1#4278190091.coordinates(array[8])
[3780206.890] {Default Queue} ext_workspace_handle_v1#4278190091.state(0)
[3780206.892] {Default Queue} ext_workspace_handle_v1#4278190091.capabilities(9)
[3780206.893] {Default Queue} ext_workspace_manager_v1#43.workspace_group(new id ext_workspace_group_handle_v1#4278190092)
[3780206.895] {Default Queue} ext_workspace_group_handle_v1#4278190092.capabilities(0)
[3780206.897] {Default Queue} ext_workspace_group_handle_v1#4278190092.output_enter(wl_output#19)
[3780206.899] {Default Queue} ext_workspace_group_handle_v1#4278190092.workspace_enter(ext_workspace_handle_v1#4278190088)
[3780206.900] {Default Queue} ext_workspace_group_handle_v1#4278190092.workspace_enter(ext_workspace_handle_v1#4278190089)
[3780206.902] {Default Queue} ext_workspace_manager_v1#43.workspace_group(new id ext_workspace_group_handle_v1#4278190093)
[3780206.904] {Default Queue} ext_workspace_group_handle_v1#4278190093.capabilities(0)
[3780206.906] {Default Queue} ext_workspace_group_handle_v1#4278190093.output_enter(wl_output#22)
[3780206.908] {Default Queue} ext_workspace_group_handle_v1#4278190093.workspace_enter(ext_workspace_handle_v1#4278190087)
[3780206.909] {Default Queue} ext_workspace_group_handle_v1#4278190093.workspace_enter(ext_workspace_handle_v1#4278190090)
[3780206.911] {Default Queue} ext_workspace_group_handle_v1#4278190093.workspace_enter(ext_workspace_handle_v1#4278190091)
[3780206.913] {Default Queue} ext_workspace_manager_v1#43.done()
[3780206.915] {Default Queue} wl_surface#45.enter(wl_output#22)
[2025-06-14 17:21:35.552] [warning] No batteries.
[3780209.391] {Default Queue}  -> zwlr_layer_shell_v1#40.get_layer_surface(new id zwlr_layer_surface_v1#47, wl_surface#46, wl_output#19, 2, "waybar")
[3780210.152] {Default Queue} wl_surface#46.enter(wl_output#19)
[2025-06-14 17:21:35.774] [info] Bar configured (width: 50, height: 1440) for output: DP-2
[2025-06-14 17:21:35.774] [error] Item '': No icon name or pixmap given.
[2025-06-14 17:21:35.786] [error] Item '': No icon name or pixmap given.
[2025-06-14 17:21:35.788] [info] Bar configured (width: 35, height: 1440) for output: DP-1

YaLTeR avatar Jun 14 '25 14:06 YaLTeR

Just a small nitpick: using wlr/workspaces feels wrong, its the official wayland protocol for workspaces rather than a wlroots one.

Consolatis avatar Jun 14 '25 14:06 Consolatis

Just a small nitpick: using wlr/workspaces feels wrong, its the official wayland protocol for workspaces rather than a wlroots one.

Yes, I agree on that. I had hoped to get a hint from the maintainers here for a better location/name, but so far no feedback :( I'm hesitant to decide for myself how this PR fits best into this project.

jp7677 avatar Jun 14 '25 14:06 jp7677

Hi, I'm implementing ext-workspace in niri: YaLTeR/niri#1800

I tested this PR, seems to work well, except for one problem: the bar only shows workspaces for one of the outputs (either my first or my second output), even with "all-outputs": true. It behaves as if it's not aware of workspaces on other outputs.

Thanks for the report. Could you describe more detailed how your setup looks like and what you are seeing? From the logs I'm seeing the following (may be with DP-1/2 reversed):

Output DP-2

  • Workspace group
    • Workspace "1"
    • Workspace "browser"

Output DP-1

  • Workspace group
    • Workspace "2
    • Workspace "discord"
    • Workspace "chat"

Waybar is configured for both outputs (so internally two waybar workspace manager are created and both should know the full topology, whereas each waybar workspace manager is bound to exactly one output).

With "all-outputs" set to "false" (which is the default), do you see the correct workspaces on each output? With "all-outputs" set to "true", does anything changes or is the result on both outputs exactly the same?

jp7677 avatar Jun 14 '25 15:06 jp7677

With all-outputs false, I see workspaces only on one of the bars (for that output). Across compositor restarts I've seen it use either.

With all-outputs true, I see the same set of workspaces (for that one output) on both.

YaLTeR avatar Jun 14 '25 15:06 YaLTeR

~Could you please post the waybar logs prefixed with [wlr/workspaces] when running waybar with debug logging (waybar -l debug)?~

jp7677 avatar Jun 14 '25 15:06 jp7677

I think I see what's going on, clearly my fault ;) Will get to work...

jp7677 avatar Jun 14 '25 16:06 jp7677

@YaLTeR Could you please try again with the last (forced) pushed commit?

jp7677 avatar Jun 14 '25 17:06 jp7677

Seems to work well!

YaLTeR avatar Jun 14 '25 20:06 YaLTeR

@jp7677

When marking the workspace as hidden, is it allowed to completely hide the workspace button on waybar?

like this:

button.set_visible(false);

Currently, only a hidden attribute has been added to it.This doesn't make him hide completely.

Perhaps an option could be added to support hiding, which is very friendly for compositor like river and dwl that are based on fixed tag lengths. You can also see that waybar has relevant pr requests to achieve the hiding of some buttons about these compositor.

DreamMaoMao avatar Jun 19 '25 12:06 DreamMaoMao

@DreamMaoMao thanks for the suggestion. This is probably easy to achieve but I would prefer to do this after this PR has landed, or at least when there is a path forward for getting this merged.

jp7677 avatar Jun 19 '25 16:06 jp7677

Btw I also think that renaming the module to ext/workspace would make sense. Especially since wlr/workspace hasn't been enabled by default yet I think?

YaLTeR avatar Jun 19 '25 16:06 YaLTeR

Btw I also think that renaming the module to ext/workspace would make sense. Especially since wlr/workspace hasn't been enabled by default yet I think?

Yes I agree. As stated above, I’m looking for a hint from the maintainers here how to handle this (naming, file locations, etc) in the best interest of the project.

jp7677 avatar Jun 19 '25 17:06 jp7677

I'd just s/wlr/ext/g and call it a day.

Consolatis avatar Jun 19 '25 17:06 Consolatis