diff --git a/main.py b/main.py index 6dba101..883f425 100644 --- a/main.py +++ b/main.py @@ -1,9 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ -NexusLauncher - 主程序(简化版) -一个现代化的应用启动器 +NexusLauncher - Main Program +A modern application launcher """ +import sys +import ctypes import customtkinter as ctk from config import ConfigManager from config.constants import ( @@ -27,15 +29,15 @@ from ui.utilities import WindowManager, UIHelpers class NexusLauncher(ctk.CTk): - """主应用程序类(简化版)""" + """Main application class""" def __init__(self): super().__init__() - # 调试模式控制 + # Debug mode control self.debug_mode = False - # 创建启动画面 + # Create a splash screen self.splash = None try: from ui import SplashScreen @@ -43,42 +45,42 @@ class NexusLauncher(ctk.CTk): except Exception as e: self._log(f"Failed to create splash screen: {e}", "WARNING") - # 初始化管理器 + # Initialization Manager self.config_manager = ConfigManager() self.window_manager = WindowManager(self, self.config_manager) - # 设置Windows AppUserModelID + # Set Windows AppUserModelID self.window_manager.setup_window_appid() - # 图标管理 + # Icon Management self.icons_dir = get_icons_dir() self.icon_size = self.config_manager.get_icon_size() self.icon_manager = IconManager(self.icons_dir, self.icon_size) - # 窗口配置 + # Window Configuration self._setup_window() - # 创建界面 + # Create Interface self._create_widgets() - # 绑定事件 + # Binding events self._bind_events() - # 初始化UI + # Initialize UI self._initialize_ui() - # 设置托盘和窗口关闭事件 + # Set tray and window close events self.protocol("WM_DELETE_WINDOW", self.window_manager.hide_window) self.window_manager.setup_tray_icon() def _log(self, message: str, level: str = "INFO"): - """统一的日志方法 + """Unified logging method Args: - message: 日志消息 - level: 日志级别 (DEBUG, INFO, WARNING, ERROR) + message: Log messages + level: Log levels (DEBUG, INFO, WARNING, ERROR) """ - # DEBUG级别的日志只在调试模式下输出 + # DEBUG level logs are only output in debug mode. if level == "DEBUG" and not self.debug_mode: return @@ -87,46 +89,46 @@ class NexusLauncher(ctk.CTk): print(full_message) def _setup_window(self): - """设置窗口属性""" + """Set window properties""" self.title("NexusLauncher") width, height = self.config_manager.get_window_size() self.minsize(200, 200) - # 定位窗口到右下角 + # Position the window to the bottom right corner self.window_manager.position_window_bottom_right(width, height) - # 设置图标和主题 + # Set icon and theme self.window_manager.set_window_icon() ctk.set_appearance_mode("dark") self.configure(fg_color=BG_COLOR_DARK) def _create_widgets(self): - """创建界面组件""" - # 配置网格布局 + """Creating UI Components""" + # Configuring Grid Layout self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(1, weight=1) - # 创建各个部分 + # Create each part self._create_header() self._create_project_area() def _create_header(self): - """创建顶部菜单栏""" + """Create a top menu bar""" self.menu_frame = ctk.CTkFrame(self, height=40, corner_radius=0) self.menu_frame.grid(row=0, column=0, sticky="ew", padx=0, pady=0) self.menu_frame.grid_columnconfigure(0, weight=1) - # 标题 + # Title ctk.CTkLabel( self.menu_frame, text="NexusLauncher", font=ctk.CTkFont(size=16, weight="bold") ).grid(row=0, column=0, padx=20, pady=8, sticky="w") - # 设置按钮 + # Set button ctk.CTkButton( self.menu_frame, - text="⚙ 设置", + text="⚙ Setting", command=self._open_settings, width=90, height=30, @@ -134,7 +136,7 @@ class NexusLauncher(ctk.CTk): ).grid(row=0, column=1, padx=20, pady=8, sticky="e") def _create_project_area(self): - """创建项目区域""" + """Create project area""" self.project_frame = ctk.CTkFrame(self, corner_radius=0, fg_color=COLOR_TRANSPARENT) self.project_frame.grid(row=1, column=0, sticky="nsew", padx=0, pady=0) self.project_frame.grid_columnconfigure(0, weight=1) @@ -144,14 +146,14 @@ class NexusLauncher(ctk.CTk): self._create_tabview() def _create_project_selector(self): - """创建项目选择下拉框""" + """Project creation selection dropdown""" project_select_frame = ctk.CTkFrame(self.project_frame, fg_color=COLOR_TRANSPARENT) project_select_frame.grid(row=0, column=0, sticky="ew", padx=20, pady=(3, 3)) project_select_frame.grid_columnconfigure(1, weight=1) ctk.CTkLabel( project_select_frame, - text="当前项目:", + text="Current Project:", font=ctk.CTkFont(size=13, weight="bold") ).grid(row=0, column=0, padx=(0, 10), sticky="w") @@ -175,7 +177,7 @@ class NexusLauncher(ctk.CTk): self.project_combo.grid(row=0, column=1, sticky="ew") def _create_tabview(self): - """创建标签页""" + """Create a tab""" self.tabview = ctk.CTkTabview( self.project_frame, height=40, @@ -196,12 +198,12 @@ class NexusLauncher(ctk.CTk): self.tabview.set("Project") def _create_project_tab(self): - """创建Project标签页""" + """Create Project tab""" self.project_tab = self.tabview.add("Project") self.project_tab.grid_columnconfigure(0, weight=1) self.project_tab.grid_rowconfigure(0, weight=1) - # 使用ProjectPanel + # Use ProjectPanel self.project_panel = ProjectPanel( self.project_tab, self.config_manager, @@ -211,48 +213,48 @@ class NexusLauncher(ctk.CTk): ) self.project_panel.grid(row=0, column=0, sticky="nsew", padx=5, pady=5) - # 设置图标大小 + # Set icon size self.project_panel.set_icon_size(self.icon_size) - # 初始化项目背景颜色 + # Initialize project background color self._update_project_background() def _create_task_tab(self): - """创建Task标签页""" + """Create Task tab""" self.task_tab = self.tabview.add("Task") self.task_tab.grid_columnconfigure(0, weight=1) self.task_tab.grid_rowconfigure(0, weight=1) - # 使用TaskPanel + # Using TaskPanel self.task_panel = TaskPanel(self.task_tab, self.config_manager, fg_color=COLOR_TRANSPARENT) self.task_panel.grid(row=0, column=0, sticky="nsew", padx=5, pady=5) - # 初始化项目颜色 + # Initialize project colors self._update_task_colors() def _bind_events(self): - """绑定事件""" + """Binding events""" self.project_combo.bind("", self._on_combo_click, add="+") self.bind_all("", self._on_zoom, add="+") self.bind("", self._on_window_resize) def _initialize_ui(self): - """初始化UI""" + """Initialize UI""" self.after(100, lambda: UIHelpers.adjust_tab_button_width(self.tabview)) self.after(150, self._configure_tab_style) self.after(200, lambda: UIHelpers.fix_dropdown_width(self.project_combo)) - self.after(250, self._update_tab_appearance) # 延迟更新标签页外观,确保UI完全初始化 + self.after(250, self._update_tab_appearance) # Delay updating the tab appearance to ensure the UI is fully initialized. self._update_project_list() - # 初始化Project标签页内容 + # Initialize Project tab content self.after(300, self.project_panel.refresh) - # 关闭启动画面 + # Close the startup screen if self.splash: self.after(350, self._close_splash) def _close_splash(self): - """关闭启动画面""" + """Close the startup screen""" if self.splash: try: self.splash.close() @@ -261,15 +263,15 @@ class NexusLauncher(ctk.CTk): pass def _configure_tab_style(self): - """配置标签页样式""" + """Configure tab styles""" UIHelpers.configure_tab_transparency(self.project_tab, self.task_tab) def _on_combo_click(self, event): - """下拉框点击事件""" + """Drop-down click event""" self.after(1, lambda: UIHelpers.fix_dropdown_width(self.project_combo)) def _on_tab_changed(self): - """标签页切换事件""" + """Tab switching event""" current_tab = self.tabview.get() self._log(f"Switched to tab: {current_tab}", "DEBUG") @@ -279,25 +281,25 @@ class NexusLauncher(ctk.CTk): self.project_panel.refresh() def _on_zoom(self, event): - """处理缩放事件""" - # 检查事件是否来自主窗口 + """Handling zoom events""" + # Check if the event originated from the main window. widget = event.widget if hasattr(widget, 'winfo_toplevel'): if widget.winfo_toplevel() != self: return - # 委托给project_panel处理 + # Delegate to project_panel return self.project_panel.handle_zoom(event) def _on_window_resize(self, event): - """窗口大小改变事件""" + """Window resize event""" if event.widget == self: if hasattr(self, '_resize_timer'): self.after_cancel(self._resize_timer) self._resize_timer = self.after(150, self._on_resize_complete) def _on_resize_complete(self): - """窗口调整完成后的处理""" + """Processing after window adjustment""" try: self.project_panel.on_window_resize() UIHelpers.adjust_tab_button_width(self.tabview) @@ -305,7 +307,7 @@ class NexusLauncher(ctk.CTk): self._log(f"Window adjustment handling failed: {e}", "WARNING") def _update_project_list(self): - """更新项目列表""" + """Update project list""" projects = self.config_manager.get_projects() if projects: self.project_combo.configure(values=projects) @@ -316,31 +318,31 @@ class NexusLauncher(ctk.CTk): self.project_combo.set(projects[0]) self.config_manager.set_current_project(projects[0]) else: - self.project_combo.configure(values=["无项目"]) - self.project_combo.set("无项目") + self.project_combo.configure(values=["No project"]) + self.project_combo.set("No project") def _on_project_changed(self, choice): - """项目切换事件""" + """Project Switching Event""" self.config_manager.set_current_project(choice) self._update_tab_appearance() self.project_panel.refresh() self.task_panel.refresh() def _update_tab_appearance(self): - """更新标签页外观""" + """Update tab appearance""" current_project = self.config_manager.get_current_project() if not current_project: return - # 更新背景颜色 + # Update background color self._update_project_background() self._update_task_colors() - # 更新标签页图标(包含高度设置) + # Update tab icons (including height settings). self.project_panel.update_tab_icon(self.tabview, current_project) def _update_project_background(self): - """更新project panel背景颜色""" + """Update project panel background color""" current_project = self.config_manager.get_current_project() if current_project: project_color = self.config_manager.get_project_color(current_project) @@ -350,7 +352,7 @@ class NexusLauncher(ctk.CTk): self.project_panel.update_background_color(project_color) def _update_task_colors(self): - """更新task panel颜色""" + """Update task panel colors""" current_project = self.config_manager.get_current_project() if current_project: project_color = self.config_manager.get_project_color(current_project) @@ -358,26 +360,75 @@ class NexusLauncher(ctk.CTk): self.task_panel.update_colors(project_color) def _open_settings(self): - """打开设置窗口""" - self.window_manager.log_with_timestamp("🔧 打开设置窗口") + """Open settings window""" + self.window_manager.log_with_timestamp("🔧 Open settings window") settings_window = SettingsWindow(self, self.config_manager, self._on_settings_updated) def _on_settings_updated(self): - """设置更新后的回调""" - self.window_manager.log_with_timestamp("🔄 设置已更新,重新加载应用") + """Set the callback after the update""" + self.window_manager.log_with_timestamp("🔄 Settings have been updated. Please reload the application.") self._update_project_list() self._update_tab_appearance() self.project_panel.refresh() def log(self, message: str): - """日志记录(委托给window_manager)""" + """Log recording (delegated to window_manager)""" self.window_manager.log(message) def main(): - """主函数""" - app = NexusLauncher() - app.mainloop() + """Main function""" + # Create a mutex lock to ensure that only one instance runs. + mutex_name = "Global\\NexusLauncher_SingleInstance_Mutex" + + try: + # Try to create a mutex lock + kernel32 = ctypes.windll.kernel32 + mutex = kernel32.CreateMutexW(None, False, mutex_name) + last_error = kernel32.GetLastError() + + # ERROR_ALREADY_EXISTS = 183 + if last_error == 183: + print("[INFO] NexusLauncher is already running and attempting to display the main window....") + # Try to find and activate an existing window. + try: + user32 = ctypes.windll.user32 + + # First try finding the window. + hwnd = user32.FindWindowW(None, "NexusLauncher") + + if hwnd: + # Show the window (whether it's hidden or minimized). + # SW_SHOW = 5, SW_RESTORE = 9 + user32.ShowWindow(hwnd, 9) # First restore + user32.ShowWindow(hwnd, 5) # Re-display + + # Bring the window to the foreground and activate it. + user32.SetForegroundWindow(hwnd) + user32.SetActiveWindow(hwnd) + + print("[INFO] The existing NexusLauncher window is now displayed.") + else: + print("[WARNING] NexusLauncher window handle not found") + print("[INFO] The program may run in the system tray; please open it from the tray menu.") + + except Exception as e: + print(f"[WARNING] Unable to activate an existing window: {e}") + print("[INFO] Please open NexusLauncher from the system tray.") + + sys.exit(0) + + # Launch application + app = NexusLauncher() + app.mainloop() + + # Release the mutex + if mutex: + kernel32.CloseHandle(mutex) + + except Exception as e: + print(f"[ERROR] Startup failed: {e}") + sys.exit(1) if __name__ == "__main__":