diff --git a/modules/panel/components/indicators.py b/modules/panel/components/indicators.py index 5cad4ea..4a46eb6 100644 --- a/modules/panel/components/indicators.py +++ b/modules/panel/components/indicators.py @@ -341,6 +341,6 @@ class BatteryIndicator(Box): # Update icon and tooltip self.battery_icon.set_from_file( - get_relative_path(f"../../../config/assets/icons/battery/{icon_file}") + get_relative_path(f"../../../config/assets/icons/{icon_file}") ) self.battery_button.set_tooltip_text(tooltip) diff --git a/modules/panel/components/menubar.py b/modules/panel/components/menubar.py index 4275287..8a2f51e 100644 --- a/modules/panel/components/menubar.py +++ b/modules/panel/components/menubar.py @@ -62,17 +62,22 @@ class AppName: return desktop_file def format_app_name(self, title, wmclass, update=False): - name = wmclass - if name == "": - name = title + # Handle case when both title and wmclass are empty (no active window) + if not title and not wmclass: + name = "Hyprland" + else: + name = wmclass + if name == "": + name = title - # Try to get the proper app name from desktop file - name = self.get_app_name(wmclass=wmclass) + # Try to get the proper app name from desktop file only if wmclass is not empty + if wmclass: + name = self.get_app_name(wmclass=wmclass) - # Smart title formatting (capitalize first letter) - name = str(name).title() - if "." in name: - name = name.split(".")[-1] + # Smart title formatting (capitalize first letter) + name = str(name).title() + if "." in name: + name = name.split(".")[-1] if update: modus_service.current_active_app_name = name @@ -382,8 +387,22 @@ class MenuBar(Box): # Create the dropdown system self.dropdown_system = MenuBarDropdowns(parent=parent_window) + # Create combined workspace and app label + self.workspace_label = Label( + label=f"{modus_service.current_workspace} -", + name="workspace-name", + style_classes="workspace-label", + ) + + # Connect to workspace changes + modus_service.connect( + "current-workspace-changed", + lambda _, value: self.workspace_label.set_label(f"{value} -"), + ) + # Add all the menu buttons to the menubar self.children = [ + self.workspace_label, self.dropdown_system.global_menu_button_title, self.dropdown_system.global_menu_button_file, self.dropdown_system.global_menu_button_edit, diff --git a/services/modus.py b/services/modus.py index 5b5d7e0..9e9ada8 100644 --- a/services/modus.py +++ b/services/modus.py @@ -1,8 +1,10 @@ +import json from typing import List from loguru import logger from fabric.core.service import Property, Service, Signal +from fabric.hyprland.service import Hyprland from fabric.notifications import Notification from services.custom_notification import CustomNotifications @@ -30,6 +32,9 @@ class ModusService(Service): @Signal def current_active_app_name_changed(self, value: str) -> None: ... + @Signal + def current_workspace_changed(self, value: str) -> None: ... + @Signal def music_changed(self, value: str) -> None: ... @@ -58,6 +63,10 @@ class ModusService(Service): def current_active_app_name(self) -> str: return self._current_active_app_name + @Property(str, flags="read-write") + def current_workspace(self) -> str: + return self._current_workspace + @Property(str, flags="read-write") def bluetooth(self) -> str: return self._bluetooth @@ -78,7 +87,7 @@ class ModusService(Service): def dock_apps(self) -> str: return self._dock_apps - @Property(str, flags="read-write") + @Property(bool, flags="read-write", default_value=False) def dont_disturb(self) -> bool: return self._dont_disturb @@ -116,6 +125,12 @@ class ModusService(Service): self._current_active_app_name = value self.current_active_app_name_changed(value) + @current_workspace.setter + def current_workspace(self, value: str): + if value != self._current_workspace: + self._current_workspace = value + self.current_workspace_changed(value) + @volume.setter def volume(self, value: int): if value != self._volume: @@ -216,7 +231,8 @@ class ModusService(Service): self._bluetooth = "" self._dock_apps = "" self._dont_disturb = False - self._current_active_app_name = "" + self._current_active_app_name = "Hyprland" + self._current_workspace = "1" self._music = "" self._current_dropdown = None self._dropdowns_hide = False @@ -226,6 +242,33 @@ class ModusService(Service): self._dock_width = 0 self._dock_height = 0 + # Initialize Hyprland connection for workspace monitoring + self._setup_workspace_monitoring() + + def _setup_workspace_monitoring(self): + """Setup Hyprland connection and workspace monitoring""" + try: + self._hyprland_connection = Hyprland() + + # Get initial workspace + workspace_data = self._hyprland_connection.send_command("j/activeworkspace").reply + active_workspace = json.loads(workspace_data.decode("utf-8"))["name"] + self._current_workspace = str(active_workspace) + + # Connect to workspace change events + self._hyprland_connection.connect("event::workspace", self._on_workspace_changed) + + except Exception as e: + logger.error(f"[ModusService] Failed to setup workspace monitoring: {e}") + self._current_workspace = "1" + + def _on_workspace_changed(self, obj, signal): + """Handle workspace change events from Hyprland""" + try: + workspace_name = json.loads(signal.data[0]) + self.current_workspace = str(workspace_name) + except Exception as e: + logger.error(f"[ModusService] Error processing workspace change: {e}") def remove_notification(self, id: int): notification_service.remove_notification(id) @@ -255,4 +298,4 @@ global modus_service try: modus_service = ModusService() except Exception as e: - logger.error("[Main] Failed to create EnvShellService:", e) + logger.error("[Main] Failed to create ModusShellService:", e)