mirror of
https://github.com/tiennm99/claude-code-usage-bubble.git
synced 2026-10-12 22:14:30 +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:
1 parent
0f3acd40d4
commit
1ef1bfa7b2
5 files changed
+161
-70
No files matched your search
+17
-9
@@ -504,19 +504,27 @@ fn place_near(anchor: RECT, panel_w: i32, panel_h: i32) -> (i32, i32) {
|
||||
// Anchor below the bubble by default; flip above if it would clip.
|
||||
let mut x = anchor.left;
|
||||
let mut y = anchor.bottom + 8;
|
||||
let virtual_screen_h = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) };
|
||||
let virtual_screen_w = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) };
|
||||
if y + panel_h > virtual_screen_h {
|
||||
// The virtual screen spans all monitors. Its origin is offset from
|
||||
// the primary monitor when a secondary monitor sits left of / above
|
||||
// the primary, so clamps must include SM_XVIRTUALSCREEN /
|
||||
// SM_YVIRTUALSCREEN — not just the width/height of the union.
|
||||
let vx = unsafe { GetSystemMetrics(SM_XVIRTUALSCREEN) };
|
||||
let vy = unsafe { GetSystemMetrics(SM_YVIRTUALSCREEN) };
|
||||
let vw = unsafe { GetSystemMetrics(SM_CXVIRTUALSCREEN) };
|
||||
let vh = unsafe { GetSystemMetrics(SM_CYVIRTUALSCREEN) };
|
||||
let right = vx + vw;
|
||||
let bottom = vy + vh;
|
||||
if y + panel_h > bottom {
|
||||
y = anchor.top - panel_h - 8;
|
||||
}
|
||||
if y < 0 {
|
||||
y = anchor.top;
|
||||
if y < vy {
|
||||
y = anchor.top.max(vy);
|
||||
}
|
||||
if x + panel_w > virtual_screen_w {
|
||||
x = virtual_screen_w - panel_w - 8;
|
||||
if x + panel_w > right {
|
||||
x = right - panel_w - 8;
|
||||
}
|
||||
if x < 0 {
|
||||
x = 8;
|
||||
if x < vx {
|
||||
x = vx + 8;
|
||||
}
|
||||
(x, y)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user