From 5587905329e1366aee17a1f41ba19b2927348db4 Mon Sep 17 00:00:00 2001 From: usamaiqb <83345144+usamaiqb@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:19:33 +0500 Subject: [PATCH 1/4] source code --- .claude/settings.local.json | 7 + src/main.rs | 1 + src/native_interop.rs | 1 + src/tray_icon.rs | 285 ++++++++++++++++++++++++++++++++++++ src/window.rs | 87 ++++++++++- 5 files changed, 378 insertions(+), 3 deletions(-) create mode 100644 .claude/settings.local.json create mode 100644 src/tray_icon.rs diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..2641db6 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(cargo build:*)" + ] + } +} diff --git a/src/main.rs b/src/main.rs index 23b9c92..88c363e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod models; mod native_interop; mod poller; mod theme; +mod tray_icon; mod updater; mod window; diff --git a/src/native_interop.rs b/src/native_interop.rs index 8e5c29f..9bccd18 100644 --- a/src/native_interop.rs +++ b/src/native_interop.rs @@ -22,6 +22,7 @@ pub const TIMER_UPDATE_CHECK: usize = 4; // Custom messages pub const WM_APP: u32 = 0x8000; pub const WM_APP_USAGE_UPDATED: u32 = WM_APP + 1; +pub const WM_APP_TRAY: u32 = WM_APP + 3; /// Get the taskbar window handle pub fn find_taskbar() -> Option { diff --git a/src/tray_icon.rs b/src/tray_icon.rs new file mode 100644 index 0000000..51f13ed --- /dev/null +++ b/src/tray_icon.rs @@ -0,0 +1,285 @@ +use windows::Win32::Foundation::*; +use windows::Win32::Graphics::Gdi::*; +use windows::Win32::UI::Shell::{ + NIF_ICON, NIF_MESSAGE, NIF_TIP, NIM_ADD, NIM_DELETE, NIM_MODIFY, NOTIFYICONDATAW, + Shell_NotifyIconW, +}; +use windows::Win32::UI::WindowsAndMessaging::*; +use windows::core::PCWSTR; + +use crate::native_interop::{self, Color, WM_APP_TRAY}; + +const TRAY_ICON_ID: u32 = 1; + +/// Menu item ID for toggling widget visibility (used by window.rs context menu). +pub const IDM_TOGGLE_WIDGET: u16 = 50; + +/// Actions the tray message handler can request from the main window. +pub enum TrayAction { + None, + ToggleWidget, + ShowContextMenu, +} + +/// Create a rounded-rectangle tray icon badge showing the usage percentage. +/// `percent` = None means "no data" (gray "?"), Some(p) is the usage level. +pub fn create_icon(percent: Option) -> HICON { + let size = 64_i32; + let margin = 4_i32; + let radius = 14_i32; + let outline = 2_i32; + + let (fill, outline_col, text_col) = match percent { + None => ( + Color::from_hex("#6c757d"), + Color::from_hex("#495057"), + Color::from_hex("#FFFFFF"), + ), + Some(p) if p < 50.0 => ( + Color::from_hex("#28a745"), + Color::from_hex("#1e7e34"), + Color::from_hex("#FFFFFF"), + ), + Some(p) if p < 75.0 => ( + Color::from_hex("#ffc107"), + Color::from_hex("#e0a800"), + Color::from_hex("#1a1a1a"), + ), + Some(p) if p < 90.0 => ( + Color::from_hex("#fd7e14"), + Color::from_hex("#d9650a"), + Color::from_hex("#FFFFFF"), + ), + _ => ( + Color::from_hex("#dc3545"), + Color::from_hex("#bd2130"), + Color::from_hex("#FFFFFF"), + ), + }; + + let display_text = match percent { + None => "?".to_string(), + Some(p) => format!("{}", p as u32), + }; + + let font_h = match display_text.len() { + 1 => -50, + 2 => -42, + _ => -30, + }; + + unsafe { + let screen_dc = GetDC(HWND::default()); + let mem_dc = CreateCompatibleDC(screen_dc); + + let bmi = BITMAPINFO { + bmiHeader: BITMAPINFOHEADER { + biSize: std::mem::size_of::() as u32, + biWidth: size, + biHeight: -size, + biPlanes: 1, + biBitCount: 32, + biCompression: 0, + ..Default::default() + }, + ..Default::default() + }; + + let mut bits: *mut std::ffi::c_void = std::ptr::null_mut(); + let dib = CreateDIBSection(mem_dc, &bmi, DIB_RGB_COLORS, &mut bits, None, 0) + .unwrap_or_default(); + + if dib.is_invalid() { + let _ = DeleteDC(mem_dc); + ReleaseDC(HWND::default(), screen_dc); + return HICON::default(); + } + + let old_bmp = SelectObject(mem_dc, dib); + + // Zero-fill (transparent background) + let pixel_data = + std::slice::from_raw_parts_mut(bits as *mut u32, (size * size) as usize); + for px in pixel_data.iter_mut() { + *px = 0; + } + + // Draw rounded rectangle badge + let null_pen = GetStockObject(NULL_PEN); + let old_pen = SelectObject(mem_dc, null_pen); + + // Outer rounded rect = outline colour + let br_outline = CreateSolidBrush(COLORREF(outline_col.to_colorref())); + let old_brush = SelectObject(mem_dc, br_outline); + let _ = RoundRect( + mem_dc, + margin, + margin, + size - margin + 1, + size - margin + 1, + radius * 2, + radius * 2, + ); + + // Inner rounded rect = fill colour + let br_fill = CreateSolidBrush(COLORREF(fill.to_colorref())); + SelectObject(mem_dc, br_fill); + let _ = RoundRect( + mem_dc, + margin + outline, + margin + outline, + size - margin - outline + 1, + size - margin - outline + 1, + (radius - 1) * 2, + (radius - 1) * 2, + ); + + SelectObject(mem_dc, old_brush); + SelectObject(mem_dc, old_pen); + let _ = DeleteObject(br_outline); + let _ = DeleteObject(br_fill); + + // Draw centered percentage text + let font_name = native_interop::wide_str("Arial Bold"); + let font = CreateFontW( + font_h, + 0, + 0, + 0, + FW_BOLD.0 as i32, + 0, + 0, + 0, + DEFAULT_CHARSET.0 as u32, + OUT_TT_PRECIS.0 as u32, + CLIP_DEFAULT_PRECIS.0 as u32, + ANTIALIASED_QUALITY.0 as u32, + (DEFAULT_PITCH.0 | FF_DONTCARE.0) as u32, + PCWSTR::from_raw(font_name.as_ptr()), + ); + let old_font = SelectObject(mem_dc, font); + let _ = SetBkMode(mem_dc, TRANSPARENT); + let _ = SetTextColor(mem_dc, COLORREF(text_col.to_colorref())); + + let mut text_rect = RECT { + left: margin, + top: margin, + right: size - margin, + bottom: size - margin, + }; + let mut text_wide: Vec = display_text.encode_utf16().collect(); + let _ = DrawTextW( + mem_dc, + &mut text_wide, + &mut text_rect, + DT_CENTER | DT_VCENTER | DT_SINGLELINE, + ); + + SelectObject(mem_dc, old_font); + let _ = DeleteObject(font); + + // Set alpha: non-zero BGR pixel -> fully opaque; background stays transparent + for px in pixel_data.iter_mut() { + if *px != 0 { + *px = (*px & 0x00FF_FFFF) | 0xFF00_0000; + } + } + + // Monochrome mask (per-pixel alpha from colour bitmap) + let mask_bytes = vec![0u8; ((size * size + 7) / 8) as usize]; + let mask_bmp = CreateBitmap( + size, + size, + 1, + 1, + Some(mask_bytes.as_ptr() as *const std::ffi::c_void), + ); + + let icon_info = ICONINFO { + fIcon: TRUE, + xHotspot: 0, + yHotspot: 0, + hbmMask: mask_bmp, + hbmColor: dib, + }; + let hicon = CreateIconIndirect(&icon_info).unwrap_or_default(); + + let _ = DeleteObject(mask_bmp); + SelectObject(mem_dc, old_bmp); + let _ = DeleteObject(dib); + let _ = DeleteDC(mem_dc); + ReleaseDC(HWND::default(), screen_dc); + + hicon + } +} + +/// Register the tray icon with the shell. +pub fn add(hwnd: HWND, percent: Option, tooltip: &str) { + let hicon = create_icon(percent); + unsafe { + let mut nid: NOTIFYICONDATAW = std::mem::zeroed(); + nid.cbSize = std::mem::size_of::() as u32; + nid.hWnd = hwnd; + nid.uID = TRAY_ICON_ID; + nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + nid.uCallbackMessage = WM_APP_TRAY; + nid.hIcon = hicon; + copy_to_tip(tooltip, &mut nid.szTip); + let _ = Shell_NotifyIconW(NIM_ADD, &nid); + if !hicon.is_invalid() { + let _ = DestroyIcon(hicon); + } + } +} + +/// Update the tray icon colour and tooltip to reflect current usage. +pub fn update(hwnd: HWND, percent: Option, tooltip: &str) { + let hicon = create_icon(percent); + unsafe { + let mut nid: NOTIFYICONDATAW = std::mem::zeroed(); + nid.cbSize = std::mem::size_of::() as u32; + nid.hWnd = hwnd; + nid.uID = TRAY_ICON_ID; + nid.uFlags = NIF_ICON | NIF_TIP; + nid.hIcon = hicon; + copy_to_tip(tooltip, &mut nid.szTip); + let _ = Shell_NotifyIconW(NIM_MODIFY, &nid); + if !hicon.is_invalid() { + let _ = DestroyIcon(hicon); + } + } +} + +/// Remove the tray icon from the shell. +pub fn remove(hwnd: HWND) { + unsafe { + let mut nid: NOTIFYICONDATAW = std::mem::zeroed(); + nid.cbSize = std::mem::size_of::() as u32; + nid.hWnd = hwnd; + nid.uID = TRAY_ICON_ID; + let _ = Shell_NotifyIconW(NIM_DELETE, &nid); + } +} + +/// Interpret a tray callback message and return the action to take. +pub fn handle_message(lparam: LPARAM) -> TrayAction { + let mouse_msg = lparam.0 as u32; + match mouse_msg { + WM_LBUTTONUP => TrayAction::ToggleWidget, + WM_RBUTTONUP => TrayAction::ShowContextMenu, + _ => TrayAction::None, + } +} + +/// Copy a string into the fixed-size szTip field (max 127 chars + null). +fn copy_to_tip(s: &str, tip: &mut [u16; 128]) { + let wide: Vec = s.encode_utf16().collect(); + let mut len = wide.len().min(127); + // Don't leave a lone high surrogate at the truncation point + if len > 0 && (0xD800..=0xDBFF).contains(&wide[len - 1]) { + len -= 1; + } + tip[..len].copy_from_slice(&wide[..len]); + tip[len] = 0; +} diff --git a/src/window.rs b/src/window.rs index 7d76600..0ec8670 100644 --- a/src/window.rs +++ b/src/window.rs @@ -20,8 +20,9 @@ use crate::localization::{self, LanguageId, Strings}; use crate::models::UsageData; use crate::native_interop::{ self, Color, TIMER_COUNTDOWN, TIMER_POLL, TIMER_RESET_POLL, TIMER_UPDATE_CHECK, - WM_APP_USAGE_UPDATED, + WM_APP_TRAY, WM_APP_USAGE_UPDATED, }; +use crate::tray_icon; use crate::poller; use crate::theme; use crate::updater::{self, InstallChannel, ReleaseDescriptor, UpdateCheckResult}; @@ -70,6 +71,8 @@ struct AppState { dragging: bool, drag_start_mouse_x: i32, drag_start_offset: i32, + + widget_visible: bool, } #[derive(Clone, Debug)] @@ -159,6 +162,8 @@ struct SettingsFile { language: Option, #[serde(default, skip_serializing_if = "Option::is_none")] last_update_check_unix: Option, + #[serde(default = "default_widget_visible")] + widget_visible: bool, } impl Default for SettingsFile { @@ -168,6 +173,7 @@ impl Default for SettingsFile { poll_interval_ms: default_poll_interval(), language: None, last_update_check_unix: None, + widget_visible: true, } } } @@ -176,6 +182,10 @@ fn default_poll_interval() -> u32 { POLL_15_MIN } +fn default_widget_visible() -> bool { + true +} + fn load_settings() -> SettingsFile { let content = match std::fs::read_to_string(settings_path()) { Ok(c) => c, @@ -204,10 +214,44 @@ fn save_state_settings() { .language_override .map(|language| language.code().to_string()), last_update_check_unix: s.last_update_check_unix, + widget_visible: s.widget_visible, }); } } +fn tray_icon_data_from_state() -> (Option, String) { + let state = lock_state(); + match state.as_ref() { + Some(s) if s.last_poll_ok => { + let tooltip = format!("5h: {} | 7d: {}", s.session_text, s.weekly_text); + (Some(s.session_percent), tooltip) + } + _ => (None, "Claude Code Usage Monitor".to_string()), + } +} + +fn toggle_widget_visibility(hwnd: HWND) { + let new_visible = { + let mut state = lock_state(); + if let Some(s) = state.as_mut() { + s.widget_visible = !s.widget_visible; + s.widget_visible + } else { + return; + } + }; + save_state_settings(); + unsafe { + if new_visible { + position_at_taskbar(); + let _ = ShowWindow(hwnd, SW_SHOWNOACTIVATE); + render_layered(); + } else { + let _ = ShowWindow(hwnd, SW_HIDE); + } + } +} + fn now_unix_secs() -> u64 { SystemTime::now() .duration_since(UNIX_EPOCH) @@ -768,6 +812,7 @@ pub fn run() { dragging: false, drag_start_mouse_x: 0, drag_start_offset: 0, + widget_visible: settings.widget_visible, }); } @@ -818,9 +863,15 @@ pub fn run() { ); } - // Position and show + // Register system tray icon + let (tray_pct, tray_tooltip) = tray_icon_data_from_state(); + tray_icon::add(hwnd, tray_pct, &tray_tooltip); + + // Position and show (only if widget_visible preference is true) position_at_taskbar(); - let _ = ShowWindow(hwnd, SW_SHOWNOACTIVATE); + if settings.widget_visible { + let _ = ShowWindow(hwnd, SW_SHOWNOACTIVATE); + } diagnose::log("window shown"); // Initial render via UpdateLayeredWindow (for embedded) or InvalidateRect (fallback) @@ -1458,6 +1509,8 @@ unsafe extern "system" fn wnd_proc( check_language_change(); render_layered(); schedule_countdown_timer(); + let (pct, tooltip) = tray_icon_data_from_state(); + tray_icon::update(hwnd, pct, &tooltip); LRESULT(0) } WM_APP_UPDATE_CHECK_COMPLETE => { @@ -1736,10 +1789,25 @@ unsafe extern "system" fn wnd_proc( save_state_settings(); render_layered(); } + id if id == tray_icon::IDM_TOGGLE_WIDGET => { + toggle_widget_visibility(hwnd); + } _ => {} } LRESULT(0) } + _ if msg == WM_APP_TRAY => { + match tray_icon::handle_message(lparam) { + tray_icon::TrayAction::ToggleWidget => { + toggle_widget_visibility(hwnd); + } + tray_icon::TrayAction::ShowContextMenu => { + show_context_menu(hwnd); + } + tray_icon::TrayAction::None => {} + } + LRESULT(0) + } WM_DESTROY => { let hook = { let state = lock_state(); @@ -1748,6 +1816,7 @@ unsafe extern "system" fn wnd_proc( if let Some(h) = hook { native_interop::unhook_win_event(h); } + tray_icon::remove(hwnd); PostQuitMessage(0); LRESULT(0) } @@ -1764,6 +1833,7 @@ fn show_context_menu(hwnd: HWND) { language_override, install_channel, update_status, + widget_visible, ) = { let state = lock_state(); match state.as_ref() { @@ -1774,6 +1844,7 @@ fn show_context_menu(hwnd: HWND) { s.language_override, s.install_channel, s.update_status.clone(), + s.widget_visible, ), None => ( POLL_15_MIN, @@ -1782,6 +1853,7 @@ fn show_context_menu(hwnd: HWND) { None, InstallChannel::Portable, UpdateStatus::Idle, + true, ), } }; @@ -1921,6 +1993,15 @@ fn show_context_menu(hwnd: HWND) { PCWSTR::from_raw(settings_label.as_ptr()), ); + let widget_label = native_interop::wide_str("Show Widget"); + let widget_flags = if widget_visible { MF_CHECKED } else { MENU_ITEM_FLAGS(0) }; + let _ = AppendMenuW( + menu, + widget_flags, + tray_icon::IDM_TOGGLE_WIDGET as usize, + PCWSTR::from_raw(widget_label.as_ptr()), + ); + let _ = AppendMenuW(menu, MF_SEPARATOR, 0, PCWSTR::null()); let exit_str = native_interop::wide_str(strings.exit); From 451c205de4cc13e70e417828a1568528d5e53b97 Mon Sep 17 00:00:00 2001 From: usamaiqb <83345144+usamaiqb@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:42:13 +0500 Subject: [PATCH 2/4] update readme --- README.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4490432..ff3d317 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ It sits in your taskbar and shows how much of your Claude Code usage window you - A **7d** bar for your current 7-day window - A live countdown until each limit resets - A small native widget that lives directly in the Windows taskbar +- A **system tray icon** showing your usage percentage as a color-coded badge +- Left-click the tray icon to toggle the taskbar widget on or off - Right-click options for refresh, update frequency, language, startup, and updates ## Who This Is For @@ -48,12 +50,27 @@ After installing with WinGet, run: claude-code-usage-monitor ``` -Once running, it will appear in your taskbar. +Once running, it will appear in your taskbar and as a tray icon in the notification area. -- Drag the left divider to move it -- Right-click for refresh, update frequency, Start with Windows, reset position, language, updates, and exit +- Drag the left divider to move the taskbar widget +- Right-click the taskbar widget or tray icon for refresh, update frequency, Start with Windows, reset position, language, updates, and exit +- Left-click the tray icon to toggle the taskbar widget on or off - Enable `Start with Windows` from the right-click menu if you want it to launch automatically when you sign in +### System Tray Icon + +The tray icon shows your current 5-hour usage as a color-coded percentage badge: + +| Color | Meaning | +|--------|-------------------| +| Green | Under 50% used | +| Yellow | 50–75% used | +| Orange | 75–90% used | +| Red | 90% or more used | +| Gray | No data available | + +Hovering over the tray icon shows a tooltip with both your 5h and 7d usage. + ## Diagnostics If you need to troubleshoot startup or visibility issues, run: From 40d3d1f7e1e1d831cf4b030cd871ba789ca4edb5 Mon Sep 17 00:00:00 2001 From: usamaiqb <83345144+usamaiqb@users.noreply.github.com> Date: Sat, 28 Mar 2026 12:46:02 +0500 Subject: [PATCH 3/4] misc --- .claude/settings.local.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json deleted file mode 100644 index 2641db6..0000000 --- a/.claude/settings.local.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(cargo build:*)" - ] - } -} From 77bd36d3e0719c011fdee83cdcef2962bacc4c47 Mon Sep 17 00:00:00 2001 From: Craig Constable Date: Tue, 31 Mar 2026 08:00:25 +1000 Subject: [PATCH 4/4] Prepare 1.2.11 changes on pr-6 --- .github/animation.gif | Bin 0 -> 95437 bytes .github/screenshot.png | Bin 12293 -> 0 bytes Cargo.lock | 2 +- Cargo.toml | 6 +- README.md | 2 +- src/tray_icon.rs | 137 ++++++++++++++++++++++++++--------------- src/window.rs | 68 +++++++++++++++++--- 7 files changed, 151 insertions(+), 64 deletions(-) create mode 100644 .github/animation.gif delete mode 100644 .github/screenshot.png diff --git a/.github/animation.gif b/.github/animation.gif new file mode 100644 index 0000000000000000000000000000000000000000..a95fd26bd15849e9f0d9c2a8929c764ac5df3b52 GIT binary patch literal 95437 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 diff --git a/Cargo.lock b/Cargo.lock index 214df5d..c537015 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,7 +38,7 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "claude-code-usage-monitor" -version = "1.2.9" +version = "1.2.11" dependencies = [ "dirs", "native-tls", diff --git a/Cargo.toml b/Cargo.toml index 2bbc81f..71ac04f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "claude-code-usage-monitor" -version = "1.2.9" +version = "1.2.11" edition = "2021" license = "MIT" -description = "Windows taskbar widget for monitoring Claude Code usage and rate limits" +description = "Claude Code Usage Monitor" homepage = "https://codezeno.com.au" repository = "https://github.com/CodeZeno/Claude-Code-Usage-Monitor" [package.metadata.winres] CompanyName = "Code Zeno Pty Ltd" ProductName = "Claude Code Usage Monitor" -FileDescription = "Windows taskbar widget for monitoring Claude Code usage and rate limits" +FileDescription = "Claude Code Usage Monitor" OriginalFilename = "claude-code-usage-monitor.exe" InternalName = "ClaudeCodeUsageMonitor" Comments = "https://codezeno.com.au" diff --git a/README.md b/README.md index ff3d317..5a28eda 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ It sits in your taskbar and shows how much of your Claude Code usage window you ![Windows](https://img.shields.io/badge/platform-Windows-blue) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -![Screenshot](.github/screenshot.png) +![Screenshot](.github/animation.gif) ## What You Get diff --git a/src/tray_icon.rs b/src/tray_icon.rs index 51f13ed..1fc2593 100644 --- a/src/tray_icon.rs +++ b/src/tray_icon.rs @@ -1,8 +1,9 @@ use windows::Win32::Foundation::*; use windows::Win32::Graphics::Gdi::*; +use windows::Win32::System::LibraryLoader::GetModuleFileNameW; use windows::Win32::UI::Shell::{ - NIF_ICON, NIF_MESSAGE, NIF_TIP, NIM_ADD, NIM_DELETE, NIM_MODIFY, NOTIFYICONDATAW, - Shell_NotifyIconW, + ExtractIconExW, NIF_ICON, NIF_MESSAGE, NIF_TIP, NIM_ADD, NIM_DELETE, NIM_MODIFY, + NOTIFYICONDATAW, Shell_NotifyIconW, }; use windows::Win32::UI::WindowsAndMessaging::*; use windows::core::PCWSTR; @@ -21,45 +22,65 @@ pub enum TrayAction { ShowContextMenu, } +fn lerp_channel(start: u8, end: u8, t: f64) -> u8 { + (start as f64 + (end as f64 - start as f64) * t.clamp(0.0, 1.0)).round() as u8 +} + +fn lerp_color(start: Color, end: Color, t: f64) -> Color { + Color::new( + lerp_channel(start.r, end.r, t), + lerp_channel(start.g, end.g, t), + lerp_channel(start.b, end.b, t), + ) +} + +fn interpolated_fill(percent: f64) -> Color { + if percent <= 50.0 { + return Color::from_hex("#D97757"); + } + + let stops = [ + (50.0, Color::from_hex("#D97757")), + (70.0, Color::from_hex("#D08540")), + (85.0, Color::from_hex("#CC8C20")), + (95.0, Color::from_hex("#C45020")), + (100.0, Color::from_hex("#B82020")), + ]; + + for pair in stops.windows(2) { + let (start_pct, start_color) = pair[0]; + let (end_pct, end_color) = pair[1]; + if percent <= end_pct { + let span = (end_pct - start_pct).max(f64::EPSILON); + let t = (percent - start_pct) / span; + return lerp_color(start_color, end_color, t); + } + } + + stops[stops.len() - 1].1 +} + /// Create a rounded-rectangle tray icon badge showing the usage percentage. -/// `percent` = None means "no data" (gray "?"), Some(p) is the usage level. +/// `percent` = None means "no data/loading" and uses the embedded app icon. pub fn create_icon(percent: Option) -> HICON { + if percent.is_none() { + let app_icon = load_embedded_app_icon(); + if !app_icon.is_invalid() { + return app_icon; + } + } + let size = 64_i32; - let margin = 4_i32; - let radius = 14_i32; - let outline = 2_i32; - - let (fill, outline_col, text_col) = match percent { - None => ( - Color::from_hex("#6c757d"), - Color::from_hex("#495057"), - Color::from_hex("#FFFFFF"), - ), - Some(p) if p < 50.0 => ( - Color::from_hex("#28a745"), - Color::from_hex("#1e7e34"), - Color::from_hex("#FFFFFF"), - ), - Some(p) if p < 75.0 => ( - Color::from_hex("#ffc107"), - Color::from_hex("#e0a800"), - Color::from_hex("#1a1a1a"), - ), - Some(p) if p < 90.0 => ( - Color::from_hex("#fd7e14"), - Color::from_hex("#d9650a"), - Color::from_hex("#FFFFFF"), - ), - _ => ( - Color::from_hex("#dc3545"), - Color::from_hex("#bd2130"), - Color::from_hex("#FFFFFF"), - ), - }; + let margin = 0_i32; + let radius = 2_i32; + let outline = 0_i32; + + let fill = interpolated_fill(percent.unwrap_or(0.0)); + let text_col = Color::from_hex("#FFFFFF"); let display_text = match percent { - None => "?".to_string(), Some(p) => format!("{}", p as u32), + None => String::new(), }; let font_h = match display_text.len() { @@ -108,22 +129,9 @@ pub fn create_icon(percent: Option) -> HICON { let null_pen = GetStockObject(NULL_PEN); let old_pen = SelectObject(mem_dc, null_pen); - // Outer rounded rect = outline colour - let br_outline = CreateSolidBrush(COLORREF(outline_col.to_colorref())); - let old_brush = SelectObject(mem_dc, br_outline); - let _ = RoundRect( - mem_dc, - margin, - margin, - size - margin + 1, - size - margin + 1, - radius * 2, - radius * 2, - ); - - // Inner rounded rect = fill colour + // Fill rounded rect let br_fill = CreateSolidBrush(COLORREF(fill.to_colorref())); - SelectObject(mem_dc, br_fill); + let old_brush = SelectObject(mem_dc, br_fill); let _ = RoundRect( mem_dc, margin + outline, @@ -136,7 +144,6 @@ pub fn create_icon(percent: Option) -> HICON { SelectObject(mem_dc, old_brush); SelectObject(mem_dc, old_pen); - let _ = DeleteObject(br_outline); let _ = DeleteObject(br_fill); // Draw centered percentage text @@ -214,6 +221,34 @@ pub fn create_icon(percent: Option) -> HICON { } } +fn load_embedded_app_icon() -> HICON { + unsafe { + let mut exe_buf = [0u16; 260]; + let len = GetModuleFileNameW(None, &mut exe_buf) as usize; + if len == 0 { + return HICON::default(); + } + + let mut small_icon = HICON::default(); + let mut large_icon = HICON::default(); + let extracted = ExtractIconExW( + PCWSTR::from_raw(exe_buf.as_ptr()), + 0, + Some(&mut large_icon), + Some(&mut small_icon), + 1, + ); + + if extracted == 0 { + HICON::default() + } else if !small_icon.is_invalid() { + small_icon + } else { + large_icon + } + } +} + /// Register the tray icon with the shell. pub fn add(hwnd: HWND, percent: Option, tooltip: &str) { let hicon = create_icon(percent); diff --git a/src/window.rs b/src/window.rs index 0ec8670..c094127 100644 --- a/src/window.rs +++ b/src/window.rs @@ -13,6 +13,7 @@ use windows::Win32::System::Threading::CreateMutexW; use windows::Win32::UI::Accessibility::HWINEVENTHOOK; use windows::Win32::UI::HiDpi::*; use windows::Win32::UI::Input::KeyboardAndMouse::{ReleaseCapture, SetCapture}; +use windows::Win32::UI::Shell::ExtractIconExW; use windows::Win32::UI::WindowsAndMessaging::*; use crate::diagnose; @@ -136,6 +137,32 @@ fn refresh_dpi() { } } +fn load_embedded_app_icons() -> (HICON, HICON) { + unsafe { + let mut exe_buf = [0u16; 260]; + let len = GetModuleFileNameW(None, &mut exe_buf) as usize; + if len == 0 { + return (HICON::default(), HICON::default()); + } + + let mut large_icon = HICON::default(); + let mut small_icon = HICON::default(); + let extracted = ExtractIconExW( + PCWSTR::from_raw(exe_buf.as_ptr()), + 0, + Some(&mut large_icon), + Some(&mut small_icon), + 1, + ); + + if extracted == 0 { + (HICON::default(), HICON::default()) + } else { + (large_icon, small_icon) + } + } +} + unsafe impl Send for AppState {} static STATE: Mutex> = Mutex::new(None); @@ -742,12 +769,15 @@ pub fn run() { unsafe { let hinstance = GetModuleHandleW(PCWSTR::null()).unwrap(); + let (large_icon, small_icon) = load_embedded_app_icons(); let wc = WNDCLASSEXW { cbSize: std::mem::size_of::() as u32, style: CS_HREDRAW | CS_VREDRAW, lpfnWndProc: Some(wnd_proc), hInstance: HINSTANCE(hinstance.0), + hIcon: large_icon, + hIconSm: small_icon, hCursor: LoadCursorW(HINSTANCE::default(), IDC_ARROW).unwrap_or_default(), hbrBackground: HBRUSH(std::ptr::null_mut()), lpszClassName: PCWSTR::from_raw(class_name.as_ptr()), @@ -781,6 +811,24 @@ pub fn run() { None, ) .unwrap(); + + if !large_icon.is_invalid() { + let _ = SendMessageW( + hwnd, + WM_SETICON, + WPARAM(ICON_BIG as usize), + LPARAM(large_icon.0 as isize), + ); + } + if !small_icon.is_invalid() { + let _ = SendMessageW( + hwnd, + WM_SETICON, + WPARAM(ICON_SMALL as usize), + LPARAM(small_icon.0 as isize), + ); + } + diagnose::log(format!("main window created hwnd={:?}", hwnd)); let is_dark = theme::is_dark_mode(); @@ -1374,18 +1422,18 @@ fn position_at_taskbar() { let widget_width = total_widget_width(); let widget_height = sc(WIDGET_HEIGHT); + let y = compute_anchor_y(anchor_top, anchor_height, widget_height); if embedded { // Child window: coordinates relative to parent (taskbar) let x = tray_left - taskbar_rect.left - widget_width - tray_offset; - let y = (anchor_top - taskbar_rect.top) + (anchor_height - widget_height) / 2; - native_interop::move_window(hwnd, x, y, widget_width, widget_height); + native_interop::move_window(hwnd, x, y - taskbar_rect.top, widget_width, widget_height); diagnose::log(format!( - "positioned embedded widget at x={x} y={y} w={widget_width} h={widget_height}" + "positioned embedded widget at x={x} y={} w={widget_width} h={widget_height}", + y - taskbar_rect.top )); } else { // Topmost popup: screen coordinates let x = tray_left - widget_width - tray_offset; - let y = anchor_top + (anchor_height - widget_height) / 2; native_interop::move_window(hwnd, x, y, widget_width, widget_height); diagnose::log(format!( "positioned fallback widget at x={x} y={y} w={widget_width} h={widget_height}" @@ -1393,6 +1441,12 @@ fn position_at_taskbar() { } } +fn compute_anchor_y(anchor_top: i32, anchor_height: i32, widget_height: i32) -> i32 { + let anchor_bottom = anchor_top + anchor_height; + let bottom_padding = (anchor_height - widget_height).clamp(0, sc(6)); + (anchor_bottom - widget_height - bottom_padding).max(anchor_top) +} + /// WinEvent callback for tray icon location changes unsafe extern "system" fn on_tray_location_changed( _hook: HWINEVENTHOOK, @@ -1627,20 +1681,18 @@ unsafe extern "system" fn wnd_proc( } let widget_width = total_widget_width(); let widget_height = sc(WIDGET_HEIGHT); + let y = compute_anchor_y(anchor_top, anchor_height, widget_height); if s.embedded { let x = tray_left - taskbar_rect.left - widget_width - new_offset; - let y = - (anchor_top - taskbar_rect.top) + (anchor_height - widget_height) / 2; native_interop::move_window( hwnd_val, x, - y, + y - taskbar_rect.top, widget_width, widget_height, ); } else { let x = tray_left - widget_width - new_offset; - let y = anchor_top + (anchor_height - widget_height) / 2; native_interop::move_window( hwnd_val, x,