This commit is contained in:
sankalp committed 2024-12-01 08:18:11 +05:45
1 parent f5eaa6596d
commit 149cd94a44
6 files changed
+75 -118

No files matched your search

-1
View File
@@ -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,
@@ -17,7 +17,7 @@ __all__ = [
"MicrophoneIndicator",
"Network",
"PowerProfile",
"TaskBar",
"VolumeIndicator",
"workspace",
"TaskBar",
]
@@ -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
+41 -14
View File
@@ -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
-2
View File
@@ -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",
-100
View File
@@ -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
)