From 9e37d72071fd0dbe64ac67762251edd1c4c844ee Mon Sep 17 00:00:00 2001 From: Ixniy Evonniy Date: Wed, 1 Jul 2026 00:32:43 +0300 Subject: [PATCH] feat: animated connecting icon --- cache.db | Bin 32768 -> 32768 bytes main.jai | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++- win32.jai | 3 +++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/cache.db b/cache.db index 8e64342324fae99c1c9d5fa2c317ae0a1c5f1a9d..ad97aac8ec5232c8cd058098ef98191ec339c5b8 100644 GIT binary patch delta 58 zcmZo@U}|V!n&2Ry!T bool { app.singbox_job_handle = job; app.singbox_running = true; + app.is_connecting = true; + app.connecting_ticks = 0; + app.animation_frame = 0; + SetTimer(app.hwnd, TIMER_ANIMATION, 250, null); + if app.use_system_proxy { set_windows_system_proxy(true, tprint("127.0.0.1:%", app.port)); log_print("System proxy enabled on port %.\n", app.port); @@ -229,6 +247,9 @@ start_singbox :: (app: *App_State) -> bool { } stop_singbox :: (app: *App_State) { + app.is_connecting = false; + KillTimer(app.hwnd, TIMER_ANIMATION); + if !app.singbox_running return; TerminateProcess(app.singbox_process_handle, 0); @@ -279,7 +300,15 @@ check_process_status :: (app: *App_State) { } trigger_immediate_update :: (app: *App_State) { + app.is_updating = true; + app.animation_frame = 0; + SetTimer(app.hwnd, TIMER_ANIMATION, 150, null); + update_tray(app); + changed, success, err_msg := perform_update(); + + app.is_updating = false; + if success { if changed { log_print("Config updated, restarting Sing-box...\n"); @@ -293,10 +322,15 @@ trigger_immediate_update :: (app: *App_State) { } else { if !app.singbox_running { start_singbox(app); + } else { + KillTimer(app.hwnd, TIMER_ANIMATION); + update_tray(app); } MessageBoxW(app.hwnd, utf8_to_wide("Configuration is already up-to-date."), utf8_to_wide("Sing-box Tray"), MB_ICONINFORMATION); } } else { + KillTimer(app.hwnd, TIMER_ANIMATION); + update_tray(app); msg := tprint("Failed to download configuration.\nError: %", err_msg); MessageBoxW(app.hwnd, utf8_to_wide(msg), utf8_to_wide("Sing-box Tray"), MB_ICONERROR); } @@ -464,6 +498,22 @@ app_wnd_proc :: (hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESUL case WM_TIMER; { if wparam == TIMER_PROCESS_CHECK { check_process_status(app); + } else if wparam == TIMER_ANIMATION { + if app.is_connecting { + app.connecting_ticks += 1; + app.animation_frame = (app.animation_frame + 1) % 4; + update_tray(app); + + // Stop connecting animation after 12 ticks (3 seconds at 250ms) + if app.connecting_ticks >= 12 { + app.is_connecting = false; + KillTimer(hwnd, TIMER_ANIMATION); + update_tray(app); + } + } else if app.is_updating { + app.animation_frame = (app.animation_frame + 1) % 4; + update_tray(app); + } } return 0; } @@ -504,6 +554,10 @@ main :: () { app_state: App_State; app_state.icon_running = load_stock_icon(SIID_WORLD); app_state.icon_stopped = load_stock_icon(SIID_ERROR); + app_state.icon_frames[0] = load_stock_icon(SIID_SERVER); + app_state.icon_frames[1] = load_stock_icon(SIID_DRIVENET); + app_state.icon_frames[2] = load_stock_icon(SIID_WORLD); + app_state.icon_frames[3] = load_stock_icon(SIID_INTERNET); hwnd := CreateWindowExW( 0, @@ -593,4 +647,7 @@ main :: () { if app_state.icon_running DestroyIcon(app_state.icon_running); if app_state.icon_stopped DestroyIcon(app_state.icon_stopped); + for app_state.icon_frames { + if it DestroyIcon(it); + } } diff --git a/win32.jai b/win32.jai index 9d88e67..3c236af 100644 --- a/win32.jai +++ b/win32.jai @@ -207,8 +207,11 @@ SHSTOCKICONINFO :: struct { szPath: [260] u16; } +SIID_DRIVENET :: 9; SIID_WORLD :: 13; +SIID_SERVER :: 15; SIID_ERROR :: 80; +SIID_INTERNET :: 104; SHGSI_ICON :: 0x00000100; SHGSI_SMALLICON :: 0x00000001;