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.151: taskbar icon repair - minimize-parking froze windows into the taskbar before KiCad assigned their icon (blank document buttons); parking now stamps iconless windows with their own exe's icon first
5 files changed
+64−7
BRIDGE_VERSION+1−1@@ -1 +1 @@-0.9.150+0.9.151
adom-bridge-kicad-manifest.json+5−5@@ -1,15 +1,15 @@ { "manifest_version": 1, "name": "kicad",- "version": "0.9.150",- "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.150/adom-bridge-kicad-v0.9.150.zip",- "sha256": "9cd704b9ae8027d0e9e1ec6f90f2715542d539a24704aef8b1bd65d02ddd08f9",- "size": 419952,+ "version": "0.9.151",+ "url": "https://wiki.adom.inc/download/adom/kicad-bridge/0.9.151/adom-bridge-kicad-v0.9.151.zip",+ "sha256": "a5e38ba6cfc2b1f15a2d3a5cdbdd633937d6be683ee2c49a3c337647b87fdb38",+ "size": 420496, "verbPrefixes": [ "kicad_" ], "healthEndpoint": "/status",- "released_at": "2026-08-17T14:39:55Z",+ "released_at": "2026-08-17T15:01:11Z", "hero": "https://wiki.adom.inc/blob/app/kicad-bridge/kicad-hero.png", "languages": [ "Python",
adom-bridge-kicad-v0.9.151.zipadded⋯ 1 unchanged line ⋯
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "kicad", "displayName": "KiCad EDA",- "version": "0.9.150",+ "version": "0.9.151", "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+57@@ -479,6 +479,62 @@ class _WINDOWPLACEMENT(ctypes.Structure if IS_WINDOWS else object): ("rcNormalPosition", ctypes.wintypes.RECT)] +_exe_icons: dict = {} # exe path -> (hicon_big, hicon_small), kept alive+++def _hwnd_exe_path(hwnd) -> str:+ try:+ pid = ctypes.wintypes.DWORD()+ _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid))+ h = _kernel32.OpenProcess(0x1000, False, pid.value)+ if not h:+ return ""+ try:+ buf = ctypes.create_unicode_buffer(512)+ size = ctypes.wintypes.DWORD(512)+ if _kernel32.QueryFullProcessImageNameW(h, 0, buf, ctypes.byref(size)):+ return buf.value+ finally:+ _kernel32.CloseHandle(h)+ except Exception:+ pass+ return ""+++def _ensure_window_icon(hwnd) -> None:+ """Minimize-parking freezes a window into the taskbar BEFORE KiCad assigns+ its icon (wx sets it a beat after frame creation), so the shell shows a+ blank document icon (John, 2026-08-17: "why are my kicad icons fucked+ up"). If the window has no icon, stamp it with its own exe's icon."""+ try:+ WM_GETICON, WM_SETICON = 0x007F, 0x0080+ GCLP_HICON, GCLP_HICONSM = -14, -34+ get_cl = getattr(_user32, "GetClassLongPtrW", None) or _user32.GetClassLongW+ has = (_user32.SendMessageW(hwnd, WM_GETICON, 1, 0)+ or _user32.SendMessageW(hwnd, WM_GETICON, 0, 0)+ or get_cl(hwnd, GCLP_HICON) or get_cl(hwnd, GCLP_HICONSM))+ if has:+ return+ exe = _hwnd_exe_path(hwnd)+ if not exe:+ return+ icons = _exe_icons.get(exe)+ if icons is None:+ big = ctypes.wintypes.HICON()+ small = ctypes.wintypes.HICON()+ ctypes.windll.shell32.ExtractIconExW(exe, 0, ctypes.byref(big),+ ctypes.byref(small), 1)+ icons = (big, small)+ _exe_icons[exe] = icons # keep HICONs alive for process lifetime+ big, small = icons+ if big and big.value:+ _user32.SendMessageW(hwnd, WM_SETICON, 1, big.value)+ if small and small.value:+ _user32.SendMessageW(hwnd, WM_SETICON, 0, small.value)+ except Exception:+ pass++ def _park_offscreen(hwnd) -> None: """Move a window fully off the visible desktop WITHOUT activation. (Instrumented: attempts + last error surface in focusDebug.)@@ -507,6 +563,7 @@ def _park_offscreen(hwnd) -> None: # visible flicker — after a few fights, minimize it without activation # instead. wx does not un-minimize itself; the taskbar button still # works; the screenshot path restores off-screen for capture.+ _ensure_window_icon(hwnd) # never freeze a blank icon into the taskbar _park_fights[hwnd] = _park_fights.get(hwnd, 0) + 1 if _park_fights[hwnd] >= 1: # minimize from first sighting: eeschema # recreates hwnds during load, resetting any higher threshold, and