Skip to content

[macOS] Background window swallows first mouseDown (needs acceptsFirstMouse:) — custom drag region & clicks require two clicks #513

Description

@diqye

[macOS] Background window swallows first mouseDown (needs acceptsFirstMouse:) — custom drag region & clicks require two clicks

Preflight Checklist

  • I have searched the issue tracker for an existing issue matching this one
  • I can reproduce this on the latest release (1.18.1)

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:

  1. 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)
  2. Make some other app active (e.g. click into a terminal/editor so piko is not key).
  3. Click-and-drag on the capsule window (the .electrobun-webkit-app-region-drag region).
  4. 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:

  1. 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.
  2. 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 }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions