# Planning: Sing-box Windows Tray Controller in Jai We will implement a lightweight, headless Windows tray application in the **Jai** language to control the `sing-box` core. ## 1. Core Architecture The application will run with a hidden/message-only window to remain headless, handling tray interaction, background updates, and process management. ```mermaid graph TD A[Main Loop / Hidden Window] --> B[System Tray Icon] B -->|Right Click| C[Context Menu] C -->|Set URL| D[Custom Edit Dialog] C -->|Start/Stop| E[Process Manager: sing-box.exe] C -->|Update Now| F[Auto-Update Loop: WinINet] C -->|Exit| G[Shutdown & Cleanup] F -->|Timer/Thread| F ``` ## 2. Component Design ### A. Headless Window & System Tray Icon - **Win32 Window**: We register a window class and create a hidden utility window using `CreateWindowExW`. This window serves as the message receiver. - **Tray Icon**: We register a system tray icon via `Shell_NotifyIconW` (using `NOTIFYICONDATAW`). - **Events**: We define a custom window message `WM_TRAY_CALLBACK` (`WM_USER + 1`). When the tray icon receives input (e.g. mouse clicks), Windows sends `WM_TRAY_CALLBACK` to our hidden window. - **Context Menu**: On `WM_RBUTTONUP` (right click) or `WM_LBUTTONUP` (left click) over the tray icon, we load a dynamic popup menu using `CreatePopupMenu`, `AppendMenuW`, and `TrackPopupMenu`. ### B. Custom Modal Dialog (Set URL) To avoid needing an external resource compiler (`.rc`) or complex UI libraries, we will implement a clean, lightweight modal window: - **Dialog Window**: A popup window using `WS_POPUP | WS_CAPTION | WS_SYSMENU` centered on screen. - **Controls**: - A static label: "Enter Sing-box Config URL:" - An edit control (`EDIT` window class) to input the URL. - An OK button and a Cancel button (`BUTTON` window class). - **Behavior**: Block interactions with other menus, read the edit text on OK, write it to a `url.txt` file, and trigger an immediate config update. ### C. Config Downloader (Auto-Update Engine) - **Downloader**: Use the Windows WinINet API to perform HTTP/HTTPS requests. - **Storage**: Save the downloaded JSON content to `config.json` in the same directory as the executable. - **Auto-Update Thread**: Spawn a background thread (using `Thread` module) that sleeps for a set interval (e.g., 1 hour), then downloads the URL. If the file content changes, it updates `config.json` and restarts the `sing-box` process if it was running. ### D. Process Management (`sing-box.exe`) - **Process Spawning**: Use the standard `Process` module's `create_process` to run: `sing-box.exe run -c config.json` - **Job Object**: Windows processes started via `create_process` will be assigned to a Job Object with `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`. This ensures `sing-box.exe` automatically shuts down when the controller application is closed. - **Status Checking**: Use `get_process_result` with 0 timeout to check if sing-box is actively running. ## 3. Implementation Steps 1. **`main.jai`**: Core application entry point, hidden window loop, tray icon management. 2. **`dialog.jai`**: Edit-box dialog for config URL input. 3. **`updater.jai`**: WinINet HTTP/HTTPS client and background auto-update thread. 4. **`build.jai`**: Jai build script (metaprogram) to compile the app without standard console window popup (using `-subsystem windows`). ## 4. Key Questions & Decisions - **Tray Icon**: Do we need a default/builtin icon? Yes, we will use a standard Windows system icon (like `IDI_APPLICATION` or `IDI_SHIELD`) so that the application works out-of-the-box without requiring an external `.ico` asset. - **sing-box Location**: We will assume `sing-box.exe` is in the same directory as the controller. If not found there, we will search the system PATH.