refactor! : drop subprocess usage and centralize brightness service initialization
This commit is contained in:
21 files changed
+834
-828
No files matched your search
@@ -625,38 +625,63 @@ class NotificationWidget(Box):
|
||||
return get_fallback_notification_icon((width, height))
|
||||
|
||||
def _get_notification_pixbuf(self, notification):
|
||||
"""Simplified notification pixbuf with NO CACHING for image-pixmap to prevent disk bloat"""
|
||||
notification_id = getattr(notification, "id", int(time.time()))
|
||||
"""Notification pixbuf — loads notification image or app icon, scaled consistently."""
|
||||
pixbuf = None
|
||||
|
||||
try:
|
||||
# Try to get cached notification image first
|
||||
if hasattr(notification, "image_pixbuf") and notification.image_pixbuf:
|
||||
# 1. Try cache_metadata keys first (cheap — no disk/pixbuf load)
|
||||
cache_meta = getattr(notification, "cache_metadata", {}) or {}
|
||||
notif_key = cache_meta.get("notification_image_cache_key")
|
||||
if notif_key:
|
||||
try:
|
||||
pixbuf = get_cached_notification_image(notif_key)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 2. Try notification image via image_pixbuf (only if no cached)
|
||||
if not pixbuf:
|
||||
try:
|
||||
img = getattr(notification, "image_pixbuf", None)
|
||||
if img is not None:
|
||||
nid = getattr(notification, "id", 0)
|
||||
ck = get_notification_image_cache_key(nid, img)
|
||||
cached = get_cached_notification_image(ck)
|
||||
if cached:
|
||||
pixbuf = cached
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 3. App icon via cache_metadata
|
||||
if not pixbuf:
|
||||
app_key = cache_meta.get("app_icon_cache_key")
|
||||
if app_key:
|
||||
try:
|
||||
cache_key = get_notification_image_cache_key(
|
||||
notification_id, notification.image_pixbuf
|
||||
)
|
||||
cached_image = get_cached_notification_image(cache_key)
|
||||
if cached_image:
|
||||
return cached_image
|
||||
except Exception as image_error:
|
||||
logger.debug(f"Notification image processing failed: {image_error}")
|
||||
# Continue to app icon fallback
|
||||
from window.notification.unified_cache import get_from_cache
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to process notification image: {e}")
|
||||
pixbuf = get_from_cache(app_key, (35, 35))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 4. Direct app icon caching
|
||||
if not pixbuf:
|
||||
app_icon = getattr(notification, "app_icon", None)
|
||||
if app_icon:
|
||||
try:
|
||||
pixbuf = cache_notification_icon(app_icon, (35, 35))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 5. Fallback
|
||||
if not pixbuf:
|
||||
pixbuf = get_fallback_notification_icon((35, 35))
|
||||
|
||||
# Use cached app icon as fallback
|
||||
try:
|
||||
app_icon_source = getattr(notification, "app_icon", None)
|
||||
if app_icon_source:
|
||||
cached_app_icon = cache_notification_icon(app_icon_source, (35, 35))
|
||||
if cached_app_icon:
|
||||
return cached_app_icon
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to get cached app icon: {e}")
|
||||
|
||||
# Ultimate fallback
|
||||
return get_fallback_notification_icon((35, 35))
|
||||
return pixbuf.scale_simple(
|
||||
NOTIFICATION_IMAGE_SIZE,
|
||||
NOTIFICATION_IMAGE_SIZE,
|
||||
GdkPixbuf.InterpType.BILINEAR,
|
||||
)
|
||||
except Exception:
|
||||
return pixbuf
|
||||
|
||||
def create_action_buttons(self, notification):
|
||||
return Box(
|
||||
@@ -1122,10 +1147,11 @@ class ModusNoti(Window):
|
||||
|
||||
self.current_notification = new_box
|
||||
|
||||
# Clear any existing children
|
||||
# Clear and destroy any existing children
|
||||
for child in list(self.notifications.children):
|
||||
try:
|
||||
self.notifications.remove(child)
|
||||
child.destroy()
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred: {e}")
|
||||
|
||||
@@ -1154,10 +1180,11 @@ class ModusNoti(Window):
|
||||
GLib.source_remove(self._transition_timer_id)
|
||||
self._transition_timer_id = None
|
||||
|
||||
# Safely remove notification box
|
||||
# Safely remove and destroy notification box
|
||||
try:
|
||||
if notification_box in self.notifications.children:
|
||||
self.notifications.remove(notification_box)
|
||||
notification_box.destroy()
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred: {e}")
|
||||
|
||||
@@ -1197,8 +1224,11 @@ class ModusNoti(Window):
|
||||
|
||||
# Also clean current notification if showing
|
||||
if self.current_notification:
|
||||
# Mark for cache cleanup when clearing queue
|
||||
self.current_notification.notif_box._should_cleanup_cache = True
|
||||
try:
|
||||
self.current_notification.notification.close("dismissed-by-user")
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred: {e}")
|
||||
|
||||
# Clear animation timers
|
||||
if self._transition_timer_id:
|
||||
|
||||
@@ -698,6 +698,8 @@ class NotificationCenter(AppletWindow):
|
||||
|
||||
self.add_keybinding("Escape", self._on_escape_pressed)
|
||||
|
||||
MAX_GROUPS = 15
|
||||
|
||||
def _rebuild_notification_groups(self):
|
||||
"""Rebuild notification groups from scratch with enhanced asset preloading and debugging"""
|
||||
# Clear existing groups
|
||||
@@ -709,23 +711,27 @@ class NotificationCenter(AppletWindow):
|
||||
child.destroy()
|
||||
|
||||
# Group notifications by app name and preload assets with debugging
|
||||
rebuild_count = 0
|
||||
for cached_notification in notification_service.cached_notifications:
|
||||
app_name = cached_notification._notification.app_name
|
||||
getattr(cached_notification._notification, "id", None)
|
||||
|
||||
# Skip ignored apps during rebuild
|
||||
if app_name in data.NOTIFICATION_IGNORED_APPS_HISTORY:
|
||||
continue
|
||||
|
||||
# Preload assets for each cached notification to ensure display consistency
|
||||
preload_notification_assets(cached_notification._notification)
|
||||
|
||||
self.notification_groups[app_name].append(cached_notification)
|
||||
rebuild_count += 1
|
||||
|
||||
# Sort groups by most recent notification
|
||||
sorted_groups = sorted(
|
||||
self.notification_groups.items(),
|
||||
key=lambda item: max(
|
||||
(getattr(n._notification, "id", 0) for n in item[1]), default=0
|
||||
),
|
||||
reverse=True,
|
||||
)[: self.MAX_GROUPS]
|
||||
|
||||
self.notification_groups.clear()
|
||||
# Create group widgets and handle limited apps
|
||||
for app_name, notifications in self.notification_groups.items():
|
||||
for app_name, notifications in sorted_groups:
|
||||
# Sort notifications by ID (highest ID first - newest notifications)
|
||||
# This ensures the latest notifications appear at the top of each group
|
||||
notifications.sort(
|
||||
@@ -736,11 +742,10 @@ class NotificationCenter(AppletWindow):
|
||||
if app_name in data.NOTIFICATION_LIMITED_APPS_HISTORY:
|
||||
if len(notifications) > 5:
|
||||
# Keep only the 5 most recent notifications
|
||||
self.notification_groups[app_name] = notifications[:5]
|
||||
notifications = notifications[:5]
|
||||
|
||||
group_widget = ExpandableNotificationGroup(
|
||||
app_name, self.notification_groups[app_name]
|
||||
)
|
||||
group_widget = ExpandableNotificationGroup(app_name, notifications)
|
||||
self.notification_groups[app_name] = notifications
|
||||
self.group_widgets[app_name] = group_widget
|
||||
self.notifications_box.add(group_widget)
|
||||
|
||||
@@ -809,9 +814,10 @@ class NotificationCenter(AppletWindow):
|
||||
def _refresh_group_widget(self, group_widget):
|
||||
"""Refresh a group widget's content"""
|
||||
try:
|
||||
# Remove existing children
|
||||
# Remove and destroy existing children
|
||||
for child in group_widget.get_children():
|
||||
group_widget.remove(child)
|
||||
child.destroy()
|
||||
|
||||
# Recreate content
|
||||
group_widget.create_collapsed_state()
|
||||
@@ -886,6 +892,8 @@ class NotificationCenter(AppletWindow):
|
||||
|
||||
# Clear all remaining cached notification images AND icons when clear all is clicked
|
||||
cleanup_all_notification_caches() # Clear ALL caches (icons + images)
|
||||
for child in self.notifications_box.get_children():
|
||||
child.destroy()
|
||||
notification_service.clear_all_cached_notifications()
|
||||
self.hide()
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import hashlib
|
||||
import time
|
||||
import uuid
|
||||
from collections import OrderedDict
|
||||
|
||||
from fabric.utils import GdkPixbuf, get_relative_path, logger, os
|
||||
|
||||
@@ -9,6 +10,9 @@ import shared.data as data
|
||||
# Unified notification cache directory (for both app icons and notification images)
|
||||
UNIFIED_NOTIFICATION_CACHE_DIR = os.path.join(data.CACHE_DIR, "notifications")
|
||||
|
||||
_MEMORY_PIXBUF_CACHE: OrderedDict[str, GdkPixbuf.Pixbuf] = OrderedDict()
|
||||
_MEMORY_CACHE_MAX = 64
|
||||
|
||||
|
||||
def ensure_cache_dir():
|
||||
"""Ensure unified notification cache directory exists"""
|
||||
@@ -72,16 +76,23 @@ def save_to_cache(pixbuf, cache_key, size=None):
|
||||
|
||||
def get_from_cache(cache_key, size=None):
|
||||
"""Get a cached asset or return None if not found"""
|
||||
mem_key = f"{cache_key}:{size}"
|
||||
if mem_key in _MEMORY_PIXBUF_CACHE:
|
||||
_MEMORY_PIXBUF_CACHE.move_to_end(mem_key)
|
||||
return _MEMORY_PIXBUF_CACHE[mem_key]
|
||||
try:
|
||||
cache_path = os.path.join(UNIFIED_NOTIFICATION_CACHE_DIR, f"{cache_key}.png")
|
||||
if os.path.exists(cache_path):
|
||||
# logger.debug(f"Using cached asset: {cache_key}")
|
||||
if size:
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
|
||||
cache_path, size[0], size[1], True
|
||||
)
|
||||
else:
|
||||
return GdkPixbuf.Pixbuf.new_from_file(cache_path)
|
||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(cache_path)
|
||||
while len(_MEMORY_PIXBUF_CACHE) >= _MEMORY_CACHE_MAX:
|
||||
_MEMORY_PIXBUF_CACHE.popitem(last=False)
|
||||
_MEMORY_PIXBUF_CACHE[mem_key] = pixbuf
|
||||
return pixbuf
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to load cached asset: {e}")
|
||||
return None
|
||||
@@ -99,6 +110,9 @@ def cleanup_cache(cache_key=None):
|
||||
)
|
||||
if os.path.exists(cache_path):
|
||||
os.unlink(cache_path)
|
||||
mem_keys = [k for k in _MEMORY_PIXBUF_CACHE if k.startswith(cache_key)]
|
||||
for k in mem_keys:
|
||||
_MEMORY_PIXBUF_CACHE.pop(k, None)
|
||||
else:
|
||||
# Remove all cached assets
|
||||
for filename in os.listdir(UNIFIED_NOTIFICATION_CACHE_DIR):
|
||||
@@ -108,6 +122,7 @@ def cleanup_cache(cache_key=None):
|
||||
os.unlink(filepath)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to cleanup cache file {filename}: {e}")
|
||||
_MEMORY_PIXBUF_CACHE.clear()
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to cleanup cache: {e}")
|
||||
|
||||
|
||||
Reference in new issue
Block a user