macOS: add WindowEvent::PointerButton::is_macos_activation_click

Apps need per-click decisions to follow the macOS convention of accepting
first mouse for low-risk actions (selection, scrolling) but rejecting it
for buttons and destructive actions. Motivated by slint-ui/slint#10451.

Always return `true` from `acceptsFirstMouse:`, and tag the resulting
`PointerButton` events with `is_macos_activation_click: true` (on both
the activating left press and its matching release) so the app can
short-circuit the whole gesture with a single check:

    WindowEvent::PointerButton { is_macos_activation_click: true, .. } => return,

Replaces an earlier callback-based design (`accepts_first_mouse` on
`ApplicationHandlerExtMacOS`) that mapped more closely to AppKit but
didn't fit winit's event-driven model and required re-entrancy handling.

Also removes `WindowAttributesMacOS::with_accepts_first_mouse`, which is
now redundant — apps that want to reject activation clicks check the
flag on the per-event instead.
This commit is contained in:
Till Adam
2026-06-18 22:39:35 +02:00
committed by Simon Hausmann
parent 92b643c3f1
commit 6a8a334426
15 changed files with 95 additions and 21 deletions

View File

@@ -1108,6 +1108,7 @@ impl EventProcessor {
state,
position,
button: MouseButton::Left.into(),
is_macos_activation_click: false,
},
xlib::Button2 => WindowEvent::PointerButton {
device_id,
@@ -1115,6 +1116,7 @@ impl EventProcessor {
state,
position,
button: MouseButton::Middle.into(),
is_macos_activation_click: false,
},
xlib::Button3 => WindowEvent::PointerButton {
device_id,
@@ -1122,6 +1124,7 @@ impl EventProcessor {
state,
position,
button: MouseButton::Right.into(),
is_macos_activation_click: false,
},
// Suppress emulated scroll wheel clicks, since we handle the real motion events for
@@ -1151,6 +1154,7 @@ impl EventProcessor {
// Button 8 maps to MouseButton::BACK = 3; 36 maps to MouseButton::Button32.
// 255 is the largest code yielded on X11 (tested).
button: MouseButton::try_from_u8((x - 5) as u8).unwrap().into(),
is_macos_activation_click: false,
},
x @ 37..=0xff => WindowEvent::PointerButton {
device_id,
@@ -1159,6 +1163,7 @@ impl EventProcessor {
position,
// 255 is the largest code yielded on X11 (tested).
button: ButtonSource::Unknown(x as u16),
is_macos_activation_click: false,
},
_ => return,
};
@@ -1450,6 +1455,7 @@ impl EventProcessor {
state: ElementState::Pressed,
position,
button: ButtonSource::Touch { finger_id, force: None },
is_macos_activation_click: false,
};
app.window_event(&self.target, window_id, event);
},
@@ -1469,6 +1475,7 @@ impl EventProcessor {
state: ElementState::Released,
position,
button: ButtonSource::Touch { finger_id, force: None },
is_macos_activation_click: false,
};
app.window_event(&self.target, window_id, event);
let event = WindowEvent::PointerLeft {