# -*- coding: utf-8 -*- """Verify GUI fix: /show resizes host window to panel rect, stays offscreen, not topmost.""" import ctypes, time, subprocess, os, threading, json from ctypes import wintypes import urllib.request EXE = r"C:\Users\locpham\SonicForgeStudio\native_bridge\build\Release\fx_vst_bridge.exe" JOB = r"C:\Users\locpham\AppData\Local\Temp\test_gui_WaveObserver.vst3.json" CLASS = b"SonicForge_FX_GUI_Class" user32 = ctypes.WinDLL("user32", use_last_error=True) user32.GetWindowRect.argtypes = [wintypes.HWND, ctypes.POINTER(wintypes.RECT)] user32.IsWindowVisible.restype = ctypes.c_int user32.GetWindowLongW.restype = ctypes.c_long user32.GetWindowLongW.argtypes = [wintypes.HWND, ctypes.c_int] user32.GetWindowThreadProcessId.argtypes = [wintypes.HWND, ctypes.POINTER(wintypes.DWORD)] user32.GetClassNameA.argtypes = [wintypes.HWND, ctypes.c_char_p, ctypes.c_int] GWL_EXSTYLE = -20 def find_own_windows(pid): out = [] WNDENUMPROC = ctypes.WINFUNCTYPE(ctypes.c_bool, wintypes.HWND, wintypes.LPARAM) @WNDENUMPROC def cb(hwnd, lp): t = wintypes.DWORD() user32.GetWindowThreadProcessId(hwnd, ctypes.byref(t)) if t.value == pid: out.append(hwnd) return True user32.EnumWindows(cb, 0) return out def http(method, url, body=None): req = urllib.request.Request(url, method=method, data=body.encode() if body else None, headers={"Content-Type": "application/json"}) with urllib.request.urlopen(req, timeout=10) as r: return r.read() proc = subprocess.Popen([EXE, "--fx-gui", JOB], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, env=dict(os.environ, SF_PARENT_PID=str(os.getpid())), creationflags=subprocess.CREATE_NO_WINDOW) lines = [] def reader(): for line in proc.stdout: lines.append(line.rstrip()) threading.Thread(target=reader, daemon=True).start() def rect_str(h): r = wintypes.RECT(); user32.GetWindowRect(h, ctypes.byref(r)) ex = user32.GetWindowLongW(h, GWL_EXSTYLE) return "L%d T%d R%d B%d W%d H%d vis=%d ex=0x%X topmost=%d" % ( r.left, r.top, r.right, r.bottom, r.right-r.left, r.bottom-r.top, user32.IsWindowVisible(h), ex, bool(ex & 0x8)) try: port = None t0 = time.time() while time.time() - t0 < 20: for l in lines: if l.startswith("SF_FXGUI_PORT="): port = int(l.split("=", 1)[1]); break if port: break time.sleep(0.1) base = f"http://127.0.0.1:{port}" t0 = time.time() while time.time() - t0 < 25: if any("editor open" in l for l in lines): break time.sleep(0.2) hwnd = None for h in find_own_windows(proc.pid): buf = ctypes.create_string_buffer(256) user32.GetClassNameA(h, buf, 256) if buf.value == CLASS: hwnd = h; break assert hwnd, "fx-gui window not found in own process" print("fx-gui hwnd:", hwnd) print("before /show:", rect_str(hwnd)) # /show with panel rect -> resize host window to panel, stay offscreen, no topmost http("POST", base + "/show", json.dumps({"rect": {"x": 300, "y": 200, "w": 640, "h": 480}})) time.sleep(1.0) print("after /show:", rect_str(hwnd)) r = wintypes.RECT(); user32.GetWindowRect(hwnd, ctypes.byref(r)) w, h = r.right-r.left, r.bottom-r.top assert r.left == -20000 and r.top == -20000, "window not offscreen!" assert not (user32.GetWindowLongW(hwnd, GWL_EXSTYLE) & 0x8), "window topmost!" assert (w, h) != (800, 600), "host window still default 800x600 — resize not applied" print("RESIZE applied: host window now %dx%d (was default 800x600)" % (w, h)) fr = http("GET", base + "/frame") print("frame size after /show+resize:", len(fr)) assert len(fr) > 1000, "capture broken after /show" print("ALL CHECKS PASSED") finally: proc.terminate() try: proc.wait(timeout=5) except Exception: proc.kill() print("cleanup done")