diff --git a/ui-electrobun/src/bun/gtk-window.ts b/ui-electrobun/src/bun/gtk-window.ts index af68508..7173326 100644 --- a/ui-electrobun/src/bun/gtk-window.ts +++ b/ui-electrobun/src/bun/gtk-window.ts @@ -104,6 +104,15 @@ function getGtk() { args: [FFIType.ptr], returns: FFIType.void, }, + // Sensitivity (disable input processing on widget) + gtk_widget_set_sensitive: { + args: [FFIType.ptr, FFIType.bool], + returns: FFIType.void, + }, + gtk_widget_get_sensitive: { + args: [FFIType.ptr], + returns: FFIType.bool, + }, // Expand flags gtk_widget_set_hexpand: { args: [FFIType.ptr, FFIType.bool], @@ -210,9 +219,41 @@ function forceSmallMinSize(lib: NonNullable, windowPtr: any) { } catch { /* ignore */ } } +/** Cache the WebView widget pointer for sensitivity toggling during resize */ +let cachedWebView: any = null; + +function findWebView(lib: NonNullable, windowPtr: any): any { + if (cachedWebView) return cachedWebView; + try { + // Window → container → scrolledwindow/webview + let widget = lib.symbols.gtk_bin_get_child(windowPtr); + // Walk down the bin chain to find the deepest child (the WebView) + for (let i = 0; i < 5; i++) { + const child = lib.symbols.gtk_bin_get_child(widget); + if (!child) break; + widget = child; + } + cachedWebView = widget; + return widget; + } catch { return null; } +} + +/** + * Temporarily disable WebView input during resize to prevent grab interference. + * Re-enable after resize completes (WM sends configure-event). + */ +export function setWebViewSensitive(windowPtr: number | bigint, sensitive: boolean) { + const lib = getGtk(); + if (!lib) return; + const wv = findWebView(lib, windowPtr as any); + if (wv) { + lib.symbols.gtk_widget_set_sensitive(wv, sensitive); + } +} + /** * Delegate resize to the window manager. - * Clears min-size constraints first so resize-in (shrink) works. + * Disables WebView input first to prevent grab interference. */ export function beginResizeDrag( windowPtr: number | bigint, @@ -224,8 +265,12 @@ export function beginResizeDrag( const lib = getGtk(); if (!lib) return false; try { - // Clear min-size RIGHT BEFORE resize so shrinking is allowed + // 1. Force small min-size forceSmallMinSize(lib, windowPtr as any); + // 2. Disable WebView input to prevent grab interference + const wv = findWebView(lib, windowPtr as any); + if (wv) lib.symbols.gtk_widget_set_sensitive(wv, false); + // 3. Start WM resize lib.symbols.gtk_window_begin_resize_drag( windowPtr as any, edge, @@ -234,6 +279,12 @@ export function beginResizeDrag( Math.round(rootY), 0, // GDK_CURRENT_TIME ); + // 4. Re-enable WebView after resize drag likely ends + // The WM holds the grab until mouse-up. 5s covers long drags. + // Shorter would risk re-enabling mid-drag. + setTimeout(() => { + if (wv) lib.symbols.gtk_widget_set_sensitive(wv, true); + }, 5000); return true; } catch (err) { console.error("[gtk-window] begin_resize_drag failed:", err);