import { useLayoutEffect, useRef } from "react"; import { useSearchParams } from "react-router-dom"; import { Events, Window } from "@wailsio/runtime"; import i18next from "@/lib/i18n"; import { isLinux } from "@/lib/platform"; const EVENT_WINDOW_PAINTED = "netbird:window-painted"; // Sizes the current Wails window to the measured content height (keeping `width`), // then reports it as painted so Go shows it. Re-applies on content resize and language change. export function useAutoSizeWindow(width: number, ready: boolean = true) { const ref = useRef(null); const [params] = useSearchParams(); const generation = params.get("gen") ?? ""; useLayoutEffect(() => { const el = ref.current; if (!el) return; let painted = false; let raf1 = 0; let raf2 = 0; const paintedOnce = () => { if (painted) return; painted = true; Events.Emit(EVENT_WINDOW_PAINTED, generation).catch(() => {}); }; const apply = async () => { if (!ready) return; const h = Math.ceil(el.getBoundingClientRect().height); if (h <= 0) return; try { // Window.SetSize takes the frame size, so add the OS title-bar height or content clips. const frame = await Window.Size(); const targetH = h + Math.max(0, frame.height - window.innerHeight); // Linux: SetSize no-ops on a mapped non-resizable window (X11), so pin via min/max instead. if (isLinux()) { await Window.SetMinSize(width, targetH); await Window.SetMaxSize(width, targetH); } await Window.SetSize(width, targetH); paintedOnce(); } catch { // window gone / not ready — ignore } }; const scheduleApply = () => { cancelAnimationFrame(raf1); cancelAnimationFrame(raf2); raf1 = requestAnimationFrame(() => { raf2 = requestAnimationFrame(apply); }); }; apply(); const ro = new ResizeObserver(apply); ro.observe(el); i18next.on("languageChanged", scheduleApply); return () => { ro.disconnect(); cancelAnimationFrame(raf1); cancelAnimationFrame(raf2); i18next.off("languageChanged", scheduleApply); }; }, [width, ready, generation]); return ref; }