♻️ refactor(dock): overhaul dock implementation for improved performance and maintainability

This commit is contained in:
sankalp committed 2025-08-07 06:08:20 +05:45
1 parent 8ba98e33d3
commit 4852fa01e2
22 files changed
+876 -2755

No files matched your search

-98
View File
@@ -1,98 +0,0 @@
from xml import etree
from xml.etree import ElementTree
from fabric.utils import get_relative_path
import json
def parse(xml):
with open(xml, "rb") as f:
tree = ElementTree.parse(f)
root = tree.getroot()
return root
def dxml(root, depth=0):
val = []
for child in root:
attrstring = {}
additional = {}
if len(child.attrib) == 0:
if child.tag == "BoxV":
additional["orientation"] = "vertical"
elif child.tag == "BoxH":
additional["orientation"] = "horizontal"
for k, v in child.attrib.items():
if v == None:
continue
if child.tag == "Ref":
continue
if child.tag == "BoxV":
additional["orientation"] = "vertical"
elif child.tag == "BoxH":
additional["orientation"] = "horizontal"
if k == "path":
# Handle path resolution more robustly
import os
# Get the directory where the XML file is located
current_dir = os.path.dirname(os.path.abspath(__file__))
# Go up to project root and then to the specified path
project_root = os.path.dirname(current_dir) # Go up from utils/
full_path = os.path.join(project_root, v)
v = full_path
k = "svg_file"
if v == "true" or v == "false":
v = v == "true"
attrstring[k] = v
for k, v in additional.items():
attrstring[k] = v
tag = child.tag
if tag in ["BoxV", "BoxH"]:
tag = "Box"
if tag == "Ref":
val.append(
{
"name": tag,
"text": child.text,
}
)
continue
val.append(
{
"name": tag,
"attributes": attrstring,
"children": dxml(child, depth + 1),
}
)
return val
def parse_child(tags, refs, child, parent):
for ch in child:
ch = ch.copy()
name = ch.get("name", None)
attrs = ch.get("attributes", None)
if attrs:
for attr in attrs:
if str(attrs[attr]).isnumeric():
attrs[attr] = int(attrs[attr])
children = ch.get("children", None)
if children:
ch.pop("children")
if name == "Ref":
text = ch.get("text", None)
v = refs[text]
parent.children = [*parent.children, v]
else:
v = tags[name](**attrs)
if children:
v.children = parse_child(tags, refs, children, v)
parent.children = [*parent.children, v]
return parent.children
def exml(file: str, tags: dict, refs: dict, root):
odi = dxml(parse(file))
di = root(children=[])
parse_child(tags, refs, odi, di)
return di
+51
View File
@@ -0,0 +1,51 @@
import json
import os
import threading
from typing import Dict, List, Optional
from loguru import logger
# Threading helper functions
def thread(target, *args, **kwargs) -> threading.Thread:
"""
Simply run the given function in a thread.
The provided args and kwargs will be passed to the function.
"""
th = threading.Thread(target=target, args=args, kwargs=kwargs, daemon=True)
th.start()
return th
def run_in_thread(func):
"""
Decorator to run the decorated function in a thread.
"""
def wrapper(*args, **kwargs):
return thread(func, *args, **kwargs)
return wrapper
@run_in_thread
def write_json_file(data: Dict, path: str):
try:
with open(path, "w") as f:
json.dump(data, f, indent=4, ensure_ascii=False)
except Exception as e:
logger.warning(f"Failed to write json: {e}")
def read_json_file(file_path: str) -> Optional[List]:
if not os.path.exists(file_path):
logger.error(f"JSON file {file_path} does not exist.")
return None
with open(file_path, "r") as file:
try:
return json.load(file)
except json.JSONDecodeError as e:
logger.error(f"Failed to read JSON file {file_path}: {e}")
return None
-234
View File
@@ -1,234 +0,0 @@
# Parameters
font_family: str = "tabler-icons"
font_weight: str = "normal"
span: str = f"<span font-family='{font_family}' font-weight='{font_weight}'>"
# Panels
apps: str = "&#xf1fd;"
dashboard: str = "&#xea87;"
chat: str = "&#xf59f;"
windows: str = "&#xefe6;"
# Bar
colorpicker: str = "&#xebe6;"
media: str = "&#xf00d;"
# Toolbox
toolbox: str = "&#xebca;"
ssfull: str = "&#xec3c;"
ssregion: str = "&#xf201;"
sswindow: str = "&#xeaea;"
screenshots: str = "&#xeb0a;"
screenrecord: str = "&#xf692;"
recordings: str = "&#xeafa;"
ocr: str = "&#xfcc3;"
gamemode: str = "&#xf026;"
gamemode_off: str = "&#xf111;"
close: str = "&#xeb55;"
# Circles
temp: str = "&#xeb38;"
disk: str = "&#xea88;"
battery: str = "&#xea38;"
memory: str = "&#xfa97;"
cpu: str = "&#xef8e;"
gpu: str = "&#xf233;"
swap: str = "&#xeb31;"
# AIchat
reload: str = "&#xf3ae;"
detach: str = "&#xea99;"
# Wallpapers
add: str = "&#xeb0b;"
sort: str = "&#xeb5a;"
circle: str = "&#xf671;"
# Chevrons
chevron_up: str = "&#xea62;"
chevron_down: str = "&#xea5f;"
chevron_left: str = "&#xea60;"
chevron_right: str = "&#xea61;"
# Power
lock: str = "&#xeae2;"
suspend: str = "&#xece7;"
logout: str = "&#xeba8;"
reboot: str = "&#xeb13;"
shutdown: str = "&#xeb0d;"
# Power Manager
power_saving: str = "&#xed4f;"
power_balanced: str = "&#xfa77;"
power_performance: str = "&#xec45;"
charging: str = "&#xefef;"
discharging: str = "&#xefe9;"
alert: str = "&#xea06;"
bat_charging: str = "&#xeeca;"
bat_discharging: str = "&#xf0a1;"
bat_low: str = "&#xff1d;"
bat_full: str = "&#xea38;"
# Applets
# Applets
wifi_0: str = "&#xeba3;"
wifi_1: str = "&#xeba4;"
wifi_2: str = "&#xeba5;"
wifi_3: str = "&#xeb52;"
world: str = "&#xeb54;"
world_off: str = "&#xf1ca;"
bluetooth: str = "&#xea37;"
night: str = "&#xeaf8;"
coffee: str = "&#xef0e;"
notifications: str = "&#xea35;"
notifications_dots: str = "&#xede3;"
wifi_off: str = "&#xecfa;"
bluetooth_off: str = "&#xeceb;"
night_off: str = "&#xf162;"
notifications_off: str = "&#xece9;"
notifications_clear: str = "&#xf814;"
download: str = "&#xea96;"
upload: str = "&#xeb47;"
# Bluetooth
bluetooth_connected: str = "&#xecea;"
bluetooth_disconnected: str = "&#xf081;"
# Player
pause: str = "&#xf690;"
play: str = "&#xf691;"
stop: str = "&#xf695;"
skip_back: str = "&#xf693;"
skip_forward: str = "&#xf694;"
prev: str = "&#xf697;"
next: str = "&#xf696;"
shuffle: str = "&#xf000;"
repeat: str = "&#xeb72;"
music: str = "&#xeafc;"
rewind_backward_5: str = "&#xfabf;"
rewind_forward_5: str = "&#xfac7;"
next_fill: str = chr(0xF04AD)
previous_fill: str = chr(0xF04AE)
# Volume
vol_off: str = "&#xf1c3;"
vol_mute: str = "&#xeb50;"
vol_medium: str = "&#xeb4f;"
vol_high: str = "&#xeb51;"
mic: str = "&#xeaf0;"
mic_mute: str = "&#xed16;"
speaker: str = "&#x10045;"
headphones: str = "&#xfa3c;"
mic_filled: str = "&#xfe0f;"
# Overview
circle_plus: str = "&#xea69;"
# Pins
paperclip: str = "&#xeb02;"
# Clipboard Manager
clipboard: str = "&#xea6f;"
clip_text: str = "&#xf089;"
# Confirm
accept: str = "&#xea5e;"
cancel: str = "&#xeb55;"
trash: str = "&#xeb41;"
# Config
config: str = "&#xeb20;"
# Icons
firefox: str = "&#xecfd;"
chromium: str = "&#xec18;"
spotify: str = "&#xfe86;"
disc: str = "&#x1003e;"
disc_off: str = "&#xf118;"
# Brightness
brightness_low: str = "&#xeb7d;"
brightness_medium: str = "&#xeb7e;"
brightness_high: str = "&#xeb30;"
brightness: str = "&#xee1a;"
# Dashboard
widgets: str = "&#xf02c;"
pins: str = "&#xec9c;"
kanban: str = "&#xec3f;"
wallpapers: str = "&#xeb61;"
sparkles: str = "&#xf6d7;"
# Misc
dot: str = "&#xf698;"
palette: str = "&#xeb01;"
cloud_off: str = "&#xed3e;"
loader: str = "&#xeca3;"
radar: str = "&#xf017;"
emoji: str = "&#xeaf7;"
keyboard: str = "&#xebd6;"
terminal: str = "&#xebef;"
timer_off: str = "&#xf146;"
timer_on: str = "&#xf756;"
spy: str = "&#xf227;"
calculator: str = "&#xeb80;"
file: str = "&#xeaa4;"
calendar: str = "&#xea53;"
connect: str = "&#xeade;"
disconnect: str = "&#xfd16;"
auth: str = "&#xeca0;"
bookmark: str = "&#xea3a;"
star: str = "&#xeb2e;"
process: str = "&#xf292;"
music: str = "&#xf00d;"
# otp
check: str = "&#xea5e;"
bulb: str = "&#xea51;"
key: str = "&#xeac7;"
magnifier: str = "&#xeb1c;"
plus: str = "&#xeb0b;"
info: str = "&#xeac5;"
# Dice
dice_1: str = "&#xf08b;"
dice_2: str = "&#xf08c;"
dice_3: str = "&#xf08d;"
dice_4: str = "&#xf08e;"
dice_5: str = "&#xf08f;"
dice_6: str = "&#xf090;"
# search engine
reddit: str = "&#xec8e;"
youtube: str = "&#xec90;"
duckduckgo: str = "&#xec8f;"
github: str = "&#xec1c;"
stackoverflow: str = "&#xef58;"
google: str = "&#xec1f;"
linkedin: str = "&#xec8c;"
wikipedia: str = "&#xfa79;"
exceptions: list[str] = ["font_family", "font_weight", "span"]
def apply_span() -> None:
global_dict = globals()
for key in global_dict:
if key not in exceptions and not key.startswith("__"):
global_dict[key] = f"{span}{global_dict[key]}</span>"
apply_span()
+60
View File
@@ -0,0 +1,60 @@
import json
import warnings
from typing import Dict
import time
from fabric.hyprland import Hyprland
from gi.repository import Gdk
from functools import lru_cache
warnings.filterwarnings("ignore", category=DeprecationWarning)
def ttl_lru_cache(seconds_to_live: int, maxsize: int = 128):
def wrapper(func):
@lru_cache(maxsize)
def inner(__ttl, *args, **kwargs):
return func(*args, **kwargs)
return lambda *args, **kwargs: inner(
time.time() // seconds_to_live, *args, **kwargs
)
return wrapper
class HyprlandWithMonitors(Hyprland):
"""A Hyprland class with additional monitor common."""
instance = None
@staticmethod
def get_default():
if HyprlandWithMonitors.instance is None:
HyprlandWithMonitors.instance = HyprlandWithMonitors()
return HyprlandWithMonitors.instance
def __init__(self, commands_only: bool = False, **kwargs):
self.display: Gdk.Display = Gdk.Display.get_default()
super().__init__(commands_only, **kwargs)
@ttl_lru_cache(100, 5)
def get_all_monitors(self) -> Dict:
monitors = json.loads(self.send_command("j/monitors").reply)
return {monitor["id"]: monitor["name"] for monitor in monitors}
def get_gdk_monitor_id_from_name(self, plug_name: str) -> int | None:
for i in range(self.display.get_n_monitors()):
if self.display.get_default_screen().get_monitor_plug_name(i) == plug_name:
return i
return None
def get_gdk_monitor_id(self, hyprland_id: int) -> int | None:
monitors = self.get_all_monitors()
if hyprland_id in monitors:
return self.get_gdk_monitor_id_from_name(monitors[hyprland_id])
return None
def get_current_gdk_monitor_id(self) -> int | None:
active_workspace = json.loads(self.send_command("j/activeworkspace").reply)
return self.get_gdk_monitor_id_from_name(active_workspace["monitor"])