From 418407b2b9d5b9bab2b3b0981a3c7fbbc3d489d7 Mon Sep 17 00:00:00 2001 From: jknapp Date: Sat, 3 Jan 2026 17:12:39 -0800 Subject: [PATCH] Fix icon loading in PyInstaller builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PyInstaller bundles data files into sys._MEIPASS, not the executable directory. - Add get_resource_path() helper in main.py and main_window.py - Use _MEIPASS for bundled resources (icon, web files) - Keep app_dir pointing to executable directory for user data (macros.json) This fixes the missing icon in taskbar and system tray on Windows builds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- gui/main_window.py | 18 ++++++++++++++---- main.py | 21 ++++++++++++++++----- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/gui/main_window.py b/gui/main_window.py index abe8edf..bb61fd1 100644 --- a/gui/main_window.py +++ b/gui/main_window.py @@ -5,6 +5,15 @@ import sys import threading from typing import Optional + +def get_resource_path(relative_path): + """Get the path to a bundled resource file.""" + if getattr(sys, 'frozen', False): + base_path = sys._MEIPASS + else: + base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + return os.path.join(base_path, relative_path) + from PySide6.QtWidgets import ( QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTabWidget, QGridLayout, @@ -293,11 +302,12 @@ class MainWindow(QMainWindow): """Setup system tray icon.""" self.tray_icon = QSystemTrayIcon(self) - # Load icon - icon_path = os.path.join(self.app_dir, "Macro Pad.png") + # Load icon from bundled resources + icon_path = get_resource_path("Macro Pad.png") if os.path.exists(icon_path): - self.tray_icon.setIcon(QIcon(icon_path)) - self.setWindowIcon(QIcon(icon_path)) + icon = QIcon(icon_path) + self.tray_icon.setIcon(icon) + self.setWindowIcon(icon) else: self.tray_icon.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_ComputerIcon)) diff --git a/main.py b/main.py index 9b85c38..5a12c52 100644 --- a/main.py +++ b/main.py @@ -7,21 +7,32 @@ import multiprocessing def get_app_dir(): - """Get the application directory.""" + """Get the application directory (where macros.json and macro_images are stored).""" if getattr(sys, 'frozen', False): - # Running as compiled executable + # Running as compiled executable - use executable's directory for user data return os.path.dirname(sys.executable) else: # Running as script return os.path.dirname(os.path.abspath(__file__)) +def get_resource_path(relative_path): + """Get the path to a bundled resource file.""" + if getattr(sys, 'frozen', False): + # Running as compiled executable - resources are in _MEIPASS + base_path = sys._MEIPASS + else: + # Running as script - resources are in the script directory + base_path = os.path.dirname(os.path.abspath(__file__)) + return os.path.join(base_path, relative_path) + + def main(): """Main entry point.""" # Required for multiprocessing on Windows multiprocessing.freeze_support() - # Get app directory + # Get directories app_dir = get_app_dir() # Import PySide6 after freeze_support @@ -34,8 +45,8 @@ def main(): app.setApplicationName("MacroPad Server") app.setOrganizationName("MacroPad") - # Set application icon - icon_path = os.path.join(app_dir, "Macro Pad.png") + # Set application icon (from bundled resources) + icon_path = get_resource_path("Macro Pad.png") if os.path.exists(icon_path): app.setWindowIcon(QIcon(icon_path))