refactor: read display flags from state for merge compatibility

Revert shared window.rs/poller.rs signatures to base. Detailed-remaining is
read from a lock-free poller atomic (countdown formatting) and a shared
window-level text-width slot (layout). The slot mechanism block is identical
to the ETD branch's so any merge subset stays conflict-free; each branch wires
only its own slot. Relocate the localization field to a distinct anchor (after
exit).
This commit is contained in:
Carlos Miguel C. Resurreccion 2026-06-19 20:10:20 +08:00
parent fd94e91612
commit 39a9166109
14 changed files with 111 additions and 84 deletions

View File

@ -59,8 +59,8 @@ Once running, it will appear in your taskbar and as one or more tray icons in th
- Drag the left divider to move the taskbar widget
- Right-click the taskbar widget or tray icon for refresh, displayed models, 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
- Enable `Show detailed remaining time` under right-click `Settings` to add minutes alongside hours (5h window) and hours alongside days (7d window)
- Enable `Start with Windows` from the right-click menu if you want it to launch automatically when you sign in
### Models

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Instellingen",
start_with_windows: "Opstarten met Windows",
reset_position: "Positie herstellen",
show_detailed_remaining: "Gedetailleerde resterende tijd tonen",
language: "Taal",
system_default: "Systeemstandaard",
check_for_updates: "Controleren op updates",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "Update beschikbaar",
update_prompt_now: "Versie {version} is beschikbaar. Wil je nu bijwerken?",
exit: "Afsluiten",
show_detailed_remaining: "Gedetailleerde resterende tijd tonen",
show_widget: "Widget tonen",
session_window: "5u",
weekly_window: "7d",

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Settings",
start_with_windows: "Start with Windows",
reset_position: "Reset Position",
show_detailed_remaining: "Show detailed remaining time",
language: "Language",
system_default: "System Default",
check_for_updates: "Check for Updates",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "Update available",
update_prompt_now: "Version {version} is available. Do you want to update now?",
exit: "Exit",
show_detailed_remaining: "Show detailed remaining time",
show_widget: "Show Widget",
session_window: "5h",
weekly_window: "7d",

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Paramètres",
start_with_windows: "Démarrer avec Windows",
reset_position: "Réinitialiser la position",
show_detailed_remaining: "Afficher le temps restant détaillé",
language: "Langue",
system_default: "Par défaut du système",
check_for_updates: "Vérifier les mises à jour",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "Mise à jour disponible",
update_prompt_now: "La version {version} est disponible. Voulez-vous mettre à jour maintenant ?",
exit: "Quitter",
show_detailed_remaining: "Afficher le temps restant détaillé",
show_widget: "Afficher le widget",
session_window: "5h",
weekly_window: "7d",

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Einstellungen",
start_with_windows: "Mit Windows starten",
reset_position: "Position zurücksetzen",
show_detailed_remaining: "Detaillierte Restzeit anzeigen",
language: "Sprache",
system_default: "Systemstandard",
check_for_updates: "Nach Updates suchen",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "Update verfügbar",
update_prompt_now: "Version {version} ist verfügbar. Möchten Sie jetzt aktualisieren?",
exit: "Beenden",
show_detailed_remaining: "Detaillierte Restzeit anzeigen",
show_widget: "Widget anzeigen",
session_window: "5h",
weekly_window: "7d",

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "設定",
start_with_windows: "Windows と同時に開始",
reset_position: "位置をリセット",
show_detailed_remaining: "残り時間を詳細表示",
language: "言語",
system_default: "システム既定",
check_for_updates: "更新を確認",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "更新が利用可能です",
update_prompt_now: "バージョン {version} が利用可能です。今すぐ更新しますか?",
exit: "終了",
show_detailed_remaining: "残り時間を詳細表示",
show_widget: "ウィジェットを表示",
session_window: "5h",
weekly_window: "7d",

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "설정",
start_with_windows: "Windows 시작 시 자동 실행",
reset_position: "위치 초기화",
show_detailed_remaining: "남은 시간 상세 표시",
language: "언어",
system_default: "시스템 기본값",
check_for_updates: "업데이트 확인",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "업데이트 사용 가능",
update_prompt_now: "버전 {version}을 사용할 수 있습니다. 지금 업데이트하시겠습니까?",
exit: "종료",
show_detailed_remaining: "남은 시간 상세 표시",
show_widget: "위젯 표시",
session_window: "5시간",
weekly_window: "7일",

View File

@ -150,7 +150,6 @@ pub struct Strings {
pub settings: &'static str,
pub start_with_windows: &'static str,
pub reset_position: &'static str,
pub show_detailed_remaining: &'static str,
pub language: &'static str,
pub system_default: &'static str,
pub check_for_updates: &'static str,
@ -165,6 +164,7 @@ pub struct Strings {
pub update_available: &'static str,
pub update_prompt_now: &'static str,
pub exit: &'static str,
pub show_detailed_remaining: &'static str,
pub show_widget: &'static str,
pub session_window: &'static str,
pub weekly_window: &'static str,

View File

@ -30,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "Atualização disponível",
update_prompt_now: "Versão {version} está disponível. Deseja atualizar agora?",
exit: "Sair",
show_detailed_remaining: "Mostrar tempo restante detalhado",
show_widget: "Exibir Widget",
session_window: "5h",
weekly_window: "7d",
@ -43,5 +44,4 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Erro de Autenticação do Codex",
codex_token_expired_body: "Execute 'codex' em um terminal e siga as instruções de login. Depois disso, atualize ou reinicie este aplicativo.",
codex_window_title: "Monitor de uso do Codex",
show_detailed_remaining: "Mostrar tempo restante detalhado",
};

View File

@ -30,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "Доступно обновление",
update_prompt_now: "Доступна версия {version}. Обновить сейчас?",
exit: "Выход",
show_detailed_remaining: "Показывать подробное оставшееся время",
show_widget: "Показать виджет",
session_window: "5ч",
weekly_window: "7д",
@ -43,5 +44,4 @@ pub(super) const STRINGS: Strings = Strings {
codex_token_expired_title: "Ошибка авторизации Codex",
codex_token_expired_body: "Запустите 'codex' в терминале и следуйте инструкциям для входа. После этого обновите или перезапустите приложение.",
codex_window_title: "Монитор использования Codex",
show_detailed_remaining: "Показывать подробное оставшееся время",
};

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "Configuración",
start_with_windows: "Iniciar con Windows",
reset_position: "Restablecer posición",
show_detailed_remaining: "Mostrar tiempo restante detallado",
language: "Idioma",
system_default: "Predeterminado del sistema",
check_for_updates: "Buscar actualizaciones",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "Actualización disponible",
update_prompt_now: "La versión {version} está disponible. ¿Quieres actualizar ahora?",
exit: "Salir",
show_detailed_remaining: "Mostrar tiempo restante detallado",
show_widget: "Mostrar widget",
session_window: "5h",
weekly_window: "7d",

View File

@ -16,7 +16,6 @@ pub(super) const STRINGS: Strings = Strings {
settings: "設定",
start_with_windows: "開機時啟動",
reset_position: "重置位置",
show_detailed_remaining: "顯示詳細剩餘時間",
language: "語言",
system_default: "系統預設",
check_for_updates: "檢查更新",
@ -31,6 +30,7 @@ pub(super) const STRINGS: Strings = Strings {
update_available: "有可用更新",
update_prompt_now: "版本 {version} 已可用。是否立即更新?",
exit: "結束",
show_detailed_remaining: "顯示詳細剩餘時間",
show_widget: "顯示小工具",
session_window: "5h",
weekly_window: "7d",

View File

@ -1,5 +1,6 @@
use std::path::PathBuf;
use std::process::Command;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use serde::Deserialize;
@ -1020,10 +1021,25 @@ fn is_leap(y: u64) -> bool {
(y % 4 == 0 && y % 100 != 0) || y % 400 == 0
}
/// Detailed remaining-time flag, mirrored from window state. Read lock-free
/// here so the countdown formatters (which run while the window state lock is
/// held) never re-lock shared state. Kept at base signatures so other features
/// that call these formatters stay source-compatible.
static DETAILED_REMAINING: AtomicBool = AtomicBool::new(false);
/// Update the detailed remaining-time flag the formatters read.
pub fn set_detailed_remaining(enabled: bool) {
DETAILED_REMAINING.store(enabled, Ordering::Relaxed);
}
fn detailed_remaining_enabled() -> bool {
DETAILED_REMAINING.load(Ordering::Relaxed)
}
/// Format a usage section as "X% · Yh" style text
pub fn format_line(section: &UsageSection, strings: Strings, detailed: bool) -> String {
pub fn format_line(section: &UsageSection, strings: Strings) -> String {
let pct = format!("{:.0}%", section.percentage);
let cd = format_countdown(section.resets_at, strings, detailed);
let cd = format_countdown(section.resets_at, strings);
if cd.is_empty() {
pct
} else {
@ -1031,7 +1047,7 @@ pub fn format_line(section: &UsageSection, strings: Strings, detailed: bool) ->
}
}
fn format_countdown(resets_at: Option<SystemTime>, strings: Strings, detailed: bool) -> String {
fn format_countdown(resets_at: Option<SystemTime>, strings: Strings) -> String {
let reset = match resets_at {
Some(t) => t,
None => return String::new(),
@ -1042,23 +1058,18 @@ fn format_countdown(resets_at: Option<SystemTime>, strings: Strings, detailed: b
Err(_) => return strings.now.to_string(),
};
format_countdown_from_secs(remaining.as_secs(), strings, detailed)
format_countdown_from_secs(remaining.as_secs(), strings)
}
/// Calculate how long until the display text would change
pub fn time_until_display_change(
resets_at: Option<SystemTime>,
detailed: bool,
) -> Option<Duration> {
pub fn time_until_display_change(resets_at: Option<SystemTime>) -> Option<Duration> {
let reset = resets_at?;
let remaining = reset.duration_since(SystemTime::now()).ok()?;
Some(time_until_display_change_from_secs(
remaining.as_secs(),
detailed,
))
Some(time_until_display_change_from_secs(remaining.as_secs()))
}
fn format_countdown_from_secs(total_secs: u64, strings: Strings, detailed: bool) -> String {
fn format_countdown_from_secs(total_secs: u64, strings: Strings) -> String {
let detailed = detailed_remaining_enabled();
let total_mins = total_secs / 60;
let total_hours = total_secs / 3600;
let total_days = total_secs / 86400;
@ -1090,7 +1101,8 @@ fn format_countdown_from_secs(total_secs: u64, strings: Strings, detailed: bool)
}
}
fn time_until_display_change_from_secs(total_secs: u64, detailed: bool) -> Duration {
fn time_until_display_change_from_secs(total_secs: u64) -> Duration {
let detailed = detailed_remaining_enabled();
let total_mins = total_secs / 60;
let total_hours = total_secs / 3600;
let total_days = total_secs / 86400;

View File

@ -1,5 +1,5 @@
use std::path::PathBuf;
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
use std::sync::{Mutex, MutexGuard};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
@ -421,22 +421,21 @@ fn refresh_usage_texts(state: &mut AppState) {
}
let strings = state.language.strings();
let detailed = state.show_detailed_remaining;
let Some(data) = state.data.as_ref() else {
return;
};
if let Some(claude_code) = data.claude_code.as_ref() {
state.session_text = poller::format_line(&claude_code.session, strings, detailed);
state.weekly_text = poller::format_line(&claude_code.weekly, strings, detailed);
state.session_text = poller::format_line(&claude_code.session, strings);
state.weekly_text = poller::format_line(&claude_code.weekly, strings);
} else if state.show_claude_code {
state.session_text = "!".to_string();
state.weekly_text = "!".to_string();
}
if let Some(codex) = data.codex.as_ref() {
state.codex_session_text = poller::format_line(&codex.session, strings, detailed);
state.codex_weekly_text = poller::format_line(&codex.weekly, strings, detailed);
state.codex_session_text = poller::format_line(&codex.session, strings);
state.codex_weekly_text = poller::format_line(&codex.weekly, strings);
} else if state.show_codex {
state.codex_session_text = "!".to_string();
state.codex_weekly_text = "!".to_string();
@ -834,12 +833,31 @@ fn active_model_count(show_claude_code: bool, show_codex: bool) -> i32 {
(show_claude_code as i32 + show_codex as i32).max(1)
}
fn text_width_for(detailed: bool) -> i32 {
if detailed {
TEXT_WIDTH_DETAILED
} else {
TEXT_WIDTH
}
// Optional display features may widen the usage text column. Each feature
// stores its own extra width (in base 96-DPI px) in a dedicated slot, read
// lock-free by the width/layout helpers below. Slots are summed so multiple
// features stack. This block is identical across the display-feature branches
// so they merge without conflict; a branch only wires up its own slot.
#[allow(dead_code)]
static EXTRA_TEXT_WIDTH_DETAILED: AtomicI32 = AtomicI32::new(0);
#[allow(dead_code)]
static EXTRA_TEXT_WIDTH_ETD: AtomicI32 = AtomicI32::new(0);
#[allow(dead_code)]
fn set_extra_text_width_detailed(px: i32) {
EXTRA_TEXT_WIDTH_DETAILED.store(px, Ordering::Relaxed);
}
#[allow(dead_code)]
fn set_extra_text_width_etd(px: i32) {
EXTRA_TEXT_WIDTH_ETD.store(px, Ordering::Relaxed);
}
/// Usage text-column width including any enabled display-feature widening.
fn effective_text_width() -> i32 {
TEXT_WIDTH
+ EXTRA_TEXT_WIDTH_DETAILED.load(Ordering::Relaxed)
+ EXTRA_TEXT_WIDTH_ETD.load(Ordering::Relaxed)
}
fn row_bar_segment_count(active_models: i32) -> i32 {
@ -850,11 +868,20 @@ fn row_bar_segment_count(active_models: i32) -> i32 {
}
}
fn total_widget_width_for(active_models: i32, detailed: bool) -> i32 {
/// Whether the detailed remaining-time display is enabled, read from shared
/// state. Returns false when state is not yet populated (startup) or the lock
/// cannot be acquired. Callers must not hold the state lock.
fn show_detailed_remaining_enabled() -> bool {
lock_state()
.as_ref()
.map_or(false, |s| s.show_detailed_remaining)
}
fn total_widget_width_for(active_models: i32) -> i32 {
let bar_segments = row_bar_segment_count(active_models);
let model_width = (sc(SEGMENT_W) + sc(SEGMENT_GAP)) * bar_segments - sc(SEGMENT_GAP)
+ sc(BAR_RIGHT_MARGIN)
+ sc(text_width_for(detailed));
+ sc(effective_text_width());
sc(LEFT_DIVIDER_W)
+ sc(DIVIDER_RIGHT_MARGIN)
@ -865,27 +892,15 @@ fn total_widget_width_for(active_models: i32, detailed: bool) -> i32 {
+ sc(RIGHT_MARGIN)
}
fn total_widget_width_for_state(state: &AppState) -> i32 {
total_widget_width_for(
active_model_count(state.show_claude_code, state.show_codex),
state.show_detailed_remaining,
)
}
fn total_widget_width() -> i32 {
let (active_models, detailed) = {
let active_models = {
let state = lock_state();
state
.as_ref()
.map(|s| {
(
active_model_count(s.show_claude_code, s.show_codex),
s.show_detailed_remaining,
)
})
.unwrap_or((1, false))
.map(|s| active_model_count(s.show_claude_code, s.show_codex))
.unwrap_or(1)
};
total_widget_width_for(active_models, detailed)
total_widget_width_for(active_models)
}
fn claude_accent_color() -> Color {
@ -986,7 +1001,7 @@ pub fn run() {
WS_POPUP,
0,
0,
total_widget_width_for(initial_model_count, settings.show_detailed_remaining),
total_widget_width_for(initial_model_count),
sc(WIDGET_HEIGHT),
HWND::default(),
HMENU::default(),
@ -1058,6 +1073,15 @@ pub fn run() {
});
}
// Mirror the detailed-remaining flag into the poller, which reads it
// lock-free while formatting countdowns (avoids re-locking shared state).
poller::set_detailed_remaining(settings.show_detailed_remaining);
set_extra_text_width_detailed(if settings.show_detailed_remaining {
TEXT_WIDTH_DETAILED - TEXT_WIDTH
} else {
0
});
// Try to embed in taskbar
if let Some(taskbar_hwnd) = native_interop::find_taskbar() {
diagnose::log(format!("taskbar found hwnd={:?}", taskbar_hwnd));
@ -1179,7 +1203,6 @@ fn render_layered() {
codex_weekly_text,
show_claude_code,
show_codex,
show_detailed_remaining,
) = {
let state = lock_state();
match state.as_ref() {
@ -1198,7 +1221,6 @@ fn render_layered() {
s.codex_weekly_text.clone(),
s.show_claude_code,
s.show_codex,
s.show_detailed_remaining,
),
None => return,
}
@ -1289,7 +1311,6 @@ fn render_layered() {
show_claude_code,
show_codex,
&codex_accent,
show_detailed_remaining,
);
// Background pixels → alpha 1 (nearly invisible but still hittable for right-click).
@ -1360,7 +1381,6 @@ fn paint_content(
show_claude_code: bool,
show_codex: bool,
codex_accent: &Color,
detailed: bool,
) {
unsafe {
let client_rect = RECT {
@ -1453,7 +1473,6 @@ fn paint_content(
accent,
codex_accent,
track,
detailed,
);
draw_row(
hdc,
@ -1471,7 +1490,6 @@ fn paint_content(
accent,
codex_accent,
track,
detailed,
);
SelectObject(hdc, old_font);
@ -1662,20 +1680,19 @@ fn schedule_countdown_timer() {
}
}
let detailed = s.show_detailed_remaining;
let delays = [
data.claude_code
.as_ref()
.and_then(|usage| poller::time_until_display_change(usage.session.resets_at, detailed)),
.and_then(|usage| poller::time_until_display_change(usage.session.resets_at)),
data.claude_code
.as_ref()
.and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at, detailed)),
.and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at)),
data.codex
.as_ref()
.and_then(|usage| poller::time_until_display_change(usage.session.resets_at, detailed)),
.and_then(|usage| poller::time_until_display_change(usage.session.resets_at)),
data.codex
.as_ref()
.and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at, detailed)),
.and_then(|usage| poller::time_until_display_change(usage.weekly.resets_at)),
];
let min_delay = delays.into_iter().flatten().min();
@ -2046,6 +2063,9 @@ unsafe extern "system" fn wnd_proc(
if is_dragging {
let mut pt = POINT::default();
let _ = GetCursorPos(&mut pt);
// Compute the widget width before locking; the width helpers read
// shared state themselves and must not run while the lock is held.
let widget_width = total_widget_width();
let move_target = {
let mut state = lock_state();
let s = match state.as_mut() {
@ -2079,7 +2099,6 @@ unsafe extern "system" fn wnd_proc(
tray_left = tray_rect.left;
}
}
let widget_width = total_widget_width_for_state(s);
let max_offset = (tray_left - taskbar_rect.left - widget_width).max(0);
if new_offset > max_offset {
new_offset = max_offset;
@ -2257,6 +2276,12 @@ unsafe extern "system" fn wnd_proc(
let mut state = lock_state();
if let Some(s) = state.as_mut() {
s.show_detailed_remaining = !s.show_detailed_remaining;
poller::set_detailed_remaining(s.show_detailed_remaining);
set_extra_text_width_detailed(if s.show_detailed_remaining {
TEXT_WIDTH_DETAILED - TEXT_WIDTH
} else {
0
});
refresh_usage_texts(s);
}
}
@ -2378,7 +2403,6 @@ fn show_context_menu(hwnd: HWND) {
widget_visible,
show_claude_code,
show_codex,
show_detailed_remaining,
) = {
let state = lock_state();
match state.as_ref() {
@ -2392,7 +2416,6 @@ fn show_context_menu(hwnd: HWND) {
s.widget_visible,
s.show_claude_code,
s.show_codex,
s.show_detailed_remaining,
),
None => (
POLL_15_MIN,
@ -2404,7 +2427,6 @@ fn show_context_menu(hwnd: HWND) {
true,
true,
false,
false,
),
}
};
@ -2511,7 +2533,7 @@ fn show_context_menu(hwnd: HWND) {
);
let detailed_str = native_interop::wide_str(strings.show_detailed_remaining);
let detailed_flags = if show_detailed_remaining {
let detailed_flags = if show_detailed_remaining_enabled() {
MF_CHECKED
} else {
MENU_ITEM_FLAGS(0)
@ -2646,7 +2668,6 @@ fn paint(hdc: HDC, hwnd: HWND) {
codex_weekly_text,
show_claude_code,
show_codex,
show_detailed_remaining,
) = {
let state = lock_state();
match state.as_ref() {
@ -2663,7 +2684,6 @@ fn paint(hdc: HDC, hwnd: HWND) {
s.codex_weekly_text.clone(),
s.show_claude_code,
s.show_codex,
s.show_detailed_remaining,
),
None => return,
}
@ -2722,7 +2742,6 @@ fn paint(hdc: HDC, hwnd: HWND) {
show_claude_code,
show_codex,
&codex_accent,
show_detailed_remaining,
);
let _ = BitBlt(hdc, 0, 0, width, height, mem_dc, 0, 0, SRCCOPY);
@ -2749,7 +2768,6 @@ fn draw_row(
claude_accent: &Color,
codex_accent: &Color,
track: &Color,
detailed: bool,
) {
let seg_h = sc(SEGMENT_H);
let active_models = active_model_count(show_claude_code, show_codex);
@ -2794,9 +2812,8 @@ fn draw_row(
claude_accent,
track,
&claude_value_color,
detailed,
);
model_x += model_usage_width(segment_count, detailed) + sc(MODEL_RIGHT_MARGIN);
model_x += model_usage_width(segment_count) + sc(MODEL_RIGHT_MARGIN);
}
if show_codex {
draw_usage_bar(
@ -2809,16 +2826,15 @@ fn draw_row(
codex_accent,
track,
&codex_value_color,
detailed,
);
}
}
}
fn model_usage_width(segment_count: i32, detailed: bool) -> i32 {
fn model_usage_width(segment_count: i32) -> i32 {
(sc(SEGMENT_W) + sc(SEGMENT_GAP)) * segment_count - sc(SEGMENT_GAP)
+ sc(BAR_RIGHT_MARGIN)
+ sc(text_width_for(detailed))
+ sc(effective_text_width())
}
fn draw_usage_bar(
@ -2831,7 +2847,6 @@ fn draw_usage_bar(
accent: &Color,
track: &Color,
text_color: &Color,
detailed: bool,
) {
let seg_w = sc(SEGMENT_W);
let seg_h = sc(SEGMENT_H);
@ -2892,7 +2907,7 @@ fn draw_usage_bar(
let mut text_rect = RECT {
left: text_x,
top: y,
right: text_x + sc(text_width_for(detailed)),
right: text_x + sc(effective_text_width()),
bottom: y + seg_h,
};
let _ = SetTextColor(hdc, COLORREF(text_color.to_colorref()));