fix(electrobun): GTK FFI direct resize via gtk_window_resize/move

Electrobun's setSize respects WebView min-size constraint. Bypass it
with direct gtk_window_resize() + gtk_window_move() FFI calls.
clearMinSizeTree() runs on every resize frame to suppress WebView
re-propagation. gtkSetFrame() exported as new RPC endpoint.
This commit is contained in:
Hibryda 2026-03-25 13:16:39 +01:00
parent e6635e436c
commit fd2f626c20
3 changed files with 39 additions and 1 deletions

View file

@ -49,6 +49,14 @@ function getGtk() {
args: [FFIType.ptr, FFIType.ptr, FFIType.ptr, FFIType.i32],
returns: FFIType.void,
},
gtk_window_resize: {
args: [FFIType.ptr, FFIType.i32, FFIType.i32],
returns: FFIType.void,
},
gtk_window_move: {
args: [FFIType.ptr, FFIType.i32, FFIType.i32],
returns: FFIType.void,
},
// Container traversal
gtk_bin_get_child: {
args: [FFIType.ptr],
@ -247,6 +255,28 @@ export function beginMoveDrag(
}
}
/**
* Direct GTK resize bypasses Electrobun's setSize which respects WebView min-size.
* Clears min-size tree first, then calls gtk_window_resize + gtk_window_move.
*/
export function gtkSetFrame(
windowPtr: number | bigint,
x: number, y: number, width: number, height: number,
) {
const lib = getGtk();
if (!lib) return false;
try {
// Clear min-size on every frame update during resize
clearMinSizeTree(lib, windowPtr as any);
lib.symbols.gtk_window_resize(windowPtr as any, Math.max(400, Math.round(width)), Math.max(300, Math.round(height)));
lib.symbols.gtk_window_move(windowPtr as any, Math.round(x), Math.round(y));
return true;
} catch (err) {
console.error("[gtk-window] gtkSetFrame failed:", err);
return false;
}
}
// Edge string → GDK_EDGE mapping
const EDGE_MAP: Record<string, GdkEdge> = {
n: GDK_EDGE.N, s: GDK_EDGE.S, e: GDK_EDGE.E, w: GDK_EDGE.W,

View file

@ -154,6 +154,13 @@ const rpc = BrowserView.defineRPC<PtyRPCSchema>({
return { ok: true };
} catch (err) { console.error("[window.clearMinSize]", err); return { ok: false }; }
},
"window.gtkSetFrame": ({ x, y, width, height }: { x: number; y: number; width: number; height: number }) => {
try {
const { gtkSetFrame } = require("./gtk-window.ts");
const ok = gtkSetFrame((mainWindow as any).ptr, x, y, width, height);
return { ok };
} catch (err) { console.error("[window.gtkSetFrame]", err); return { ok: false }; }
},
},
messages: {},
},

View file

@ -148,7 +148,8 @@
if (resizeEdge.includes('s')) height = Math.max(MIN_H, height + dy);
if (resizeEdge.includes('n')) { const nh = Math.max(MIN_H, height - dy); y += height - nh; height = nh; }
appRpc.request['window.setFrame']({ x: Math.round(x), y: Math.round(y), width: Math.round(width), height: Math.round(height) }).catch(() => {});
// Use GTK FFI directly — bypasses Electrobun's setSize which respects WebView min-size
appRpc.request['window.gtkSetFrame']({ x: Math.round(x), y: Math.round(y), width: Math.round(width), height: Math.round(height) }).catch(() => {});
}
function onResizeEnd() {