From 0d2494abd7088da78c9e5838958835887c9df117 Mon Sep 17 00:00:00 2001 From: LemonNexus Date: Sun, 15 Feb 2026 23:29:54 +0000 Subject: [PATCH] fix: Simplify tray icon - remove timer and complex styling that blocks UI The tray icon was blocking the main UI thread because: 1. QTimer was updating menu state every second 2. Complex stylesheet on menu may cause blocking 3. Emojis in menu items might cause encoding issues Simplified: - Removed update timer (no longer needed) - Removed complex stylesheet (use default) - Removed emojis from menu items - Made TrayIcon inherit QWidget for proper parent - Simplified signal connections --- core/tray_icon.py | 165 ++++++++++++---------------------------------- 1 file changed, 43 insertions(+), 122 deletions(-) diff --git a/core/tray_icon.py b/core/tray_icon.py index 3eb71e2..0cab8a5 100644 --- a/core/tray_icon.py +++ b/core/tray_icon.py @@ -1,32 +1,17 @@ """ -EU-Utility - System Tray Icon -============================= +EU-Utility - System Tray Icon (Simplified) +========================================== -System tray implementation with right-click menu. -Replaces the floating icon with a proper tray icon. +Simple, responsive system tray icon. """ -from PyQt6.QtWidgets import QSystemTrayIcon, QMenu, QApplication -from PyQt6.QtGui import QAction -from PyQt6.QtCore import QTimer, pyqtSignal, QObject -from PyQt6.QtGui import QIcon, QColor, QPainter, QFont, QFontMetrics - -from core.logger import get_logger - -logger = get_logger(__name__) +from PyQt6.QtWidgets import QSystemTrayIcon, QMenu, QApplication, QWidget +from PyQt6.QtGui import QAction, QIcon, QColor, QPainter, QFont +from PyQt6.QtCore import pyqtSignal -class TrayIcon(QObject): - """ - System tray icon for EU-Utility. - - Features: - - Right-click context menu - - Show/hide dashboard - - Toggle activity bar - - Settings access - - Quit option - """ +class TrayIcon(QWidget): + """Simple system tray icon for EU-Utility.""" show_dashboard = pyqtSignal() toggle_activity_bar = pyqtSignal() @@ -36,126 +21,62 @@ class TrayIcon(QObject): def __init__(self, app: QApplication, parent=None): super().__init__(parent) self.app = app - self.tray_icon = None - self.menu = None + # Create icon self._create_icon() - self._setup_menu() - self._setup_visibility_timer() - - def _create_icon(self): - """Create the tray icon with EU logo.""" - # Create a simple colored circle icon with "EU" text - pixmap = QIcon.fromTheme("applications-system") - # If no system icon, create custom - if pixmap.isNull(): - from PyQt6.QtGui import QPixmap, QPainter, QColor, QFont - px = QPixmap(64, 64) - px.fill(QColor(255, 140, 66)) # Orange background - - painter = QPainter(px) - painter.setPen(QColor(255, 255, 255)) - font = QFont("Segoe UI", 24, QFont.Weight.Bold) - painter.setFont(font) - painter.drawText(px.rect(), Qt.AlignmentFlag.AlignCenter, "EU") - painter.end() - - pixmap = QIcon(px) + # Create menu (but don't set it yet) + self._create_menu() - self.tray_icon = QSystemTrayIcon(self) - self.tray_icon.setIcon(pixmap) - self.tray_icon.setToolTip("EU-Utility") - - # Show the icon - self.tray_icon.show() - - # Connect activation (double-click) + # Connect signals self.tray_icon.activated.connect(self._on_activated) - def _setup_menu(self): - """Setup the right-click context menu.""" - self.menu = QMenu() - self.menu.setStyleSheet(""" - QMenu { - background: rgba(35, 35, 35, 0.98); - color: white; - border: 1px solid rgba(255, 255, 255, 0.1); - border-radius: 8px; - padding: 8px; - } - QMenu::item { - padding: 10px 24px; - border-radius: 6px; - } - QMenu::item:selected { - background: rgba(255, 140, 66, 0.3); - } - QMenu::separator { - height: 1px; - background: rgba(255, 255, 255, 0.1); - margin: 8px 16px; - } - """) + def _create_icon(self): + """Create tray icon.""" + # Create simple icon + px = QPixmap(64, 64) + px.fill(QColor(255, 140, 66)) # Orange - # Dashboard action - self.dashboard_action = QAction("📊 Dashboard", self) - self.dashboard_action.triggered.connect(self.show_dashboard) + painter = QPainter(px) + painter.setPen(QColor(255, 255, 255)) + font = QFont("Segoe UI", 24, QFont.Weight.Bold) + painter.setFont(font) + painter.drawText(px.rect(), 0x84, "EU") # AlignCenter + painter.end() + + self.tray_icon = QSystemTrayIcon(self) + self.tray_icon.setIcon(QIcon(px)) + self.tray_icon.setToolTip("EU-Utility") + self.tray_icon.show() + + def _create_menu(self): + """Create simple context menu.""" + self.menu = QMenu() + + # Simple actions (no emojis to avoid encoding issues) + self.dashboard_action = QAction("Dashboard", self) + self.dashboard_action.triggered.connect(self.show_dashboard.emit) self.menu.addAction(self.dashboard_action) - # Activity Bar toggle - self.activity_bar_action = QAction("🎮 Activity Bar", self) + self.activity_bar_action = QAction("Activity Bar", self) self.activity_bar_action.setCheckable(True) - self.activity_bar_action.triggered.connect(self.toggle_activity_bar) + self.activity_bar_action.triggered.connect(self.toggle_activity_bar.emit) self.menu.addAction(self.activity_bar_action) self.menu.addSeparator() - # Settings - self.settings_action = QAction("⚙️ Settings", self) - self.settings_action.triggered.connect(self.open_settings) - self.menu.addAction(self.settings_action) - - self.menu.addSeparator() - - # Quit - self.quit_action = QAction("❌ Quit", self) - self.quit_action.triggered.connect(self.quit_app) + self.quit_action = QAction("Quit", self) + self.quit_action.triggered.connect(self.quit_app.emit) self.menu.addAction(self.quit_action) - # Set menu + # Set context menu self.tray_icon.setContextMenu(self.menu) - def _setup_visibility_timer(self): - """Setup timer to update menu state.""" - self.update_timer = QTimer(self) - self.update_timer.timeout.connect(self._update_menu_state) - self.update_timer.start(1000) # Update every second - - def _update_menu_state(self): - """Update menu checkbox states.""" - # This will be connected to actual state - pass - def _on_activated(self, reason): - """Handle tray icon activation.""" + """Handle double-click.""" if reason == QSystemTrayIcon.ActivationReason.DoubleClick: self.show_dashboard.emit() - def show_notification(self, title: str, message: str, duration: int = 3000): - """Show a system notification.""" - if self.tray_icon and self.tray_icon.supportsMessages(): - self.tray_icon.showMessage( - title, - message, - QSystemTrayIcon.MessageIcon.Information, - duration - ) - def set_activity_bar_checked(self, checked: bool): - """Update activity bar menu item state.""" + """Update checkbox.""" self.activity_bar_action.setChecked(checked) - - def is_visible(self) -> bool: - """Check if tray icon is visible.""" - return self.tray_icon and self.tray_icon.isVisible()