refactor(src/services): simplify menu cache implementation and remove unused imports

- Remove time import and unused typing items
- Streamline cache eviction and hit logic
- Replace sentinel handling with simpler checks
- Fix activation environment command arguments
- Improve logging messages and cache hit reporting
This commit is contained in:
sankalp committed 2026-07-03 21:31:41 +05:45
1 parent 6171577ecc
commit 8d40ac1a7f
1 file changed
+27 -41
+27 -41
View File
@@ -3,8 +3,7 @@
import json
import re
import threading
import time
from typing import List, Optional
from typing import List, Optional, Dict, Union
from fabric.core.service import Property, Service, Signal
from fabric.utils import (
@@ -82,11 +81,10 @@ class GlobalMenuService(Service):
self._current_wm_class: str = ""
self._current_pid: int = 0
# Bounded LRU caches — deliberately small to save memory
self._client_cache: dict[str, Optional[DBusMenuClient]] = {}
self._menu_cache: dict[str, Optional[List[DBusMenuItem]]] = {}
self._cache_order: list[str] = []
self._empty_cache_ts: dict[str, float] = {} # wm_class -> monotonic timestamp
# Cached dbus menu clients mapping: wm_class -> Client
self._client_cache: Dict[str, Union[GtkMenuClient, DBusMenuClient]] = {}
# Cached layout for fast repaints
self._menu_cache: Dict[str, List[DBusMenuItem]] = {}
# Registrar mapping: sender -> (service_name, object_path)
self._registered_menus: dict[str, tuple[str, str]] = {}
@@ -137,8 +135,9 @@ class GlobalMenuService(Service):
# causing gdk_wayland_window_set_dbus_properties_libgtk_only assertion failures.
# The hyprctl/dbus-update-activation-environment calls set it for future apps instead.
exec_shell_command("hyprctl keyword env GTK_MODULES,appmenu-gtk-module")
exec_shell_command("hyprctl keyword env UBUNTU_MENUPROXY,1")
exec_shell_command(
"dbus-update-activation-environment --systemd GTK_MODULES=appmenu-gtk-module"
"dbus-update-activation-environment --systemd GTK_MODULES=appmenu-gtk-module UBUNTU_MENUPROXY=1"
)
# 2. Automatically grant Flatpak apps permission to talk to the DBus Registrar
@@ -258,24 +257,10 @@ class GlobalMenuService(Service):
self.active_app_changed(app_name, wm_class)
# Check cache — snapshot under lock, serve non-empty + non-expired results
# Check cache — snapshot under lock, serve non-empty results
with self._lock:
cached_menu = self._menu_cache.get(wm_class)
has_good_cache = (
wm_class in self._client_cache
and cached_menu is not None
and cached_menu # non-empty
and cached_menu is not _EMPTY_SENTINEL
)
if has_good_cache:
# non-empty, serve it
pass
elif cached_menu is _EMPTY_SENTINEL:
# last attempt returned empty — check TTL
empty_ts = self._empty_cache_ts.get(wm_class, 0)
if time.monotonic() - empty_ts < _EMPTY_CACHE_TTL:
has_good_cache = True # still within TTL, skip re-scan
cached_menu = []
has_good_cache = wm_class in self._client_cache and cached_menu is not None
if has_good_cache:
with self._state_lock:
@@ -283,10 +268,8 @@ class GlobalMenuService(Service):
self._current_app = app_name
self._current_wm_class = wm_class
self._current_pid = target_pid
logger.info(
f"[GlobalMenuService] Cache {'hit' if cached_menu else 'skip (empty TTL)'} for '{wm_class}'"
)
self.menu_changed(cached_menu or [])
logger.info(f"[GlobalMenuService] Cache hit for '{wm_class}'")
self.menu_changed(cached_menu)
return
# Clear menu IMMEDIATELY for the new app (before in_flight check below).
@@ -629,6 +612,16 @@ class GlobalMenuService(Service):
try:
test_client = GtkMenuClient(gsvc, gpath)
test_items = test_client.get_layout()
if not test_items:
import time
for _ in range(4):
time.sleep(0.05)
test_items = test_client.get_layout()
if test_items:
break
if test_items:
logger.info(
f"[GlobalMenuService] GTK menu found: {gsvc} {gpath} ({len(test_items)} items)"
@@ -875,6 +868,8 @@ class GlobalMenuService(Service):
def _evict_cache_if_needed(self, key: str):
"""Evict oldest cache entries when over the size limit. Must be called under _lock."""
if not hasattr(self, "_cache_order"):
self._cache_order: list[str] = []
if key not in self._cache_order:
self._cache_order.append(key)
@@ -882,7 +877,6 @@ class GlobalMenuService(Service):
oldest = self._cache_order.pop(0)
self._client_cache.pop(oldest, None)
self._menu_cache.pop(oldest, None)
self._empty_cache_ts.pop(oldest, None)
logger.debug(f"[GlobalMenuService] Evicted cache for '{oldest}'")
def _extract_menu(
@@ -901,24 +895,16 @@ class GlobalMenuService(Service):
if client:
items = client.get_layout()
with self._lock:
if items:
if items:
with self._lock:
self._client_cache[wm_class] = client
self._menu_cache[wm_class] = items
self._empty_cache_ts.pop(wm_class, None)
self._evict_cache_if_needed(wm_class)
logger.info(
f"[GlobalMenuService] Found menu for '{wm_class}': {len(items)} items"
)
else:
# Cache empty result with TTL to avoid repeated DBus scanning
self._client_cache.pop(wm_class, None)
self._menu_cache[wm_class] = _EMPTY_SENTINEL
self._empty_cache_ts[wm_class] = time.monotonic()
self._evict_cache_if_needed(wm_class)
logger.info(
f"[GlobalMenuService] No DBus menu found for '{wm_class}' (cached empty)"
)
else:
logger.info(f"[GlobalMenuService] No DBus menu found for '{wm_class}'")
with self._seq_lock:
current_seq = self._extraction_seq