♻️ refactor(dock,workspace,switcher): centralize special workspace detection logic
This commit is contained in:
6 files changed
+227
-199
No files matched your search
+107
-114
@@ -16,7 +16,7 @@ from loguru import logger
|
||||
|
||||
import config.data as data
|
||||
from services.modus import modus_service
|
||||
from utils.functions import read_json_file, write_json_file
|
||||
from utils.functions import read_json_file, write_json_file, is_special_workspace_id
|
||||
from utils.icon_resolver import IconResolver
|
||||
from utils.occlusion import check_occlusion
|
||||
from widgets.wayland import WaylandWindow as Window
|
||||
@@ -40,7 +40,7 @@ class AppBar(Box):
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
spacing=10,
|
||||
spacing=0,
|
||||
name="dock",
|
||||
orientation=orientation,
|
||||
children=[],
|
||||
@@ -74,7 +74,7 @@ class AppBar(Box):
|
||||
logger.error(f"[AppBar] Error updating apps: {e}")
|
||||
return True
|
||||
|
||||
GLib.timeout_add(1000, update_running_apps)
|
||||
GLib.timeout_add(100, update_running_apps)
|
||||
GLib.idle_add(self.update_dock_apps)
|
||||
|
||||
def _populate_pinned_apps(self):
|
||||
@@ -486,42 +486,42 @@ class AppBar(Box):
|
||||
return None
|
||||
|
||||
def update_dock_apps(self):
|
||||
clients = self.get_clients()
|
||||
focused_window = self.get_focused_window()
|
||||
focused_address = focused_window.get("address", "") if focused_window else ""
|
||||
try:
|
||||
clients = self.get_clients()
|
||||
focused_window = self.get_focused_window()
|
||||
focused_address = focused_window.get("address", "") if focused_window else ""
|
||||
|
||||
current_instance_ids = set()
|
||||
current_instance_ids = set()
|
||||
|
||||
for client in clients:
|
||||
if client.get("hidden", False):
|
||||
continue
|
||||
for client in clients:
|
||||
if client.get("hidden", False) or not self._should_show_app_instance(client):
|
||||
continue
|
||||
|
||||
# Skip apps in special workspaces if configured to hide them
|
||||
if not self._should_show_app_instance(client):
|
||||
continue
|
||||
instance_address = client.get("address", "")
|
||||
app_class = client.get("class", "") or client.get("title", "")
|
||||
if not instance_address or not app_class:
|
||||
continue
|
||||
|
||||
instance_address = client.get("address", "")
|
||||
if not instance_address:
|
||||
continue
|
||||
current_instance_ids.add(instance_address)
|
||||
|
||||
current_instance_ids.add(instance_address)
|
||||
app_class = client.get("class", "") or client.get("title", "unknown-app")
|
||||
if instance_address not in self.client_buttons:
|
||||
self.create_instance_button(instance_address, client, app_class)
|
||||
else:
|
||||
self.update_instance_button(instance_address, client, app_class)
|
||||
|
||||
if instance_address not in self.client_buttons:
|
||||
self.create_instance_button(instance_address, client, app_class)
|
||||
else:
|
||||
self.update_instance_button(instance_address, client, app_class)
|
||||
button = self.client_buttons[instance_address]
|
||||
if instance_address == focused_address:
|
||||
button.add_style_class("activated")
|
||||
else:
|
||||
button.remove_style_class("activated")
|
||||
|
||||
button = self.client_buttons[instance_address]
|
||||
if instance_address == focused_address:
|
||||
button.add_style_class("activated")
|
||||
else:
|
||||
button.remove_style_class("activated")
|
||||
self._update_pinned_apps_state(clients)
|
||||
self._update_separator_visibility()
|
||||
|
||||
self._update_pinned_apps_state(clients)
|
||||
self._update_separator_visibility()
|
||||
|
||||
self._cleanup_removed_instances(current_instance_ids)
|
||||
self._cleanup_removed_instances(current_instance_ids)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[AppBar] Error in update_dock_apps: {e}")
|
||||
|
||||
def _update_pinned_apps_state(self, clients):
|
||||
running_app_classes = {
|
||||
@@ -549,91 +549,93 @@ class AppBar(Box):
|
||||
if instance_id not in current_instance_ids
|
||||
]
|
||||
|
||||
for instance_id in buttons_to_remove:
|
||||
button = self.client_buttons.pop(instance_id)
|
||||
try:
|
||||
if button in self.running_items_pos:
|
||||
self.running_items_pos.remove(button)
|
||||
button.remove_style_class("shown")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def remove_later():
|
||||
# Clean up removed and orphaned buttons
|
||||
for instance_id in buttons_to_remove + [k for k, v in self.client_buttons.items()
|
||||
if not hasattr(v, 'instance_address') or not v.get_parent()]:
|
||||
if instance_id in self.client_buttons:
|
||||
button = self.client_buttons.pop(instance_id)
|
||||
try:
|
||||
self.running_apps_container.remove(button)
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
GLib.timeout_add(250, remove_later)
|
||||
if button in self.running_items_pos:
|
||||
self.running_items_pos.remove(button)
|
||||
button.remove_style_class("shown")
|
||||
button.remove_style_class("activated")
|
||||
if button.get_parent():
|
||||
button.get_parent().remove(button)
|
||||
button.destroy()
|
||||
except Exception as e:
|
||||
logger.warning(f"[AppBar] Error during cleanup: {e}")
|
||||
|
||||
def create_instance_button(self, instance_address, client, app_class):
|
||||
client_image = Image(name="dock_item_icon")
|
||||
|
||||
try:
|
||||
desktop_apps = get_desktop_applications(include_hidden=False)
|
||||
desktop_app = self._find_desktop_app_by_id(app_class, desktop_apps)
|
||||
client_image = Image(name="dock_item_icon")
|
||||
|
||||
if desktop_app:
|
||||
pixbuf = desktop_app.get_icon_pixbuf(data.DOCK_ICON_SIZE)
|
||||
else:
|
||||
pixbuf = self.icon_resolver.get_icon_pixbuf(
|
||||
app_class, data.DOCK_ICON_SIZE
|
||||
try:
|
||||
desktop_apps = get_desktop_applications(include_hidden=False)
|
||||
desktop_app = self._find_desktop_app_by_id(app_class, desktop_apps)
|
||||
|
||||
if desktop_app:
|
||||
pixbuf = desktop_app.get_icon_pixbuf(data.DOCK_ICON_SIZE)
|
||||
else:
|
||||
pixbuf = self.icon_resolver.get_icon_pixbuf(
|
||||
app_class, data.DOCK_ICON_SIZE
|
||||
)
|
||||
|
||||
client_image.set_from_pixbuf(pixbuf)
|
||||
except Exception as e:
|
||||
logger.warning(f"[AppBar] Could not load icon for {app_class}: {e}")
|
||||
|
||||
workspace_id = self._get_workspace_id(client)
|
||||
workspace_label = None
|
||||
if workspace_id is not None:
|
||||
workspace_label = Label(
|
||||
label=str(workspace_id),
|
||||
name="workspace-indicator",
|
||||
h_align="end",
|
||||
v_align="end",
|
||||
)
|
||||
|
||||
client_image.set_from_pixbuf(pixbuf)
|
||||
except Exception as e:
|
||||
logger.warning(f"[AppBar] Could not load icon for {app_class}: {e}")
|
||||
image_overlay = Overlay(name="dock-image-overlay", child=client_image)
|
||||
if workspace_label:
|
||||
image_overlay.add_overlay(workspace_label)
|
||||
|
||||
workspace_id = self._get_workspace_id(client)
|
||||
workspace_label = None
|
||||
if workspace_id is not None:
|
||||
workspace_label = Label(
|
||||
label=str(workspace_id),
|
||||
name="workspace-indicator",
|
||||
h_align="end",
|
||||
v_align="end",
|
||||
indicator = Box(name="dock_item_indicator", h_align="center")
|
||||
main_container = Box(
|
||||
name="dock_item_main_container",
|
||||
orientation="v",
|
||||
children=[image_overlay, indicator],
|
||||
)
|
||||
|
||||
image_overlay = Overlay(name="dock-image-overlay", child=client_image)
|
||||
if workspace_label:
|
||||
image_overlay.add_overlay(workspace_label)
|
||||
tooltip_text = client.get("title", app_class)
|
||||
if tooltip_text != app_class:
|
||||
tooltip_text = f"{app_class}: {tooltip_text}"
|
||||
|
||||
indicator = Box(name="dock_item_indicator", h_align="center")
|
||||
main_container = Box(
|
||||
name="dock_item_main_container",
|
||||
orientation="v",
|
||||
children=[image_overlay, indicator],
|
||||
)
|
||||
client_button = Button(
|
||||
name="dock_item",
|
||||
child=main_container,
|
||||
tooltip_text=tooltip_text,
|
||||
on_button_press_event=lambda widget, event: self.handle_instance_click(
|
||||
widget, event
|
||||
),
|
||||
on_enter_notify_event=lambda *_: self._handle_item_hovered(
|
||||
client_button, False
|
||||
),
|
||||
on_leave_notify_event=lambda *_: self._handle_item_unhovered(
|
||||
client_button, False
|
||||
),
|
||||
)
|
||||
|
||||
tooltip_text = client.get("title", app_class)
|
||||
if tooltip_text != app_class:
|
||||
tooltip_text = f"{app_class}: {tooltip_text}"
|
||||
client_button.instance_address = instance_address
|
||||
client_button.client_data = client
|
||||
client_button.app_class = app_class
|
||||
client_button.workspace_label = workspace_label
|
||||
client_button.add_style_class("shown")
|
||||
|
||||
client_button = Button(
|
||||
name="dock_item",
|
||||
child=main_container,
|
||||
tooltip_text=tooltip_text,
|
||||
on_button_press_event=lambda widget, event: self.handle_instance_click(
|
||||
widget, event
|
||||
),
|
||||
on_enter_notify_event=lambda *_: self._handle_item_hovered(
|
||||
client_button, False
|
||||
),
|
||||
on_leave_notify_event=lambda *_: self._handle_item_unhovered(
|
||||
client_button, False
|
||||
),
|
||||
)
|
||||
|
||||
client_button.instance_address = instance_address
|
||||
client_button.client_data = client
|
||||
client_button.app_class = app_class
|
||||
client_button.workspace_label = workspace_label
|
||||
client_button.add_style_class("shown")
|
||||
|
||||
self.client_buttons[instance_address] = client_button
|
||||
self.running_apps_container.add(client_button)
|
||||
self.running_items_pos.append(client_button)
|
||||
self.client_buttons[instance_address] = client_button
|
||||
self.running_apps_container.add(client_button)
|
||||
self.running_items_pos.append(client_button)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"[AppBar] Error creating instance button for {app_class}: {e}")
|
||||
|
||||
def _get_workspace_id(self, client):
|
||||
workspace_data = client.get("workspace", {})
|
||||
@@ -644,16 +646,7 @@ class AppBar(Box):
|
||||
return None
|
||||
|
||||
def _is_special_workspace_id(self, ws_id):
|
||||
try:
|
||||
# Convert to int if it's a string
|
||||
workspace_id = int(ws_id)
|
||||
# Special workspaces have negative IDs
|
||||
return workspace_id < 0
|
||||
except (ValueError, TypeError):
|
||||
# If it's a string, check if it starts with "special:"
|
||||
if isinstance(ws_id, str) and ws_id.startswith("special:"):
|
||||
return True
|
||||
return False
|
||||
return is_special_workspace_id(ws_id)
|
||||
|
||||
def _should_show_app_instance(self, client):
|
||||
if not data.DOCK_HIDE_SPECIAL_WORKSPACE_APPS:
|
||||
@@ -844,4 +837,4 @@ class Dock(Window):
|
||||
|
||||
return True
|
||||
|
||||
GLib.timeout_add(250, check_dock_occlusion)
|
||||
GLib.timeout_add(100, check_dock_occlusion)
|
||||
@@ -1,6 +1,7 @@
|
||||
from fabric.hyprland.widgets import HyprlandWorkspaces, WorkspaceButton
|
||||
from fabric.widgets.box import Box
|
||||
import config.data as data
|
||||
from utils.functions import is_special_workspace_id
|
||||
|
||||
# TODO: Support Multi Monitor
|
||||
|
||||
@@ -31,22 +32,13 @@ class WorkspaceIndicator(Box):
|
||||
self.show_all()
|
||||
|
||||
def _is_special_workspace_id(self, ws_id):
|
||||
"""Check if a workspace ID represents a special workspace"""
|
||||
try:
|
||||
# Convert to int if it's a string
|
||||
workspace_id = int(ws_id)
|
||||
# Special workspaces have negative IDs
|
||||
return workspace_id < 0
|
||||
except (ValueError, TypeError):
|
||||
# If it's a string, check if it starts with "special:"
|
||||
if isinstance(ws_id, str) and ws_id.startswith("special:"):
|
||||
return True
|
||||
return False
|
||||
return is_special_workspace_id(ws_id)
|
||||
|
||||
def _create_filtered_button(self, ws_id):
|
||||
"""Create workspace button only if it should be shown"""
|
||||
if data.HIDE_SPECIAL_WORKSPACE and self._is_special_workspace_id(ws_id):
|
||||
# Return None or an empty widget to hide special workspaces
|
||||
return None
|
||||
|
||||
return WorkspaceButton(id=ws_id, label=str(ws_id))
|
||||
|
||||
|
||||
+2
-18
@@ -11,6 +11,7 @@ from fabric.widgets.image import Image
|
||||
from fabric.widgets.label import Label
|
||||
from utils.icon_resolver import IconResolver
|
||||
from utils.occlusion import get_screen_dimensions
|
||||
from utils.functions import is_special_workspace
|
||||
from widgets.wayland import WaylandWindow as Window
|
||||
|
||||
gi.require_version("Glace", "0.1")
|
||||
@@ -193,24 +194,7 @@ class ApplicationSwitcher(Window):
|
||||
image_widget.set_from_pixbuf(icon_img)
|
||||
|
||||
def _is_special_workspace(self, client):
|
||||
"""Check if a client is in a special workspace"""
|
||||
if "workspace" not in client:
|
||||
return False
|
||||
|
||||
workspace = client["workspace"]
|
||||
if "name" in workspace:
|
||||
workspace_name = str(workspace["name"])
|
||||
# Special workspaces typically start with "special:" or have negative IDs
|
||||
if workspace_name.startswith("special:"):
|
||||
return True
|
||||
|
||||
if "id" in workspace:
|
||||
workspace_id = workspace["id"]
|
||||
# Special workspaces have negative IDs
|
||||
if workspace_id < 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
return is_special_workspace(client)
|
||||
|
||||
def update_windows(self) -> None:
|
||||
for child in self.view.get_children():
|
||||
|
||||
+24
-24
@@ -1,12 +1,11 @@
|
||||
# Standard library imports
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# Fabric imports
|
||||
from fabric.core.service import Property, Service, Signal
|
||||
# Fabric imports
|
||||
from fabric.core.service import Property, Service
|
||||
|
||||
# Local imports
|
||||
import config.data as data
|
||||
@@ -14,23 +13,23 @@ import config.data as data
|
||||
|
||||
class TodoService(Service):
|
||||
"""Service for managing persistent todo list with JSON storage"""
|
||||
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._todos = []
|
||||
self._file_path = self._get_todos_file_path()
|
||||
self._load_todos()
|
||||
self._callbacks = []
|
||||
|
||||
|
||||
def add_callback(self, callback):
|
||||
"""Add a callback function to be notified of changes"""
|
||||
self._callbacks.append(callback)
|
||||
|
||||
|
||||
def remove_callback(self, callback):
|
||||
"""Remove a callback function"""
|
||||
if callback in self._callbacks:
|
||||
self._callbacks.remove(callback)
|
||||
|
||||
|
||||
def _notify_callbacks(self, event_type, data=None):
|
||||
"""Notify all registered callbacks of changes"""
|
||||
for callback in self._callbacks:
|
||||
@@ -38,13 +37,13 @@ class TodoService(Service):
|
||||
callback(event_type, data)
|
||||
except Exception as e:
|
||||
print(f"Error in todo callback: {e}")
|
||||
|
||||
|
||||
def _get_todos_file_path(self):
|
||||
"""Returns the path to the todos JSON file"""
|
||||
cache_dir = Path(data.CACHE_DIR) / "todos"
|
||||
cache_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cache_dir / "todos.json"
|
||||
|
||||
|
||||
def _load_todos(self):
|
||||
"""Load todos from JSON file"""
|
||||
try:
|
||||
@@ -56,7 +55,7 @@ class TodoService(Service):
|
||||
except Exception as e:
|
||||
print(f"Error loading todos: {e}")
|
||||
self._todos = []
|
||||
|
||||
|
||||
def _save_todos(self):
|
||||
"""Save todos to JSON file"""
|
||||
try:
|
||||
@@ -64,12 +63,12 @@ class TodoService(Service):
|
||||
json.dump(self._todos, f, indent=2, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
print(f"Error saving todos: {e}")
|
||||
|
||||
|
||||
@Property(list, "readable")
|
||||
def todos(self):
|
||||
"""Get all todos"""
|
||||
return self._todos.copy()
|
||||
|
||||
|
||||
def add_todo(self, text: str, priority: str = "medium") -> dict:
|
||||
"""Add a new todo item"""
|
||||
todo = {
|
||||
@@ -78,14 +77,14 @@ class TodoService(Service):
|
||||
"completed": False,
|
||||
"priority": priority, # low, medium, high
|
||||
"created_at": datetime.now().isoformat(),
|
||||
"updated_at": datetime.now().isoformat()
|
||||
"updated_at": datetime.now().isoformat(),
|
||||
}
|
||||
self._todos.append(todo)
|
||||
self._save_todos()
|
||||
self._notify_callbacks("todo-added", todo)
|
||||
self._notify_callbacks("todos-changed")
|
||||
return todo
|
||||
|
||||
|
||||
def delete_todo(self, todo_id: str) -> bool:
|
||||
"""Delete a todo item by ID"""
|
||||
for i, todo in enumerate(self._todos):
|
||||
@@ -96,7 +95,7 @@ class TodoService(Service):
|
||||
self._notify_callbacks("todos-changed")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def toggle_todo(self, todo_id: str) -> bool:
|
||||
"""Toggle completion status of a todo item"""
|
||||
for todo in self._todos:
|
||||
@@ -108,7 +107,7 @@ class TodoService(Service):
|
||||
self._notify_callbacks("todos-changed")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def edit_todo(self, todo_id: str, new_text: str) -> bool:
|
||||
"""Edit the text of a todo item"""
|
||||
for todo in self._todos:
|
||||
@@ -120,12 +119,12 @@ class TodoService(Service):
|
||||
self._notify_callbacks("todos-changed")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def set_priority(self, todo_id: str, priority: str) -> bool:
|
||||
"""Set the priority of a todo item"""
|
||||
if priority not in ["low", "medium", "high"]:
|
||||
return False
|
||||
|
||||
|
||||
for todo in self._todos:
|
||||
if todo["id"] == todo_id:
|
||||
todo["priority"] = priority
|
||||
@@ -135,14 +134,14 @@ class TodoService(Service):
|
||||
self._notify_callbacks("todos-changed")
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_todo(self, todo_id: str) -> dict | None:
|
||||
"""Get a specific todo by ID"""
|
||||
for todo in self._todos:
|
||||
if todo["id"] == todo_id:
|
||||
return todo.copy()
|
||||
return None
|
||||
|
||||
|
||||
def clear_completed(self):
|
||||
"""Remove all completed todos"""
|
||||
initial_count = len(self._todos)
|
||||
@@ -150,20 +149,21 @@ class TodoService(Service):
|
||||
if len(self._todos) < initial_count:
|
||||
self._save_todos()
|
||||
self._notify_callbacks("todos-changed")
|
||||
|
||||
|
||||
def get_stats(self) -> dict:
|
||||
"""Get todo statistics"""
|
||||
total = len(self._todos)
|
||||
completed = sum(1 for todo in self._todos if todo["completed"])
|
||||
pending = total - completed
|
||||
|
||||
|
||||
return {
|
||||
"total": total,
|
||||
"completed": completed,
|
||||
"pending": pending,
|
||||
"completion_rate": (completed / total * 100) if total > 0 else 0
|
||||
"completion_rate": (completed / total * 100) if total > 0 else 0,
|
||||
}
|
||||
|
||||
|
||||
# Global service instance
|
||||
todo_service = TodoService()
|
||||
todo_service = TodoService()
|
||||
|
||||
+32
-31
@@ -22,44 +22,44 @@
|
||||
#dock_item.shown.semi_hovered #dock_item_main_container {
|
||||
margin-top: -7px;
|
||||
}
|
||||
/**/
|
||||
/* #dock_item.shown.semi_hovered #dock_item_indicator { */
|
||||
/* margin-top: 11px; */
|
||||
/* } */
|
||||
|
||||
#dock_item.shown.semi_hovered #dock_item_indicator {
|
||||
margin-top: 11px;
|
||||
}
|
||||
|
||||
#dock_item.shown.activated:hover #dock_item_main_container {
|
||||
margin-top: -12px;
|
||||
}
|
||||
|
||||
#dock_item.shown.activated:hover #dock_item_indicator {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
#dock_item.shown.activated #dock_item_main_container {
|
||||
margin-top: -4px;
|
||||
}
|
||||
/* #dock_item.shown.activated:hover #dock_item_main_container { */
|
||||
/* margin-top: -12px; */
|
||||
/* } */
|
||||
/**/
|
||||
/* #dock_item.shown.activated:hover #dock_item_indicator { */
|
||||
/* margin-top: 16px; */
|
||||
/* } */
|
||||
/**/
|
||||
/* #dock_item.shown.activated #dock_item_main_container { */
|
||||
/* margin-top: -4px; */
|
||||
/* } */
|
||||
|
||||
#dock_item.shown.activated #dock_item_icon {
|
||||
opacity: 1;
|
||||
/* background-color: #01458e; */
|
||||
}
|
||||
|
||||
#dock_item.shown.activated #dock_item_indicator {
|
||||
min-width: 4px;
|
||||
margin-top: 8px;
|
||||
background-color: #aac7ff;
|
||||
}
|
||||
/* #dock_item.shown.activated #dock_item_indicator { */
|
||||
/* min-width: 4px; */
|
||||
/* margin-top: 8px; */
|
||||
/* background-color: #aac7ff; */
|
||||
/* } */
|
||||
|
||||
#dock_item_icon {
|
||||
border-radius: 13px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
#dock_item_indicator {
|
||||
transition: all 0.15s ease-out;
|
||||
min-height: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* #dock_item_indicator { */
|
||||
/* transition: all 0.15s ease-out; */
|
||||
/* min-height: 4px; */
|
||||
/* border-radius: 4px; */
|
||||
/* } */
|
||||
|
||||
#dock_item {
|
||||
transition: margin 0.2s ease-out;
|
||||
@@ -78,6 +78,7 @@
|
||||
transition: all 0.1s ease-out;
|
||||
min-width: 1.5px;
|
||||
min-height: 50px;
|
||||
margin: 0px 4px;
|
||||
border-radius: 2px;
|
||||
background-color: #2b5ea7;
|
||||
}
|
||||
@@ -88,9 +89,9 @@
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#dock_item.shown:not(.activated) {
|
||||
min-width: 0px;
|
||||
min-height: 0px;
|
||||
margin-top: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
/* #dock_item.shown:not(.activated) { */
|
||||
/* min-width: 0px; */
|
||||
/* min-height: 0px; */
|
||||
/* margin-top: 0px; */
|
||||
/* background-color: transparent; */
|
||||
/* } */
|
||||
@@ -95,3 +95,61 @@ def get_wifi_connecting_icon() -> str:
|
||||
project_root = os.path.dirname(current_dir)
|
||||
|
||||
return os.path.join(project_root, "config", "assets", "icons", "wifi", "wifi-connecting.svg")
|
||||
|
||||
|
||||
def is_special_workspace_id(ws_id) -> bool:
|
||||
"""
|
||||
Check if a workspace ID represents a special workspace.
|
||||
|
||||
Args:
|
||||
ws_id: Workspace ID (can be int, string, or other types)
|
||||
|
||||
Returns:
|
||||
True if the workspace is special, False otherwise
|
||||
"""
|
||||
try:
|
||||
# Convert to int if it's a string
|
||||
workspace_id = int(ws_id)
|
||||
# Special workspaces have negative IDs
|
||||
return workspace_id < 0
|
||||
except (ValueError, TypeError):
|
||||
# If it's a string, check if it starts with "special:"
|
||||
if isinstance(ws_id, str) and ws_id.startswith("special:"):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_special_workspace(client: dict) -> bool:
|
||||
"""
|
||||
Check if a client is in a special workspace.
|
||||
|
||||
Args:
|
||||
client: Client data dictionary from Hyprland
|
||||
|
||||
Returns:
|
||||
True if the client is in a special workspace, False otherwise
|
||||
"""
|
||||
if "workspace" not in client:
|
||||
return False
|
||||
|
||||
workspace = client["workspace"]
|
||||
|
||||
# Check workspace name first
|
||||
if "name" in workspace:
|
||||
workspace_name = str(workspace["name"])
|
||||
# Special workspaces typically start with "special:" or have negative IDs
|
||||
if workspace_name.startswith("special:"):
|
||||
return True
|
||||
|
||||
# Check workspace ID
|
||||
if "id" in workspace:
|
||||
workspace_id = workspace["id"]
|
||||
# Special workspaces have negative IDs
|
||||
if workspace_id < 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user