From 7eeb447a76b202d86e0b3dd760055648d7647e85 Mon Sep 17 00:00:00 2001 From: HonoLite <85190357+HonoLite@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:27:59 +0300 Subject: [PATCH] add windows autostart (#171) --- windows.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/windows.py b/windows.py index 94ea7b0..9310720 100644 --- a/windows.py +++ b/windows.py @@ -4,6 +4,7 @@ import ctypes import json import logging import os +import winreg import psutil import sys import threading @@ -34,6 +35,7 @@ DEFAULT_CONFIG = { "host": "127.0.0.1", "dc_ip": ["2:149.154.167.220", "4:149.154.167.220"], "verbose": False, + "autostart": False, } @@ -165,6 +167,61 @@ def setup_logging(verbose: bool = False): root.addHandler(ch) +def _autostart_reg_name() -> str: + return APP_NAME + + +def _autostart_command() -> str: + exe = sys.executable + return f'"{exe}"' + + +def is_autostart_enabled() -> bool: + try: + with winreg.OpenKey( + winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Run", + 0, + winreg.KEY_READ, + ) as k: + val, _ = winreg.QueryValueEx(k, _autostart_reg_name()) + stored = str(val).strip() + expected = _autostart_command().strip() + return stored == expected + except FileNotFoundError: + return False + except OSError: + return False + + +def set_autostart_enabled(enabled: bool) -> None: + try: + with winreg.CreateKey( + winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Run", + ) as k: + if enabled: + winreg.SetValueEx( + k, + _autostart_reg_name(), + 0, + winreg.REG_SZ, + _autostart_command(), + ) + else: + try: + winreg.DeleteValue(k, _autostart_reg_name()) + except FileNotFoundError: + pass + except OSError as exc: + log.error("Failed to update autostart: %s", exc) + _show_error( + "Не удалось изменить автозапуск.\n\n" + "Попробуйте запустить приложение от имени пользователя с правами на реестр.\n\n" + f"Ошибка: {exc}" + ) + + def _make_icon_image(size: int = 64): if Image is None: raise RuntimeError("Pillow is required for tray icon") @@ -327,7 +384,7 @@ def _edit_config_dialog(): TEXT_SECONDARY = "#707579" FONT_FAMILY = "Segoe UI" - w, h = 420, 480 + w, h = 420, 520 sw = root.winfo_screenwidth() sh = root.winfo_screenheight() root.geometry(f"{w}x{h}+{(sw-w)//2}+{(sh-h)//2}") @@ -378,6 +435,15 @@ def _edit_config_dialog(): corner_radius=6, border_width=2, border_color=FIELD_BORDER).pack(anchor="w", pady=(0, 8)) + # Autostart + autostart_var = ctk.BooleanVar(value=cfg.get("autostart", False)) + ctk.CTkCheckBox(frame, text="Автозапуск при включении Windows", + variable=autostart_var, font=(FONT_FAMILY, 13), + text_color=TEXT_PRIMARY, + fg_color=TG_BLUE, hover_color=TG_BLUE_HOVER, + corner_radius=6, border_width=2, + border_color=FIELD_BORDER).pack(anchor="w", pady=(0, 8)) + # Info label ctk.CTkLabel(frame, text="Изменения вступят в силу после перезапуска прокси.", font=(FONT_FAMILY, 11), text_color=TEXT_SECONDARY, @@ -413,11 +479,14 @@ def _edit_config_dialog(): "port": port_val, "dc_ip": lines, "verbose": verbose_var.get(), + "autostart": autostart_var.get(), } save_config(new_cfg) _config.update(new_cfg) log.info("Config saved: %s", new_cfg) + set_autostart_enabled(bool(new_cfg.get("autostart", False))) + _tray_icon.menu = _build_menu() from tkinter import messagebox @@ -661,6 +730,8 @@ def run_tray(): log.info("Config: %s", _config) log.info("Log file: %s", LOG_FILE) + set_autostart_enabled(bool(_config.get("autostart", False))) + if pystray is None or Image is None: log.error("pystray or Pillow not installed; " "running in console mode")