From 149cd94a44d2ae172cced72c83eb368e68e91bb8 Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Sun, 1 Dec 2024 08:18:11 +0545 Subject: [PATCH] fixed --- config/fabric/modules/bar/bar.py | 1 - config/fabric/modules/bar/widgets/__init__.py | 2 +- .../modules/bar/widgets/screen_record.py | 33 ++++++ config/fabric/modules/bar/widgets/taskbar.py | 55 +++++++--- config/fabric/snippets/__init__.py | 2 - config/fabric/snippets/icon_resolver.py | 100 ------------------ 6 files changed, 75 insertions(+), 118 deletions(-) create mode 100644 config/fabric/modules/bar/widgets/screen_record.py delete mode 100644 config/fabric/snippets/icon_resolver.py diff --git a/config/fabric/modules/bar/bar.py b/config/fabric/modules/bar/bar.py index 58576d38..ea8b622a 100644 --- a/config/fabric/modules/bar/bar.py +++ b/config/fabric/modules/bar/bar.py @@ -6,7 +6,6 @@ from fabric.widgets.button import Button from fabric.widgets.centerbox import CenterBox from fabric.widgets.datetime import DateTime from fabric.widgets.wayland import WaylandWindow as Window - from modules.bar.widgets import ( BatteryLabel, Bluetooth, diff --git a/config/fabric/modules/bar/widgets/__init__.py b/config/fabric/modules/bar/widgets/__init__.py index e4ec6d06..27ff16e8 100644 --- a/config/fabric/modules/bar/widgets/__init__.py +++ b/config/fabric/modules/bar/widgets/__init__.py @@ -17,7 +17,7 @@ __all__ = [ "MicrophoneIndicator", "Network", "PowerProfile", - "TaskBar", "VolumeIndicator", "workspace", + "TaskBar", ] diff --git a/config/fabric/modules/bar/widgets/screen_record.py b/config/fabric/modules/bar/widgets/screen_record.py new file mode 100644 index 00000000..43217724 --- /dev/null +++ b/config/fabric/modules/bar/widgets/screen_record.py @@ -0,0 +1,33 @@ +from fabric import Fabricator +from fabric.widgets.box import Box +from fabric.widgets.button import Button +from services import ScreenRecorder +from snippets import MaterialIcon + + +class ScreenRecordButton(Box): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + self.recorder = ScreenRecorder() + self.record_icon_button = self.create_record_icon() + + Fabricator(interval=1000, poll_from=self.update_recording_status) + + self.children = (self.record_icon_button,) + + def create_record_icon(self): + icon = MaterialIcon("screen_record", size="16px") + button = Button(child=icon, on_clicked=self.stop_recording) + button.icon_widget = icon + return button + + def stop_recording(self, *_): + self.recorder.screencast_stop() + self.update_recording_status() + + def update_recording_status(self, *_): + if self.recorder.recording: + self.record_icon_button.icon_widget.set_label("screen_record") + + return True diff --git a/config/fabric/modules/bar/widgets/taskbar.py b/config/fabric/modules/bar/widgets/taskbar.py index 8db80e8c..aaf88486 100644 --- a/config/fabric/modules/bar/widgets/taskbar.py +++ b/config/fabric/modules/bar/widgets/taskbar.py @@ -1,4 +1,5 @@ import json +import os from typing import TypedDict from fabric.hyprland.widgets import get_hyprland_connection @@ -7,7 +8,7 @@ from fabric.widgets.box import Box from fabric.widgets.button import Button from fabric.widgets.image import Image from gi.repository import GdkPixbuf, GLib, Gtk -from snippets import IconResolver +from loguru import logger class PagerClient(TypedDict): @@ -29,7 +30,6 @@ class TaskBar(Box): self.connection = get_hyprland_connection() self.icon_size = icon_size self.icon_theme = Gtk.IconTheme.get_default() - self.icon_resolver = IconResolver() self.set_visible(False) self._icon_cache = {} @@ -61,9 +61,7 @@ class TaskBar(Box): button = Button(image=icon, tooltip_text=client["title"]) if client["address"] == active_window_address: - button.set_style( - "background-color: @surfaceVariant; border-radius:100px;" - ) + button.add_style_class("activated") button.connect( "button-press-event", self.on_icon_click, client["address"] ) @@ -95,18 +93,47 @@ class TaskBar(Box): def bake_window_icon( self, window_class: str, fallback_icon: str = "image-missing" ) -> Image: - icon_name = self.icon_resolver.get_icon_name(window_class) or fallback_icon - if icon_name not in self._icon_cache: - pixbuf = self.load_icon(icon_name) - self._icon_cache[icon_name] = pixbuf - return Image(pixbuf=self._icon_cache[icon_name], size=self.icon_size) + icon_name = self.get_icon_from_desktop_entry(window_class) - def load_icon(self, icon_name: str) -> GdkPixbuf.Pixbuf: + if icon_name: + pixbuf = self.load_icon(icon_name) + else: + pixbuf = self.load_icon(window_class, fallback_icon) + + return Image(pixbuf=pixbuf, size=self.icon_size) + + def get_icon_from_desktop_entry(self, window_class: str) -> str: + for data_dir in GLib.get_system_data_dirs(): + applications_dir = os.path.join(data_dir, "applications") + + if os.path.isdir(applications_dir): + for desktop_file in os.listdir(applications_dir): + if desktop_file.endswith(".desktop"): + file_path = os.path.join(applications_dir, desktop_file) + try: + with open(file_path, "r") as f: + app_name = None + icon_name = None + for line in f: + if line.startswith("Name="): + app_name = line.split("=", 2)[1].strip().lower() + elif line.startswith("Icon=") and app_name: + icon_name = line.split("=", 2)[1].strip() + if window_class in app_name: + return icon_name + except Exception as e: + logger.error(f"Error reading {file_path}: {e}") + return None + + def load_icon( + self, icon_name: str, fallback_icon: str = "image-missing" + ) -> GdkPixbuf.Pixbuf: try: - return self.icon_theme.load_icon( + pixbuf = self.icon_theme.load_icon( icon_name, self.icon_size, Gtk.IconLookupFlags.FORCE_SIZE ) except Exception: - return self.icon_theme.load_icon( - "image-missing", self.icon_size, Gtk.IconLookupFlags.FORCE_SIZE + pixbuf = self.icon_theme.load_icon( + fallback_icon, self.icon_size, Gtk.IconLookupFlags.FORCE_SIZE ) + return pixbuf diff --git a/config/fabric/snippets/__init__.py b/config/fabric/snippets/__init__.py index 6d550f3a..a785baa2 100644 --- a/config/fabric/snippets/__init__.py +++ b/config/fabric/snippets/__init__.py @@ -6,12 +6,10 @@ from .functions import ( username, ) from .icon import MaterialIcon -from .icon_resolver import IconResolver __all__ = [ "Animator", "MaterialIcon", - "IconResolver", "read_config", "get_profile_picture_path", "username", diff --git a/config/fabric/snippets/icon_resolver.py b/config/fabric/snippets/icon_resolver.py deleted file mode 100644 index 6c1fc9c6..00000000 --- a/config/fabric/snippets/icon_resolver.py +++ /dev/null @@ -1,100 +0,0 @@ -import json -import os -import re - -import gi - -gi.require_version("Gtk", "3.0") -from gi.repository import GLib, Gtk -from loguru import logger - -# TODO WIP -# Idea: nearest string matching algorithm -# if already exists: retrieve from json -# if found: stor in json: app_id -> icon_name -# if not found: store in json -> misisng-icon - - -CACHE_DIR = str(GLib.get_user_cache_dir()) + "/fabric" -ICON_CACHE_FILE = CACHE_DIR + "/icons.json" -if not os.path.exists(CACHE_DIR): - os.makedirs(CACHE_DIR) - - -class IconResolver: - def __init__(self, default_applicaiton_icon: str = "image-missing"): - if os.path.exists(ICON_CACHE_FILE): - f = open(ICON_CACHE_FILE) - try: - self._icon_dict = json.load(f) - except json.JSONDecodeError: - logger.info("[ICONS] Cache file does not exist or is corrupted") - f.close() - else: - self._icon_dict = {} - - self.default_applicaiton_icon = default_applicaiton_icon - - def get_icon_name(self, app_id: str): - if app_id in self._icon_dict: - return self._icon_dict[app_id] - new_icon = self._compositor_find_icon(app_id) - logger.info( - f"[ICONS] found new icon: '{new_icon}' for app id: '{app_id}', storing..." - ) - self._store_new_icon(app_id, new_icon) - return new_icon - - def get_icon_pixbuf(self, app_id: str, size: int = 16): - return Gtk.IconTheme.get_default().load_icon( - self.get_icon_name(app_id), - size, - Gtk.IconLookupFlags.FORCE_SIZE, - ) - - def _store_new_icon(self, app_id: str, icon: str): - self._icon_dict[app_id] = icon - with open(ICON_CACHE_FILE, "w") as f: - json.dump(self._icon_dict, f) - f.close() - - def _get_icon_from_desktop_file(self, desktop_file_path: str): - # TODO: get icon in the [Desktop Entry] section only - with open(desktop_file_path) as f: - for line in f.readlines(): - if "Icon=" in line: - return "".join(line[5:].split()) - return self.default_applicaiton_icon - - def _get_desktop_file(self, app_id: str) -> str | None: - data_dirs = GLib.get_system_data_dirs() - for data_dir in data_dirs: - data_dir = data_dir + "/applications/" - if os.path.exists(data_dir): - # Do name resolving here - - files = os.listdir(data_dir) - matching = [ - s for s in files if "".join(app_id.lower().split()) in s.lower() - ] - if matching: - return data_dir + matching[0] - - for word in list(filter(None, re.split(r"-|\.|_|\s", app_id))): - matching = [s for s in files if word.lower() in s.lower()] - if matching: - return data_dir + matching[0] - - return None - - def _compositor_find_icon(self, app_id: str): - if Gtk.IconTheme.get_default().has_icon(app_id): - return app_id - if Gtk.IconTheme.get_default().has_icon(app_id + "-desktop"): - return app_id + "-desktop" - desktop_file = self._get_desktop_file(app_id) - return ( - self._get_icon_from_desktop_file(desktop_file) - if desktop_file - else self.default_applicaiton_icon - )