8000 feat(`HyprlandService`): sync workspaces on ``"renameworkspace"`` event by linkfrg · Pull Request #172 · linkfrg/ignis · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat(HyprlandService): sync workspaces on "renameworkspace" event #172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 9, 2025

Conversation

linkfrg
Copy link
Owner
@linkfrg linkfrg commented Feb 28, 2025

Closes: #94

@ArtemChandragupta
Copy link

If I launch ignis built from main branch with this config

import datetime
from ignis.widgets import Widget
from ignis.utils import Utils
from ignis.app import IgnisApp
from ignis.services.audio import AudioService
from ignis.services.system_tray import SystemTrayService, SystemTrayItem
from ignis.services.hyprland import HyprlandService

app = IgnisApp.get_default()

app.apply_css(f"{Utils.get_current_dir()}/style.scss")

audio         = AudioService.get_default()
system_tray   = SystemTrayService.get_default()
hyprland      = HyprlandService.get_default()

def hyprland_workspace_button(workspace: dict) -> Widget.Button:
    widget = Widget.Button(
        css_classes=["workspace"],
        on_click=lambda x, id=workspace["id"]: hyprland.switch_to_workspace(id),
        child=Widget.Label(
            label=str(workspace["id"]),
        ),
    )
    if workspace["id"] == hyprland.active_workspace["id"]:
        widget.add_css_class("active")

    return widget


def workspace_button(workspace: dict) -> Widget.Button:
    if hyprland.is_available:
        return hyprland_workspace_button(workspace)
    else:
        return Widget.Button()


def hyprland_scroll_workspaces(direction: str) -> None:
    current = hyprland.active_workspace["id"]
    if direction == "up":
        target = current - 1
        hyprland.switch_to_workspace(target)
    else:
        target = current + 1
        if target == 11:
            return
        hyprland.switch_to_workspace(target)


def scroll_workspaces(direction: str, monitor_name: str = "") -> None:
    if hyprland.is_available:
        hyprland_scroll_workspaces(direction)
    else:
        pass


def hyprland_workspaces() -> Widget.EventBox:
    return Widget.EventBox(
        on_scroll_up=lambda x: scroll_workspaces("up"),
        on_scroll_down=lambda x: scroll_workspaces("down"),
        css_classes=["workspaces"],
        spacing=5,
        child=hyprland.bind(
            "workspaces",
            transform=lambda value: [workspace_button(i) for i in value],
        ),
    )


def workspaces(monitor_name: str) -> Widget.EventBox:
    if hyprland.is_available:
        return hyprland_workspaces()
    else:
        return Widget.EventBox()


def clock() -> Widget.Label:
    return Widget.Label(
        css_classes=["clock"],
        label=Utils.Poll(
            1_000, lambda self: datetime.datetime.now().strftime("%H:%M")
        ).bind("output"),
    )


def speaker_volume() -> Widget.Box:
    return Widget.Box(
        child=[
            Widget.Icon(
                image=audio.speaker.bind("icon_name"), style="margin-right: 5px;"
            ),
            Widget.Label(
                label=audio.speaker.bind("volume", transform=lambda value: str(value))
            ),
        ]
    )


def tray_item(item: SystemTrayItem) -> Widget.Button:
    if item.menu:
        menu = item.menu.copy()
    else:
        menu = None

    return Widget.Button(
        child=Widget.Box(
            child=[
                Widget.Icon(image=item.bind("icon"), pixel_size=24),
                menu,
            ]
        ),
        setup=lambda self: item.connect("removed", lambda x: self.unparent()),
        tooltip_text=item.bind("tooltip"),
        on_click=lambda x: menu.popup() if menu else None,
        on_right_click=lambda x: menu.popup() if menu else None,
        css_classes=["tray-item"],
    )


def tray():
    return Widget.Box(
        setup=lambda self: system_tray.connect(
            "added", lambda x, item: self.append(tray_item(item))
        ),
        spacing=10,
    )


def left(monitor_name: str) -> Widget.Box:
    return Widget.Box(
        child=[
            tray(),
            workspaces(monitor_name), 
        ], 
        spacing=10
    )


def center() -> Widget.Box:
    return Widget.Box(
        child=[
            clock(),
        ],
        spacing=10,
    )


def right() -> Widget.Box:
    return Widget.Box(
        child=[
            speaker_volume(),
        ],
        spacing=10,
    )


def bar(monitor_id: int = 0) -> Widget.Window:
    monitor_name = Utils.get_monitor(monitor_id).get_connector()  # type: ignore
    return Widget.Window(
        namespace=f"ignis_bar_{monitor_id}",
        monitor=monitor_id,
        anchor=["left", "top", "right"],
        exclusivity="exclusive",
        child=Widget.CenterBox(
            css_classes=["bar"],
            start_widget=left(monitor_name),  # type: ignore
            center_widget=center(),
            end_widget=right(),
        ),
    )


# this will display bar on all monitors
for i in range(Utils.get_n_monitors()):
    bar(i)

I get the error:

>>-  ignis init
Traceback (most recent call last):
  File "/nix/store/bhnslxcxcmr2qccc9lrj6fp1pjl5lqz5-ignis-0.4.dev0+date=20250228_43af327/bin/.ignis-wrapped", line 4, in <module>
    from ignis.main import main
  File "/nix/store/bhnslxcxcmr2qccc9lrj6fp1pjl5lqz5-ignis-0.4.dev0+date=20250228_43af327/lib/python3.12/site-packages/ignis/__init__.py", line 6, in <module>
    from gi.events import GLibEventLoopPolicy  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ModuleNotFoundError: No module named 'gi.events'
10000

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 1, 2025

Starting from #152 Ignis requires PyGObject 3.50.0 and higher
Hmm, maybe something wrong with the nix package? I don't know much about Nix, but is there any way to "pin" PyGObject version to >=3.50.0?
By the way, there is already the open issue about this: #170

Should be fixed after 0c29504

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 1, 2025

@ArtemChandragupta
In case of testing PR, it's better to set up a dev env and run git checkout feat/hyprland-renameworkspace-sync

@ArtemChandragupta
Copy link
ArtemChandragupta commented Mar 1, 2025

I understand, just want firstly to sinchronize my config with main branch.

Yes, the last commit fixed an issue, but now I have this:

TypeError: 'HyprlandWorkspace' object is not subscriptable
2025-03-01 15:01:07 [ERROR] TypeError: 'HyprlandWorkspace' object is not subscriptable
2025-03-01 15:01:07 [INFO] Using configuration file: /home/artem/.config/ignis/config.py
2025-03-01 15:01:07 [INFO] Applied css: /home/artem/.config/ignis/style.scss
2025-03-01 15:01:07 [ERROR] TypeError: 'HyprlandWorkspace' object is not subscriptable
Traceback (most recent call last):

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/bin/.ignis-wrapped", line 5, in <module>
    main()
    └ <function main at 0x7f696a9294e0>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/main.py", line 12, in main
    cli(prog_name="ignis")
    └ <OrderedGroup cli>

  File "/nix/store/6k64nlqhg20cky326qhh6282z6zkpr5s-python3.12-click-8.1.7/lib/python3.12/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           │    │     │       └ {'prog_name': 'ignis'}
           │    │     └ ()
           │    └ <function BaseCommand.main at 0x7f6966f09620><OrderedGroup cli>

  File "/nix/store/6k64nlqhg20cky326qhh6282z6zkpr5s-python3.12-click-8.1.7/lib/python3.12/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         │    │      └ <click.core.Context object at 0x7f696a906c90>
         │    └ <function MultiCommand.invoke at 0x7f6966f0a840><OrderedGroup cli>

  File "/nix/store/6k64nlqhg20cky326qhh6282z6zkpr5s-python3.12-click-8.1.7/lib/python3.12/site-packages/click/core.py", line 1688, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
           │               │       │       │      └ <click.core.Context object at 0x7f6969711850>
           │               │       │       └ <function Command.invoke at 0x7f6966f0a200>
           │               │       └ <Command init>
           │               └ <click.core.Context object at 0x7f6969711850><function MultiCommand.invoke.<locals>._process_result at 0x7f6969077d80>

  File "/nix/store/6k64nlqhg20cky326qhh6282z6zkpr5s-python3.12-click-8.1.7/lib/python3.12/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           │   │      │    │           │   └ {'config': '/home/artem/.config/ignis/config.py', 'debug': False}
           │   │      │    │           └ <click.core.Context object at 0x7f6969711850>
           │   │      │    └ <function init at 0x7f6966265440>
           │   │      └ <Command init>
           │   └ <function Context.invoke at 0x7f6966f08b80>
           └ <click.core.Context object at 0x7f6969711850>

  File "/nix/store/6k64nlqhg20cky326qhh6282z6zkpr5s-python3.12-click-8.1.7/lib/python3.12/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
                       │       └ {'config': '/home/artem/.config/ignis/config.py', 'debug': False}
                       └ ()

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/cli.py", line 91, in init
    run_app(config_path, debug)
    │       │            └ False
    │       └ '/home/artem/.config/ignis/config.py'
    └ <function run_app at 0x7f6966265bc0>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/app.py", line 588, in run_app
    app.run(None)
    │   └ <function Application.run at 0x7f6966f12ca0>
    └ <app.IgnisApp object at 0x7f69661445c0 (ignis+app+IgnisApp at 0x1462f710)>

  File "/nix/store/m9y1ffs5jyvra1zc95spdgyxcg852wv1-python3.12-pygobject-3.50.0/lib/python3.12/site-packages/gi/overrides/Gio.py", line 42, in run
    return Gio.Application.run(self, *args, **kwargs)
           │   │           │   │      │       └ {}
           │   │           │   │      └ (None,)
           │   │           │   └ <app.IgnisApp object at 0x7f69661445c0 (ignis+app+IgnisApp at 0x1462f710)>
           │   │           └ gi.FunctionInfo(run, bound=None)
           │   └ <class 'gi.repository.Gio.Application'>
           └ <IntrospectionModule 'Gio' from '/nix/store/w1nz8qqc1l0dk6af9s36zchba3hm04ry-glib-2.82.4/lib/girepository-1.0/Gio-2.0.typelib'>

> File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/app.py", line 417, in do_activate
    __import__(config_filename)
               └ 'config'

  File "/home/artem/.config/ignis/config.py", line 175, in <module>
    bar(i)
    │   └ 0
    └ <function bar at 0x7f694fd77a60>

  File "/home/artem/.config/ignis/config.py", line 166, in bar
    start_widget=left(monitor_name),  # type: ignore
                 │    └ 'eDP-1'
                 └ <function left at 0x7f694fd77880>

  File "/home/artem/.config/ignis/config.py", line 133, in left
    workspaces(monitor_name),
    │          └ 'eDP-1'
    └ <function workspaces at 0x7f694fd77560>

  File "/home/artem/.config/ignis/config.py", line 72, in workspaces
    return hyprland_workspaces()
           └ <function hyprland_workspaces at 0x7f694fd774c0>

  File "/home/artem/.config/ignis/config.py", line 58, in hyprland_workspaces
    return Widget.EventBox(
           │      └ <class 'ignis.widgets.eventbox.EventBox'>
           └ <class 'ignis.widgets.Widget'>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/widgets/eventbox.py", line 58, in __init__
    super().__init__(**kwargs)
                       └ {'on_scroll_up': <function hyprland_workspaces.<locals>.<lambda> at 0x7f694fd77ba0>, 'on_scroll_down': <function hyprland_wor...

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/widgets/box.py", line 37, in __init__
    BaseWidget.__init__(self, **kwargs)
    │          │        │       └ {'on_scroll_up': <function hyprland_workspaces.<locals>.<lambda> at 0x7f694fd77ba0>, 'on_scroll_down': <function hyprland_wor...
    │          │        └ <eventbox.EventBox object at 0x7f694fded740 (IgnisEventBox at 0x14ca74a0)>
    │          └ <function BaseWidget.__init__ at 0x7f696613e5c0>
    └ <class 'ignis.base_widget.BaseWidget'>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/base_widget.py", line 52, in __init__
    IgnisGObject.__init__(self, **kwargs)
    │            │        │       └ {'on_scroll_up': <function hyprland_workspaces.<locals>.<lambda> at 0x7f694fd77ba0>, 'on_scroll_down': <function hyprland_wor...
    │            │        └ <eventbox.EventBox object at 0x7f694fded740 (IgnisEventBox at 0x14ca74a0)>
    │            └ <function IgnisGObject.__init__ at 0x7f6966f49e40>
    └ <class 'ignis.gobject.IgnisGObject'>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/gobject.py", line 67, in __init__
    self.set_property(key, kwargs[key])
    │    │            │    │      └ 'child'
    │    │            │    └ {'on_scroll_up': <function hyprland_workspaces.<locals>.<lambda> at 0x7f694fd77ba0>, 'on_scroll_down': <function hyprland_wor...
    │    │            └ 'child'
    │    └ <function BaseWidget.set_property at 0x7f696613e200>
    └ <eventbox.EventBox object at 0x7f694fded740 (IgnisEventBox at 0x14ca74a0)>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/base_widget.py", line 119, in set_property
    super().set_property(property_name, value)
                         │              └ <gobject.Binding object at 0x7f694fdd7f40 (ignis+gobject+Binding at 0x14657de0)>
                         └ 'child'

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/gobject.py", line 109, in set_property
    self.bind_property2(
    │    └ <function IgnisGObject.bind_property2 at 0x7f6966f4a200>
    └ <eventbox.EventBox object at 0x7f694fded740 (IgnisEventBox at 0x14ca74a0)>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/gobject.py", line 153, in bind_property2
    callback()
    └ <function IgnisGObject.bind_property2.<locals>.callback at 0x7f694fd77ec0>

  File "/nix/store/x1k820yvh6y3lj5zqkmflddsalr7y53b-ignis-0.4.dev0+date=20250301_0c29504/lib/python3.12/site-packages/ignis/gobject.py", line 142, in callback
    value = transform(*values)
            │          └ [[<workspace.HyprlandWorkspace object at 0x7f694fdd6dc0 (ignis+services+hyprland+workspace+HyprlandWorkspace at 0x14c9aeb0)>,...
            └ <function hyprland_workspaces.<locals>.<lambda> at 0x7f694fd77e20>

  File "/home/artem/.config/ignis/config.py", line 65, in <lambda>
    transform=lambda value: [workspace_button(i) for i in value],
                     │       │                │      │    └ [<workspace.HyprlandWorkspace object at 0x7f694fdd6dc0 (ignis+services+hyprland+workspace+HyprlandWorkspace at 0x14c9aeb0)>, ...
                     │       │                │      └ 0
                     │       │                └ 0
                     │       └ <function workspace_button at 0x7f694fd772e0>
                     └ [<workspace.HyprlandWorkspace object at 0x7f694fdd6dc0 (ignis+services+hyprland+workspace+HyprlandWorkspace at 0x14c9aeb0)&
8000
gt;, ...

  File "/home/artem/.config/ignis/config.py", line 33, in workspace_button
    return hyprland_workspace_button(workspace)
           │                         └ <workspace.HyprlandWorkspace object at 0x7f694fdd6dc0 (ignis+services+hyprland+workspace+HyprlandWorkspace at 0x14c9aeb0)>
           └ <function hyprland_workspace_button at 0x7f694fd771a0>

  File "/home/artem/.config/ignis/config.py", line 20, in hyprland_workspace_button
    on_click=lambda x, id=workspace["id"]: hyprland.switch_to_workspace(id),
                          │                │        └ <function HyprlandService.switch_to_workspace at 0x7f694fd76520>
                          │                └ <service.HyprlandService object at 0x7f696907c2c0 (ignis+services+hyprland+service+HyprlandService at 0x14c9a5c0)>
                          └ <workspace.HyprlandWorkspace object at 0x7f694fdd6dc0 (ignis+services+hyprland+workspace+HyprlandWorkspace at 0x14c9aeb0)>

<\details>

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 1, 2025

Yes, the last commit fixed an issue, but now I have this:

Because workspaces are not dictionaries anymore, see migration guide or example bar (I updated it right now)

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 7, 2025

@ArtemChandragupta any updates on this?

@ArtemChandragupta
Copy link

Hi. Sorry for latency.

I modified my initial config in a way described in new example bar configuration, it worked. After that I built ignis from ignis.url = "github:linkfrg/ignis/feat/hyprland-renameworkspace-sync"; and got the error:

raceback (most recent call last):
  File "/nix/store/66q09s7xshz9j6ik84lci6xz3xfdyla4-ignis-0.4.dev0+date=20250228_220f78a/bin/.ignis-wrapped", line 4, in <module>
    from ignis.main import main
  File "/nix/store/66q09s7xshz9j6ik84lci6xz3xfdyla4-ignis-0.4.dev0+date=20250228_220f78a/lib/python3.12/site-packages/ignis/__init__.py", line 6, in <module>
    from gi.events import GLibEventLoopPolicy  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ModuleNotFoundError: No module named 'gi.events'

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 8, 2025

After that I built ignis from ignis.url = "github:linkfrg/ignis/feat/hyprland-renameworkspace-sync"; and got the error:

Oops, I forgot to merge changes from the main so flake.lock in this branch remained old.
Can you try now?

@ArtemChandragupta
Copy link

Seems that it has strange behavior

2025-03-08-183333-record_sKZp1IPc.mp4

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 8, 2025 8000

Seems that it has strange behavior
2025-03-08-183333-record_sKZp1IPc.mp4

I cannot reproduce this using the example bar

@ArtemChandragupta
Copy link

Yes, it works for me also. I will find error in my configuration

@ArtemChandragupta
Copy link

I installed hyprland-autoname-workspaces, and changed workspace button label to name instead of id. There is a bug - if you come to empty workspace, the widget is broken. Other widgets in panel works. Waybar with hyprland-autoname-workspaces do not have a bug.

Also, what do you think about copying waybar's way to name workspaces to ditch dependencies such as hyprland-autoname-workspaces?

2025-03-08-193507-record_YJ7HWpFg.mp4

@linkfrg
Copy link
Owner Author
8000 linkfrg commented Mar 8, 2025

I installed hyprland-autoname-workspaces, and changed workspace button label to name instead of id. There is a bug - if you come to empty workspace, the widget is broken. Other widgets in panel works. Waybar with hyprland-autoname-workspaces do not have a bug.

Hmm, can you try now?

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 8, 2025

Also, what do you think about copying waybar's way to name workspaces to ditch dependencies such as hyprland-autoname-workspaces?

I'm a little out of the loop, what you mean by waybar's way?

@ArtemChandragupta
Copy link

Hmm, can you try now?

Yes, it works now.

Waybar implements workspace autonaming in hyprland itself based on workspaces clients

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 9, 2025

Waybar implements workspace autonaming in hyprland itself based on workspaces clients

I guess it can be implemented by an user since HyprlandWindow have workspace_id property

@linkfrg linkfrg merged commit e856218 into main Mar 9, 2025
3 checks passed
@linkfrg linkfrg deleted the feat/hyprland-renameworkspace-sync branch March 9, 2025 13:23
@ArtemChandragupta
Copy link

Waybar implements workspace autonaming in hyprland itself based on workspaces clients

I guess it can be implemented by an user since HyprlandWindow have workspace_id property

I talk about window rewrite rules in waybar, to implement it you need client classes on a workspace, not a workspace id. Or you talk about calling hyprctl clients externally?

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 10, 2025

I talk about window rewrite rules in waybar, to implement it you need client classes on a workspace, not a workspace id. Or you talk about calling hyprctl clients externally?

Oh, wait, I thought I added windows to the HyprlandService but I didn't.
Anyway, yes, we can implement HyprlandService.windows property and some function like HyprlandService.get_windows_on_workspace(workspace_id: int) -> list[HyprlandWindow], and then, user can get each window title/class by using HyprlandWindow.

But there is problem: there are can be multiple windows on a workspace, which one should we use?

@ArtemChandragupta
Copy link

This is waybar with window rewrite. I have two windows on a workspace - yazi and firefox, and in waybar I have icons of both of them. The thing is to name a workspace with all windows on it, not to choose specific one.

image

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 10, 2025

This is waybar with window rewrite. I have two windows on a workspace - yazi and firefox, and in waybar I have icons of both of them. The thing is to name a workspace with all windows on it, not to choose specific one.

Got it. So, adding HyprlandService.windows and HyprlandService.get_windows_on_workspace() should be enough to implement this.
Hyprland Service shouldn't automatically rename workspaces, I think It's better to leave it to the user, e.g., something like this (concept):

from ignis.widgets import Widget
from ignis.utils import Utils
from ignis.services.hyprland import HyprlandService

hyprland = HyprlandService.get_default()

Widget.Box(
    child=[
        Widget.Icon(
            icon_name=Utils.get_app_icon_name(window.class_name)
        )
        for window in hyprland.get_windows_on_workspace(1)  # 1st workspace as example
    ]
)

@linkfrg
Copy link
Owner Author
linkfrg commented Mar 22, 2025

d456b5d adds HyprlandService.get_windows_on_workspace().

2025-03-22_20-24-01.mp4

The code block used in the video:

child=Widget.Box(
    child=hyprland.bind(
        "windows",
        lambda _: [
            Widget.Icon(icon_name=Utils.get_app_icon_name(window.class_name))
            for window in hyprland.get_windows_on_workspace(workspace_id=workspace.id)
        ],
    )
)

@ArtemChandragupta
Copy link
ArtemChandragupta commented Mar 22, 2025

Very interesting!

image

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.

How to bind Hyprland workspace name?
2 participants
0