[macOS] Background window swallows first mouseDown (needs acceptsFirstMouse:) — custom drag region & clicks require two clicks
Preflight Checklist
Summary
When an Electrobun window is not the key window, the first mouseDown is consumed by the OS to bring the window to key/front. The underlying webview never receives that first mousedown event. As a result:
- Custom drag regions (
-webkit-app-region: drag / .electrobun-webkit-app-region-drag) don't work until the window is already key — the user must click once to activate, then click-and-drag again to move the window. This breaks the "click-and-drag the capsule to move it" UX that native macOS apps have.
- Buttons inside the webview require two clicks when the window is not key (first click activates, second click actually triggers the handler).
This is exactly the behavior that Apple's -acceptsFirstMouse: exists to fix, and Electrobun does not currently override it.
Reproduction project
A real-world app that reproduces this: https://github.com/diqye/piko (a floating, always-on-top "capsule" status window for code agents). Relevant bits:
- Window creation —
src/bun/capsule/index.ts:
this.win = new BrowserWindow({
title: "piko",
url: "views://capsuleview/index.html",
frame,
titleBarStyle: "hidden",
transparent: true,
styleMask: { Resizable: false, NonactivatingPanel: true },
hidden: true,
rpc: this.rpc,
});
this.win.setAlwaysOnTop(true);
- Custom drag region —
src/capsuleview/Capsule.tsx:
<div className="electrobun-webkit-app-region-drag ...">
Steps to Reproduce
You can reproduce either with the project above or a minimal window:
git clone https://github.com/diqye/piko && cd piko && bun install && bun start
(or create a transparent, titleBarStyle: "hidden", always-on-top window with a .electrobun-webkit-app-region-drag element)
- Make some other app active (e.g. click into a terminal/editor so piko is not key).
- Click-and-drag on the capsule window (the
.electrobun-webkit-app-region-drag region).
- Also try: while another app is active, single-click the action button inside the capsule.
Expected
- The window moves immediately on the first mouseDown, exactly like a native HUD/floating window.
- The button fires on the first click.
Actual
- The first mouseDown only brings the window to key/front. The window does not move.
- The user has to release and click-and-drag again to move it.
- The button also requires two clicks.
Root Cause (from inspecting libNativeWrapper.dylib)
The window class ElectrobunWindow is a subclass of NSWindow and only overrides canBecomeKeyWindow / canBecomeMainWindow. It does not override acceptsFirstMouse: (which NSWindow returns NO for by default).
$ otool -ov libNativeWrapper.dylib | grep -A4 _OBJC_CLASS_\$_ElectrobunWindow
superclass 0x0 _OBJC_CLASS_$_NSWindow <-- NSWindow, not NSPanel
imp ... -[ElectrobunWindow canBecomeKeyWindow]
imp ... -[ElectrobunWindow canBecomeMainWindow]
(no acceptsFirstMouse:, no performDrag: override)
Because electrobun's custom drag is implemented in JS (preload/dragRegions.ts listens for webview mousedown → calls startWindowMove → native uses setFrameOrigin:), the JS handler can never fire on the first click when the window isn't key.
Two related findings:
NonactivatingPanel style mask is effectively a no-op for this class. Per Apple's docs, NSWindowStyleMaskNonactivatingPanel only affects NSPanel subclasses. Since ElectrobunWindow is an NSWindow subclass, setting styleMask: { NonactivatingPanel: true } does not yield a non-activating panel, so it does not solve the first-click problem either.
- The drag implementation also doesn't use
NSWindow -performDragWithEvent:, which would itself accept the first mouse event.
Suggested Fix
Override acceptsFirstMouse: on ElectrobunWindow to return YES, at least when NonactivatingPanel / UtilityWindow is requested:
- (BOOL)acceptsFirstMouse:(NSEvent *)event {
return YES; // or tie to a styleMask flag
}
This is what most floating/HUD-style macOS apps do, and it makes the first-click-and-drag "just work" like a native window. (Web browsers like Chrome/Safari do the same for their custom titlebar drag regions.)
Optionally also consider using NSPanel (or NSPanel-backed class) when NonactivatingPanel is requested, so that style mask actually has the documented effect.
Environment
- Electrobun: 1.18.1
- OS: macOS (arm64)
- Window config:
titleBarStyle: "hidden", transparent: true, always-on-top, styleMask: { NonactivatingPanel: true }
[macOS] Background window swallows first mouseDown (needs acceptsFirstMouse:) — custom drag region & clicks require two clicks
Preflight Checklist
Summary
When an Electrobun window is not the key window, the first
mouseDownis consumed by the OS to bring the window to key/front. The underlying webview never receives that firstmousedownevent. As a result:-webkit-app-region: drag/.electrobun-webkit-app-region-drag) don't work until the window is already key — the user must click once to activate, then click-and-drag again to move the window. This breaks the "click-and-drag the capsule to move it" UX that native macOS apps have.This is exactly the behavior that Apple's
-acceptsFirstMouse:exists to fix, and Electrobun does not currently override it.Reproduction project
A real-world app that reproduces this: https://github.com/diqye/piko (a floating, always-on-top "capsule" status window for code agents). Relevant bits:
src/bun/capsule/index.ts:src/capsuleview/Capsule.tsx:Steps to Reproduce
You can reproduce either with the project above or a minimal window:
git clone https://github.com/diqye/piko && cd piko && bun install && bun start(or create a transparent,
titleBarStyle: "hidden", always-on-top window with a.electrobun-webkit-app-region-dragelement).electrobun-webkit-app-region-dragregion).Expected
Actual
Root Cause (from inspecting
libNativeWrapper.dylib)The window class
ElectrobunWindowis a subclass ofNSWindowand only overridescanBecomeKeyWindow/canBecomeMainWindow. It does not overrideacceptsFirstMouse:(whichNSWindowreturnsNOfor by default).Because electrobun's custom drag is implemented in JS (
preload/dragRegions.tslistens for webviewmousedown→ callsstartWindowMove→ native usessetFrameOrigin:), the JS handler can never fire on the first click when the window isn't key.Two related findings:
NonactivatingPanelstyle mask is effectively a no-op for this class. Per Apple's docs,NSWindowStyleMaskNonactivatingPanelonly affectsNSPanelsubclasses. SinceElectrobunWindowis anNSWindowsubclass, settingstyleMask: { NonactivatingPanel: true }does not yield a non-activating panel, so it does not solve the first-click problem either.NSWindow -performDragWithEvent:, which would itself accept the first mouse event.Suggested Fix
Override
acceptsFirstMouse:onElectrobunWindowto returnYES, at least whenNonactivatingPanel/UtilityWindowis requested:This is what most floating/HUD-style macOS apps do, and it makes the first-click-and-drag "just work" like a native window. (Web browsers like Chrome/Safari do the same for their custom titlebar drag regions.)
Optionally also consider using
NSPanel(orNSPanel-backed class) whenNonactivatingPanelis requested, so that style mask actually has the documented effect.Environment
titleBarStyle: "hidden",transparent: true, always-on-top,styleMask: { NonactivatingPanel: true }