-
Notifications
You must be signed in to change notification settings - Fork 27
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
Conversation
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' |
@ArtemChandragupta |
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> |
Because workspaces are not dictionaries anymore, see migration guide or example bar (I updated it right now) |
@ArtemChandragupta any updates on this? |
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 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' |
Oops, I forgot to merge changes from the main so |
Seems that it has strange behavior 2025-03-08-183333-record_sKZp1IPc.mp4 |
I cannot reproduce this using the example bar |
Yes, it works for me also. I will find error in my configuration |
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 |
Hmm, can you try now? |
I'm a little out of the loop, what you mean by waybar's way? |
Yes, it works now. Waybar implements workspace autonaming in hyprland itself based on workspaces clients |
I guess it can be implemented by an user since |
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 |
Oh, wait, I thought I added But there is problem: there are can be multiple windows on a workspace, which one should we use? |
Got it. So, adding 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
]
) |
d456b5d adds 2025-03-22_20-24-01.mp4The 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)
],
)
) |
Closes: #94