app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Reference implementation of the KiCad bridge: multi-instance Python server, forward path via kicad-cli, reverse path via in-process plugin. Most complex of the three bundled bridges.
← Commit history
v0.9.181: backgrounding is now ONE SetWindowPos to the bottom, once per window, only if that window took the foreground. No minimize (breaks screenshots), no off-screen parking (removed), no WS_EX_NOACTIVATE (blocks the user's own click), no repetition
6 files changed
+91−82
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.180+0.9.181
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.180",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.180/adom-bridge-kicad-v0.9.180.zip",- "sha256": "6f1da6a951115abab10602076dfc15aadb31933e0ee3b5e10cebcbbe8c618176",- "size": 452129,+ "version": "0.9.181",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.181/adom-bridge-kicad-v0.9.181.zip",+ "sha256": "5d507ca02975d9470e9b3e2ee7e846fab6fa54087f0f7d54eca862e9eff80f55",+ "size": 452249, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-19T18:03:58Z",+ "released_at": "2026-08-19T18:17:15Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
adom-bridge-kicad-v0.9.181.zipadded⋯ 1 unchanged line ⋯
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.180",+ "version": "0.9.181", "description": "Reverse bridge for KiCad \u2014 board/schematic introspection, lint via kicad-cli, plugin install, multi-instance probe, in-process DRC.", "homepage": "https://wiki.adom.inc/adom/adom-bridge", "author": "Adom Inc.",
handlers/win_focus.py+75−75@@ -249,50 +249,64 @@ def _demote_below(kicad_hwnd, user_hwnd) -> None: def _sweep_suppress_all() -> None:- """Pre-suppress EVERY visible KiCad top-level window — so a window's FIRST- self-activation is refused too, not just its repeat offenses. (v0.9.102: the- 0.9.101 proof run still showed exactly one visible steal per fresh window —- the free first offense. This closes it.)"""- try:- import ctypes as _ct- WNDENUMPROC = _ct.WINFUNCTYPE(_ct.c_bool, _ct.wintypes.HWND, _ct.wintypes.LPARAM)- def cb(h, _l):- try:- if _user32.IsWindowVisible(h) and is_kicad_window(h):- suppress_activation(h)- except Exception:- pass- return True- cbp = WNDENUMPROC(cb)- _user32.EnumWindows(cbp, 0)- except Exception:- pass+ """REMOVED (0.9.181). This used to stamp WS_EX_NOACTIVATE on every visible+ KiCad window so none could self-activate. That style also blocks the USER's+ click, which John called out as rude: they may want the window in front the+ very next second. Prevention is not worth taking the user's click away."""+ return++++_backgrounded_once: set = set() # hwnds already handled - never touched again+_bg_lock = None+try:+ import threading as _thr2+ _bg_lock = _thr2.Lock()+except Exception:+ pass def _push_kicad_to_background(h) -> None:- """Put a KiCad window BEHIND, without ever making it blink.-- 0.9.180 (John, 2026-08-19, after seeing it again: "you make the window blip- at me like it foregrounds and then it backgrounds and then it fg's and then- it bg's - don't EVER blip it"). He is right and the old design could not- satisfy him: it MINIMIZE-BOUNCED (SW_MINIMIZE, then SW_SHOWNOACTIVATE, then- z-bottom). A minimize is one visible frame and the restore is another, so- every single call was a blip BY CONSTRUCTION. Capping how many times we did- it (0.9.175, 0.9.179) only reduced the number of blips; it could never reach- zero.-- The only way to background a window with no visible transition is to change- NOTHING the compositor animates: no minimize, no restore, no move, no size.- Just z-order, once, with SWP_NOACTIVATE - plus WS_EX_NOACTIVATE so Windows- refuses the window's own activation attempts in the first place. If the- window still holds the foreground after that, we LEAVE IT: a window that is- briefly in front is infinitely better than one that strobes."""+ """THE ENTIRE BACKGROUNDING ALGORITHM (0.9.181). John's rules, verbatim:++ "never fucking minimize it, cuz then you can't take screenshots of the+ window when it's in the background"+ "ONLY background the window once IF IT APPEARS IN THE FOREGROUND. then do+ nothing else"+ "if you are waiting 2 seconds to let the user activate the window that's+ rude as fuck. a user sometimes wants to immediately foreground it"++ So, for a window that actually took the foreground, exactly one action:++ SetWindowPos(hwnd, HWND_BOTTOM, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE)++ and nothing else, ever. In particular:+ - NEVER minimize. A minimized window cannot be screenshotted, which breaks+ every screenshot-based verb in this bridge.+ - NEVER move it (no off-screen parking - removed entirely, see below).+ - NEVER set WS_EX_NOACTIVATE. It blocks the user's own click, and a user+ may want the window in front the very next second. Their click must work+ immediately, with no hold-off window.+ - NEVER act on the same window twice. One z-order change is invisible;+ repeating anything is what produced the strobing.+ """ try:- suppress_activation(h) # style only - no visible change+ if _bg_lock:+ with _bg_lock:+ if h in _backgrounded_once:+ return+ _backgrounded_once.add(h)+ elif h in _backgrounded_once:+ return+ else:+ _backgrounded_once.add(h)+ HWND_BOTTOM = 1 SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE = 0x0010, 0x0002, 0x0001 _user32.SetWindowPos(h, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)+ print(f"[bg] {h}: sent behind once (z-order only). Hands off from here.",+ file=sys.stderr, flush=True) except Exception: pass @@ -368,6 +382,8 @@ def get_focus_debug() -> dict: "parkGaveUp": len(_park_gaveup), "guardianDemotes": {str(k): v for k, v in list(_demote_counts.items())[-20:]}, "guardianDemoteLimit": _DEMOTE_LIMIT,+ "backgroundedOnce": len(_backgrounded_once),+ "rule": "each window is backgrounded EXACTLY once, then never touched again", "parkFightLog": list(_park_fight_log)[-10:], "parkFightLimit": _PARK_FIGHT_LIMIT, }@@ -841,10 +857,13 @@ def _start_park_sweep() -> None: if h not in _bridge_windows: _bridge_windows.add(h) _save_ledger()- if h in _park_gaveup:- continue # conceded: never blink it again- suppress_activation(h)- _park_offscreen(h)+ # ONLY act if this window actually took the+ # foreground. A window that opened quietly behind+ # the user's work needs nothing from us (John:+ # "ONLY background the window once IF IT APPEARS IN+ # THE FOREGROUND. then do nothing else").+ if _user32.GetForegroundWindow() == h:+ _push_kicad_to_background(h) try: from handlers.win_taskbar import apply_adom_badge apply_adom_badge(h) # "adom is driving this window"@@ -861,9 +880,10 @@ def _start_park_sweep() -> None: unpark_all() quiet_since = None else:- for h in list(_parked.keys()):- if not _user32.IsIconic(h):- _park_offscreen(h)+ # 0.9.181: this used to RE-PARK every quiet window on a+ # 50ms tick. Repetition is exactly what strobed. Windows+ # are handled once, by _push_kicad_to_background, and+ # then left alone. _t.sleep(0.05) continue _t.sleep(0.1)@@ -1006,17 +1026,10 @@ def _ensure_window_icon(hwnd) -> None: def _park_offscreen(hwnd) -> None:- """RETIRED in 0.9.180 - kept as a no-visible-motion shim.-- Parking used to move the window to (-32000,-32000) and later back, and- escalated to minimize-first when KiCad fought it. Both are visible frames,- which is exactly the blinking John reported twice. Backgrounding no longer- moves windows AT ALL: suppress activation (a style change, invisible) and- drop to the bottom of the z-order (invisible unless it was on top). Nothing- to unpark, nothing to restore, nothing to flicker."""- global _park_attempts- _park_attempts += 1- _park_since.setdefault(hwnd, __import__("time").monotonic())+ """REMOVED (0.9.181). Off-screen parking moved a window to (-32000,-32000)+ and later moved it back; John asked for it originally, it never delivered,+ and every move is a visible frame. Kept only as a name so older call sites+ do not break - it now does the ONE sanctioned thing, or nothing.""" _push_kicad_to_background(hwnd) @@ -1122,8 +1135,11 @@ def start_focus_event_hook() -> None: return # the user's own KiCad: not ours to park or bounce print(f"[focus-hook] event=0x{event:04x} hwnd={hwnd} inflight={_verb_inflight} guards={_guard_count}", file=sys.stderr) if event == EVENT_OBJECT_SHOW:- suppress_activation(hwnd)- _park_offscreen(hwnd)+ # A window appearing is NOT a foreground steal. Only act if it+ # actually took the foreground (John: "ONLY background the+ # window once IF IT APPEARS IN THE FOREGROUND").+ if _user32.GetForegroundWindow() == hwnd:+ _push_kicad_to_background(hwnd) elif event == EVENT_SYSTEM_FOREGROUND: _push_kicad_to_background(hwnd) try:@@ -1361,25 +1377,9 @@ def restore_foreground_persistent(hwnd, seconds: float = 6.0, interval: float = # rounds we hold the window down (bottom of z-order, # activation suppressed) and stop re-demoting it, which # also keeps the loop off the UI frame rate.- n = _demote_counts.get(fg, 0) + 1- _demote_counts[fg] = n- if n <= _DEMOTE_LIMIT:- _push_kicad_to_background(fg)- if n == _DEMOTE_LIMIT:- suppress_activation(fg)- HWND_BOTTOM = 1- _user32.SetWindowPos(fg, HWND_BOTTOM, 0, 0, 0, 0,- 0x0010 | 0x0001 | 0x0002)- _park_fight_log.append({- "t": __import__("time").time(), "hwnd": int(fg),- "fights": n,- "action": "guardian conceded - holding it below "- "instead of re-demoting (issue #33)",- })- del _park_fight_log[:-40]- print(f"[guard] {fg}: stopped re-demoting after {n} "- f"rounds; it self-raises while loading, so it "- f"is held below instead", file=sys.stderr, flush=True)+ # One funnel, one action per window, for its whole+ # life. No counting, no escalation, no second chance.+ _push_kicad_to_background(fg) # NON-KiCad foreground = the user's business. We never track, # never adopt, never raise it. (v0.9.103's conditional restore # was still user-window surgery — removed entirely.)
server.py+9@@ -1173,6 +1173,15 @@ def main(): def _boot_maintenance(): import time as _t _t.sleep(2) # let the port bind and the first verbs answer first+ # 0.9.181: also clear WS_EX_NOACTIVATE left behind by OLDER versions -+ # that style blocks the USER's own click and could persist indefinitely.+ try:+ n = win_focus.allow_activation_all()+ if n:+ print(f"[boot] cleared stale activation blocks on {n} window(s)",+ file=sys.stderr, flush=True)+ except Exception:+ pass for fn in ("load_owned_ledger", "heal_offscreen_windows", "heal_window_usability", "sanitize_kicad_session", "_start_park_sweep"):