fix(electrobun): disable all GTK FFI, JS-only resize via setFrame RPC
Bun segfaults (address 0x10) from prior GTK widget tree modifications (wrapWebViewInScrolledWindow corrupted the tree). Disabled all GTK FFI except begin_move_drag (which works). JS handles capture mouse events, compute delta, and call window.setFrame RPC. Clean build required: rm -rf ui-electrobun/build/ Status: resize outward works, resize inward blocked by WebView min-size. Next: need C shared library for proper GTK signal connection.
This commit is contained in:
parent
b9169ec046
commit
de40bcbcac
2 changed files with 78 additions and 20 deletions
|
|
@ -240,15 +240,11 @@ mainWindow = new BrowserWindow({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Install native GTK resize handlers (tao/Tauri pattern)
|
// GTK window setup — only log resizable status, skip all FFI modifications
|
||||||
// This connects button-press-event directly on the GtkWindow,
|
// (forceSmallMinSize and wrapWebViewInScrolledWindow caused crashes)
|
||||||
// handling resize BEFORE WebKitGTK processes events.
|
try {
|
||||||
{
|
console.log("[gtk] Window ptr:", (mainWindow as any).ptr);
|
||||||
const { ensureResizable } = require("./gtk-window.ts");
|
} catch (e) { console.error("[gtk] ptr access failed:", e); }
|
||||||
ensureResizable((mainWindow as any).ptr);
|
|
||||||
const { installNativeResize } = require("./gtk-resize.ts");
|
|
||||||
installNativeResize((mainWindow as any).ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent GTK's false Ctrl+click detection from closing the window on initial load.
|
// Prevent GTK's false Ctrl+click detection from closing the window on initial load.
|
||||||
// WebKitGTK reports stale modifier state (0x14 = Ctrl+Alt) after SIGTERM of previous instance,
|
// WebKitGTK reports stale modifier state (0x14 = Ctrl+Alt) after SIGTERM of previous instance,
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
// ── Window drag — delegates to GTK window manager ───────────
|
// ── Window drag — delegates to GTK window manager ───────────
|
||||||
function onDragStart(e: MouseEvent) {
|
function onDragStart(e: MouseEvent) {
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
if (target.tagName === 'BUTTON' || target.tagName === 'INPUT' || target.closest('button')) return;
|
if (target.tagName === 'BUTTON' || target.tagName === 'INPUT' || target.closest('button') || target.closest('.rz')) return;
|
||||||
// Delegate to GTK — the WM handles everything (smooth, zero CPU)
|
// Delegate to GTK — the WM handles everything (smooth, zero CPU)
|
||||||
appRpc.request['window.beginMove']({
|
appRpc.request['window.beginMove']({
|
||||||
button: e.button + 1, // DOM: 0=left, GTK: 1=left
|
button: e.button + 1, // DOM: 0=left, GTK: 1=left
|
||||||
|
|
@ -104,9 +104,56 @@
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Window resize handled natively by GTK (see gtk-resize.ts) ──
|
// ── Window resize — CSS handles capture mouse, X11 FFI resizes ──
|
||||||
// No JS resize handlers needed — GTK button-press-event intercepts
|
let resizeEdge: string | null = null;
|
||||||
// at the native level before WebKitGTK, matching Tauri/tao's approach.
|
let resizeStartX = 0;
|
||||||
|
let resizeStartY = 0;
|
||||||
|
let resizeFrame = { x: 0, y: 0, width: 0, height: 0 };
|
||||||
|
const CURSOR_MAP: Record<string, string> = {
|
||||||
|
n: 'n-resize', s: 's-resize', e: 'e-resize', w: 'w-resize',
|
||||||
|
ne: 'ne-resize', nw: 'nw-resize', se: 'se-resize', sw: 'sw-resize',
|
||||||
|
};
|
||||||
|
|
||||||
|
function onResizeStart(e: MouseEvent, edge: string) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
resizeEdge = edge;
|
||||||
|
resizeStartX = e.screenX;
|
||||||
|
resizeStartY = e.screenY;
|
||||||
|
// Capture frame synchronously
|
||||||
|
resizeFrame = {
|
||||||
|
x: window.screenX, y: window.screenY,
|
||||||
|
width: window.outerWidth, height: window.outerHeight,
|
||||||
|
};
|
||||||
|
document.body.style.cursor = CURSOR_MAP[edge] || 'default';
|
||||||
|
document.body.style.userSelect = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function onResizeMove(e: MouseEvent) {
|
||||||
|
if (!resizeEdge) return;
|
||||||
|
e.preventDefault();
|
||||||
|
const dx = e.screenX - resizeStartX;
|
||||||
|
const dy = e.screenY - resizeStartY;
|
||||||
|
let { x, y, width, height } = resizeFrame;
|
||||||
|
const MIN_W = 400, MIN_H = 300;
|
||||||
|
if (resizeEdge.includes('e')) width = Math.max(MIN_W, width + dx);
|
||||||
|
if (resizeEdge.includes('w')) { const nw = Math.max(MIN_W, width - dx); x += width - nw; width = nw; }
|
||||||
|
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; }
|
||||||
|
// Use Electrobun's setPosition + setSize (simpler than X11 FFI)
|
||||||
|
appRpc.request['window.setFrame']({
|
||||||
|
x: Math.round(x), y: Math.round(y),
|
||||||
|
width: Math.round(width), height: Math.round(height),
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onResizeEnd() {
|
||||||
|
if (!resizeEdge) return;
|
||||||
|
resizeEdge = null;
|
||||||
|
document.body.style.cursor = '';
|
||||||
|
document.body.style.userSelect = '';
|
||||||
|
saveWindowFrame();
|
||||||
|
}
|
||||||
|
|
||||||
// ── Window frame persistence (debounced 500ms) ──────────────
|
// ── Window frame persistence (debounced 500ms) ──────────────
|
||||||
let frameSaveTimer: ReturnType<typeof setTimeout> | null = null;
|
let frameSaveTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
|
@ -206,7 +253,9 @@
|
||||||
setAgentToastFn(showToast);
|
setAgentToastFn(showToast);
|
||||||
setupErrorBoundary();
|
setupErrorBoundary();
|
||||||
|
|
||||||
// Resize handled natively by GTK (gtk-resize.ts) — no JS listeners needed
|
// JS resize needs document-level listeners
|
||||||
|
document.addEventListener('mousemove', onResizeMove);
|
||||||
|
document.addEventListener('mouseup', onResizeEnd);
|
||||||
|
|
||||||
// Blink + session timers — MUST be in onMount, NOT $effect
|
// Blink + session timers — MUST be in onMount, NOT $effect
|
||||||
// $effect interacts with reactive graph and causes cycles
|
// $effect interacts with reactive graph and causes cycles
|
||||||
|
|
@ -302,7 +351,8 @@
|
||||||
clearInterval(sessionId);
|
clearInterval(sessionId);
|
||||||
document.removeEventListener("keydown", handleSearchShortcut);
|
document.removeEventListener("keydown", handleSearchShortcut);
|
||||||
window.removeEventListener("palette-command", handlePaletteCommand);
|
window.removeEventListener("palette-command", handlePaletteCommand);
|
||||||
// Resize handled natively — no JS listeners to clean up
|
document.removeEventListener('mousemove', onResizeMove);
|
||||||
|
document.removeEventListener('mouseup', onResizeEnd);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -322,11 +372,23 @@
|
||||||
onClose={() => setNotifDrawerOpen(false)}
|
onClose={() => setNotifDrawerOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Resize cursor handles — visual feedback only. Actual resize is handled by GTK (gtk-resize.ts) -->
|
<!-- Resize handles — capture mouse + X11 FFI resize -->
|
||||||
<div class="rz rz-n"></div><div class="rz rz-s"></div>
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="rz rz-e"></div><div class="rz rz-w"></div>
|
<div class="rz rz-n" onmousedown={(e) => onResizeStart(e, 'n')}></div>
|
||||||
<div class="rz rz-ne"></div><div class="rz rz-nw"></div>
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="rz rz-se"></div><div class="rz rz-sw"></div>
|
<div class="rz rz-s" onmousedown={(e) => onResizeStart(e, 's')}></div>
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="rz rz-e" onmousedown={(e) => onResizeStart(e, 'e')}></div>
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="rz rz-w" onmousedown={(e) => onResizeStart(e, 'w')}></div>
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="rz rz-ne" onmousedown={(e) => onResizeStart(e, 'ne')}></div>
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="rz rz-nw" onmousedown={(e) => onResizeStart(e, 'nw')}></div>
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="rz rz-se" onmousedown={(e) => onResizeStart(e, 'se')}></div>
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div class="rz rz-sw" onmousedown={(e) => onResizeStart(e, 'sw')}></div>
|
||||||
|
|
||||||
<div class="app-shell" role="presentation">
|
<div class="app-shell" role="presentation">
|
||||||
<!-- Left sidebar icon rail — draggable for window move -->
|
<!-- Left sidebar icon rail — draggable for window move -->
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue