mirror of
https://github.com/tiennm99/claude-code-usage-bubble.git
synced 2026-06-07 08:12:41 +00:00
fix: phase 2 — UI-freeze + GDI-leak + panic-on-GDI-exhaustion fixes
- P0: pull blocking HTTPS out from under the global mutex. AppState's http and registry now live behind Arc<Client> and Arc<Mutex<Registry>>; do_poll, attempt_refresh, and version_action's Apply branch clone these out, drop lock_state, then do their I/O. Apply now spawns a worker thread that posts WM_APP_UPDATE_APPLIED back to the message- only window when the cmd handoff is launched, so the UI no longer freezes for the duration of the download. - P1: bubble.rs paint_text_layer saves and restores the DC's previous HFONT before DeleteObject. The old code's DeleteObject on a still- selected HFONT silently failed and leaked one handle per paint frame (up to ~12/s under the ≥95% pulse animation). - P1: replace 5x CreatePopupMenu().unwrap() with let-else early returns that destroy any half-built menus and log. GDI exhaustion no longer panics the UI thread. - P1: at-most-one-in-flight gate (static AtomicBool) on the poll thread so rapid Refresh clicks don't stack concurrent HTTPS calls. - P1: token-expired balloon now picks the title/body for the provider that actually failed, instead of always falling back to Claude when show_claude_code is on. - P1: panel place_near honors SM_XVIRTUALSCREEN / SM_YVIRTUALSCREEN so multi-monitor setups with a secondary display left of the primary no longer mis-clamp the panel position. - P1: COUNTDOWN_TEMPLATE bumped from "999d" to "999시간" — Korean has the widest suffix among shipped locales and was overflowing the countdown column. Bumps version to 0.1.4.
This commit is contained in:
+12
-3
@@ -888,7 +888,12 @@ fn check_fullscreen(bubble_hwnd: HWND) {
|
||||
|
||||
const ACCENT_STRIPE_W_LOGICAL: i32 = 4;
|
||||
const LABEL_PAD_LOGICAL: i32 = 6;
|
||||
const COUNTDOWN_TEMPLATE: &str = "999d";
|
||||
// Sized for the widest countdown across all shipped locales. Korean
|
||||
// "999시간" (3 digits + 2 CJK chars for the hour suffix) is the current
|
||||
// worst case; ASCII-only "999d" was too narrow and let CJK text spill
|
||||
// out of the column. Update this when adding a locale with a longer
|
||||
// suffix.
|
||||
const COUNTDOWN_TEMPLATE: &str = "999시간";
|
||||
// Percent now lives in its own column between the bar and the countdown so
|
||||
// the two numeric readouts ("44%" and "3h") sit next to each other for
|
||||
// quick scanning, and the percent never has to fight the bar's fill colour
|
||||
@@ -1296,8 +1301,10 @@ fn paint_text_layer(hdc: HDC, layout: &BarLayout, inputs: &PaintInputs) {
|
||||
let label_font = create_font(layout.label_font_px, &font_name, FW_NORMAL.0 as i32);
|
||||
SetBkMode(hdc, TRANSPARENT);
|
||||
|
||||
// Row labels in the left column.
|
||||
SelectObject(hdc, label_font);
|
||||
// Save the DC's original font so we can restore it before deleting
|
||||
// ours. DeleteObject silently fails on a still-selected HFONT,
|
||||
// which would leak the handle on every paint frame.
|
||||
let prev_font = SelectObject(hdc, label_font);
|
||||
SetTextColor(hdc, COLORREF(muted_color.into_colorref()));
|
||||
draw_label(hdc, layout, layout.row1_y, "5h");
|
||||
draw_label(hdc, layout, layout.row2_y, "7d");
|
||||
@@ -1314,6 +1321,8 @@ fn paint_text_layer(hdc: HDC, layout: &BarLayout, inputs: &PaintInputs) {
|
||||
draw_countdown(hdc, layout, layout.row1_y, &inputs.session_text);
|
||||
draw_countdown(hdc, layout, layout.row2_y, &inputs.weekly_text);
|
||||
|
||||
// Restore the original font, then it is safe to delete ours.
|
||||
SelectObject(hdc, prev_font);
|
||||
let _ = DeleteObject(main_font);
|
||||
let _ = DeleteObject(bold_font);
|
||||
let _ = DeleteObject(label_font);
|
||||
|
||||
Reference in New Issue
Block a user