mirror of
https://github.com/rust-windowing/winit.git
synced 2026-08-29 04:40:04 -04:00
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:
committed by
Simon Hausmann
parent
92b643c3f1
commit
6a8a334426
@@ -383,6 +383,7 @@ impl EventLoop {
|
|||||||
android_activity::input::ToolType::Mouse => continue,
|
android_activity::input::ToolType::Mouse => continue,
|
||||||
_ => event::ButtonSource::Unknown(0),
|
_ => event::ButtonSource::Unknown(0),
|
||||||
},
|
},
|
||||||
|
is_macos_activation_click: false,
|
||||||
};
|
};
|
||||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||||
},
|
},
|
||||||
@@ -426,6 +427,7 @@ impl EventLoop {
|
|||||||
android_activity::input::ToolType::Mouse => continue,
|
android_activity::input::ToolType::Mouse => continue,
|
||||||
_ => event::ButtonSource::Unknown(0),
|
_ => event::ButtonSource::Unknown(0),
|
||||||
},
|
},
|
||||||
|
is_macos_activation_click: false,
|
||||||
};
|
};
|
||||||
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
app.window_event(&self.window_target, GLOBAL_WINDOW, event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -367,7 +367,6 @@ pub struct WindowAttributesMacOS {
|
|||||||
pub(crate) fullsize_content_view: bool,
|
pub(crate) fullsize_content_view: bool,
|
||||||
pub(crate) disallow_hidpi: bool,
|
pub(crate) disallow_hidpi: bool,
|
||||||
pub(crate) has_shadow: bool,
|
pub(crate) has_shadow: bool,
|
||||||
pub(crate) accepts_first_mouse: bool,
|
|
||||||
pub(crate) tabbing_identifier: Option<String>,
|
pub(crate) tabbing_identifier: Option<String>,
|
||||||
pub(crate) option_as_alt: OptionAsAlt,
|
pub(crate) option_as_alt: OptionAsAlt,
|
||||||
pub(crate) borderless_game: bool,
|
pub(crate) borderless_game: bool,
|
||||||
@@ -431,13 +430,6 @@ impl WindowAttributesMacOS {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Window accepts click-through mouse events.
|
|
||||||
#[inline]
|
|
||||||
pub fn with_accepts_first_mouse(mut self, accepts_first_mouse: bool) -> Self {
|
|
||||||
self.accepts_first_mouse = accepts_first_mouse;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines the window tabbing identifier.
|
/// Defines the window tabbing identifier.
|
||||||
///
|
///
|
||||||
/// <https://developer.apple.com/documentation/appkit/nswindow/1644704-tabbingidentifier>
|
/// <https://developer.apple.com/documentation/appkit/nswindow/1644704-tabbingidentifier>
|
||||||
@@ -506,7 +498,6 @@ impl Default for WindowAttributesMacOS {
|
|||||||
fullsize_content_view: false,
|
fullsize_content_view: false,
|
||||||
disallow_hidpi: false,
|
disallow_hidpi: false,
|
||||||
has_shadow: true,
|
has_shadow: true,
|
||||||
accepts_first_mouse: true,
|
|
||||||
tabbing_identifier: None,
|
tabbing_identifier: None,
|
||||||
option_as_alt: Default::default(),
|
option_as_alt: Default::default(),
|
||||||
borderless_game: false,
|
borderless_game: false,
|
||||||
|
|||||||
@@ -138,7 +138,10 @@ pub struct ViewState {
|
|||||||
/// to the application, even during IME
|
/// to the application, even during IME
|
||||||
forward_key_to_app: Cell<bool>,
|
forward_key_to_app: Cell<bool>,
|
||||||
marked_text: RefCell<Retained<NSMutableAttributedString>>,
|
marked_text: RefCell<Retained<NSMutableAttributedString>>,
|
||||||
accepts_first_mouse: bool,
|
|
||||||
|
/// Set by `acceptsFirstMouse:` so the next `mouseDown:` can tag its
|
||||||
|
/// [`WindowEvent::PointerButton`] with `is_macos_activation_click: true`.
|
||||||
|
next_click_is_activation: Cell<bool>,
|
||||||
|
|
||||||
/// The state of the `Option` as `Alt`.
|
/// The state of the `Option` as `Alt`.
|
||||||
option_as_alt: Cell<OptionAsAlt>,
|
option_as_alt: Cell<OptionAsAlt>,
|
||||||
@@ -780,9 +783,18 @@ define_class!(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(method(acceptsFirstMouse:))]
|
#[unsafe(method(acceptsFirstMouse:))]
|
||||||
fn accepts_first_mouse(&self, _event: &NSEvent) -> bool {
|
fn accepts_first_mouse(&self, event: Option<&NSEvent>) -> bool {
|
||||||
let _entered = debug_span!("acceptsFirstMouse:").entered();
|
let _entered = debug_span!("acceptsFirstMouse:").entered();
|
||||||
self.ivars().accepts_first_mouse
|
// Always accept the click. The following `mouseDown:` is tagged with
|
||||||
|
// `is_macos_activation_click: true` so the application can decide per click
|
||||||
|
// whether to act on it.
|
||||||
|
//
|
||||||
|
// AppKit may pass nil here for synthetic queries that are not tied to a
|
||||||
|
// specific click; only set the flag when we actually have an event.
|
||||||
|
if event.is_some() {
|
||||||
|
self.ivars().next_click_is_activation.set(true);
|
||||||
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -790,7 +802,6 @@ define_class!(
|
|||||||
impl WinitView {
|
impl WinitView {
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
app_state: &Rc<AppState>,
|
app_state: &Rc<AppState>,
|
||||||
accepts_first_mouse: bool,
|
|
||||||
option_as_alt: OptionAsAlt,
|
option_as_alt: OptionAsAlt,
|
||||||
mtm: MainThreadMarker,
|
mtm: MainThreadMarker,
|
||||||
) -> Retained<Self> {
|
) -> Retained<Self> {
|
||||||
@@ -808,7 +819,7 @@ impl WinitView {
|
|||||||
ime_capabilities: Default::default(),
|
ime_capabilities: Default::default(),
|
||||||
forward_key_to_app: Default::default(),
|
forward_key_to_app: Default::default(),
|
||||||
marked_text: Default::default(),
|
marked_text: Default::default(),
|
||||||
accepts_first_mouse,
|
next_click_is_activation: Default::default(),
|
||||||
option_as_alt: Cell::new(option_as_alt),
|
option_as_alt: Cell::new(option_as_alt),
|
||||||
});
|
});
|
||||||
let this: Retained<Self> = unsafe { msg_send![super(this), init] };
|
let this: Retained<Self> = unsafe { msg_send![super(this), init] };
|
||||||
@@ -1155,12 +1166,23 @@ impl WinitView {
|
|||||||
|
|
||||||
self.update_modifiers(event, false);
|
self.update_modifiers(event, false);
|
||||||
|
|
||||||
|
// `acceptsFirstMouse:` fires only for the left button, so the activation flag is
|
||||||
|
// applied to the left press and held until the matching left release. This lets
|
||||||
|
// apps short-circuit both events with a single `if is_macos_activation_click` check
|
||||||
|
// without having to track gesture state themselves.
|
||||||
|
let is_macos_activation_click = matches!(button, MouseButton::Left)
|
||||||
|
&& match button_state {
|
||||||
|
ElementState::Pressed => self.ivars().next_click_is_activation.get(),
|
||||||
|
ElementState::Released => self.ivars().next_click_is_activation.replace(false),
|
||||||
|
};
|
||||||
|
|
||||||
self.queue_event(WindowEvent::PointerButton {
|
self.queue_event(WindowEvent::PointerButton {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
primary: true,
|
primary: true,
|
||||||
state: button_state,
|
state: button_state,
|
||||||
position,
|
position,
|
||||||
button: button.into(),
|
button: button.into(),
|
||||||
|
is_macos_activation_click,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -842,12 +842,7 @@ fn new_window(
|
|||||||
window.center();
|
window.center();
|
||||||
}
|
}
|
||||||
|
|
||||||
let view = WinitView::new(
|
let view = WinitView::new(app_state, macos_attrs.option_as_alt, mtm);
|
||||||
app_state,
|
|
||||||
macos_attrs.accepts_first_mouse,
|
|
||||||
macos_attrs.option_as_alt,
|
|
||||||
mtm,
|
|
||||||
);
|
|
||||||
|
|
||||||
// The default value of `setWantsBestResolutionOpenGLSurface:` was `false` until
|
// The default value of `setWantsBestResolutionOpenGLSurface:` was `false` until
|
||||||
// macos 10.14 and `true` after 10.15, we should set it to `YES` or `NO` to avoid
|
// macos 10.14 and `true` after 10.15, we should set it to `YES` or `NO` to avoid
|
||||||
|
|||||||
@@ -329,6 +329,25 @@ pub enum WindowEvent {
|
|||||||
primary: bool,
|
primary: bool,
|
||||||
|
|
||||||
button: ButtonSource,
|
button: ButtonSource,
|
||||||
|
|
||||||
|
/// Whether this event is part of the click that activated an otherwise inactive window.
|
||||||
|
///
|
||||||
|
/// On macOS, AppKit normally consumes the click that brings a window forward without
|
||||||
|
/// delivering it as a regular mouse event (controlled by [`acceptsFirstMouse:`]). Winit
|
||||||
|
/// always delivers it, but tags both the activating press *and* its matching release
|
||||||
|
/// with this flag so applications can short-circuit the whole gesture with a single
|
||||||
|
/// check — e.g. ignore activation clicks for destructive or button-like targets while
|
||||||
|
/// accepting them for low-risk actions (selection, scrolling).
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **Only available on macOS.** Always `false` on every other platform.
|
||||||
|
/// - Only ever `true` for the left mouse button. Intervening drag motion (delivered as
|
||||||
|
/// [`WindowEvent::PointerMoved`]) is not tagged; applications that care about drags
|
||||||
|
/// during the activation gesture must track that state themselves.
|
||||||
|
///
|
||||||
|
/// [`acceptsFirstMouse:`]: https://developer.apple.com/documentation/appkit/nsview/acceptsfirstmouse(_:)
|
||||||
|
is_macos_activation_click: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Multi-finger hold gesture on the touchpad or touchscreen without movement.
|
/// Multi-finger hold gesture on the touchpad or touchscreen without movement.
|
||||||
@@ -1689,6 +1708,7 @@ mod tests {
|
|||||||
state: event::ElementState::Pressed,
|
state: event::ElementState::Pressed,
|
||||||
position: (0, 0).into(),
|
position: (0, 0).into(),
|
||||||
button: event::ButtonSource::Unknown(0),
|
button: event::ButtonSource::Unknown(0),
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
with_window_event(PointerButton {
|
with_window_event(PointerButton {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
@@ -1699,6 +1719,7 @@ mod tests {
|
|||||||
finger_id: fid,
|
finger_id: fid,
|
||||||
force: Some(event::Force::Normalized(0.0)),
|
force: Some(event::Force::Normalized(0.0)),
|
||||||
},
|
},
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
with_window_event(PinchGesture {
|
with_window_event(PinchGesture {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
|
|||||||
@@ -460,6 +460,7 @@ impl EventLoop {
|
|||||||
state,
|
state,
|
||||||
position: event_state.mouse_pos.into(),
|
position: event_state.mouse_pos.into(),
|
||||||
button: button.into(),
|
button: button.into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -571,6 +571,7 @@ impl WinitView {
|
|||||||
} else {
|
} else {
|
||||||
ButtonSource::Touch { finger_id, force }
|
ButtonSource::Touch { finger_id, force }
|
||||||
},
|
},
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -629,6 +630,7 @@ impl WinitView {
|
|||||||
} else {
|
} else {
|
||||||
ButtonSource::Touch { finger_id, force }
|
ButtonSource::Touch { finger_id, force }
|
||||||
},
|
},
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ impl PointerHandler for WinitState {
|
|||||||
state,
|
state,
|
||||||
position,
|
position,
|
||||||
button,
|
button,
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
window_id,
|
window_id,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ impl TouchHandler for WinitState {
|
|||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
position,
|
position,
|
||||||
button: ButtonSource::Touch { finger_id, force: None },
|
button: ButtonSource::Touch { finger_id, force: None },
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
window_id,
|
window_id,
|
||||||
);
|
);
|
||||||
@@ -120,6 +121,7 @@ impl TouchHandler for WinitState {
|
|||||||
state: ElementState::Released,
|
state: ElementState::Released,
|
||||||
position,
|
position,
|
||||||
button: ButtonSource::Touch { finger_id, force: None },
|
button: ButtonSource::Touch { finger_id, force: None },
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
window_id,
|
window_id,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ impl Dispatch2<ZwpTabletToolV2, WinitState> for TabletToolData {
|
|||||||
button,
|
button,
|
||||||
data: data.tool_state.clone(),
|
data: data.tool_state.clone(),
|
||||||
},
|
},
|
||||||
|
is_macos_activation_click: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TabletEvent::Left => WindowEvent::PointerLeft {
|
TabletEvent::Left => WindowEvent::PointerLeft {
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ impl ActiveEventLoop {
|
|||||||
state,
|
state,
|
||||||
position,
|
position,
|
||||||
button,
|
button,
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
}]));
|
}]));
|
||||||
}
|
}
|
||||||
@@ -323,6 +324,7 @@ impl ActiveEventLoop {
|
|||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
position,
|
position,
|
||||||
button,
|
button,
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
@@ -351,6 +353,7 @@ impl ActiveEventLoop {
|
|||||||
state: ElementState::Released,
|
state: ElementState::Released,
|
||||||
position,
|
position,
|
||||||
button,
|
button,
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1873,6 +1873,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
result = ProcResult::Value(0);
|
result = ProcResult::Value(0);
|
||||||
},
|
},
|
||||||
@@ -1902,6 +1903,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
result = ProcResult::Value(0);
|
result = ProcResult::Value(0);
|
||||||
},
|
},
|
||||||
@@ -1930,6 +1932,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
position,
|
position,
|
||||||
// 1 is defined as back, 2 as forward; other codes are unexpected.
|
// 1 is defined as back, 2 as forward; other codes are unexpected.
|
||||||
button: MouseButton::try_from_u8(b).unwrap().into(),
|
button: MouseButton::try_from_u8(b).unwrap().into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
result = ProcResult::Value(0);
|
result = ProcResult::Value(0);
|
||||||
},
|
},
|
||||||
@@ -1959,6 +1962,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
position,
|
position,
|
||||||
// 1 is defined as back, 2 as forward; other codes are unexpected.
|
// 1 is defined as back, 2 as forward; other codes are unexpected.
|
||||||
button: MouseButton::try_from_u8(b).unwrap().into(),
|
button: MouseButton::try_from_u8(b).unwrap().into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
result = ProcResult::Value(0);
|
result = ProcResult::Value(0);
|
||||||
},
|
},
|
||||||
@@ -2018,6 +2022,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
state: Pressed,
|
state: Pressed,
|
||||||
position,
|
position,
|
||||||
button: Touch { finger_id, force: None },
|
button: Touch { finger_id, force: None },
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
} else if util::has_flag(input.dwFlags, TOUCHEVENTF_UP) {
|
} else if util::has_flag(input.dwFlags, TOUCHEVENTF_UP) {
|
||||||
userdata.send_window_event(window, WindowEvent::PointerButton {
|
userdata.send_window_event(window, WindowEvent::PointerButton {
|
||||||
@@ -2026,6 +2031,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
state: Released,
|
state: Released,
|
||||||
position,
|
position,
|
||||||
button: Touch { finger_id, force: None },
|
button: Touch { finger_id, force: None },
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
userdata.send_window_event(window, WindowEvent::PointerLeft {
|
userdata.send_window_event(window, WindowEvent::PointerLeft {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
@@ -2187,6 +2193,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
state: Pressed,
|
state: Pressed,
|
||||||
position,
|
position,
|
||||||
button,
|
button,
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
userdata.send_window_event(window, WindowEvent::PointerButton {
|
userdata.send_window_event(window, WindowEvent::PointerButton {
|
||||||
@@ -2195,6 +2202,7 @@ unsafe fn public_window_callback_inner(
|
|||||||
state: Released,
|
state: Released,
|
||||||
position,
|
position,
|
||||||
button,
|
button,
|
||||||
|
is_macos_activation_click: false,
|
||||||
});
|
});
|
||||||
userdata.send_window_event(window, WindowEvent::PointerLeft {
|
userdata.send_window_event(window, WindowEvent::PointerLeft {
|
||||||
device_id: None,
|
device_id: None,
|
||||||
|
|||||||
@@ -1108,6 +1108,7 @@ impl EventProcessor {
|
|||||||
state,
|
state,
|
||||||
position,
|
position,
|
||||||
button: MouseButton::Left.into(),
|
button: MouseButton::Left.into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
xlib::Button2 => WindowEvent::PointerButton {
|
xlib::Button2 => WindowEvent::PointerButton {
|
||||||
device_id,
|
device_id,
|
||||||
@@ -1115,6 +1116,7 @@ impl EventProcessor {
|
|||||||
state,
|
state,
|
||||||
position,
|
position,
|
||||||
button: MouseButton::Middle.into(),
|
button: MouseButton::Middle.into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
xlib::Button3 => WindowEvent::PointerButton {
|
xlib::Button3 => WindowEvent::PointerButton {
|
||||||
device_id,
|
device_id,
|
||||||
@@ -1122,6 +1124,7 @@ impl EventProcessor {
|
|||||||
state,
|
state,
|
||||||
position,
|
position,
|
||||||
button: MouseButton::Right.into(),
|
button: MouseButton::Right.into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Suppress emulated scroll wheel clicks, since we handle the real motion events for
|
// 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.
|
// Button 8 maps to MouseButton::BACK = 3; 36 maps to MouseButton::Button32.
|
||||||
// 255 is the largest code yielded on X11 (tested).
|
// 255 is the largest code yielded on X11 (tested).
|
||||||
button: MouseButton::try_from_u8((x - 5) as u8).unwrap().into(),
|
button: MouseButton::try_from_u8((x - 5) as u8).unwrap().into(),
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
x @ 37..=0xff => WindowEvent::PointerButton {
|
x @ 37..=0xff => WindowEvent::PointerButton {
|
||||||
device_id,
|
device_id,
|
||||||
@@ -1159,6 +1163,7 @@ impl EventProcessor {
|
|||||||
position,
|
position,
|
||||||
// 255 is the largest code yielded on X11 (tested).
|
// 255 is the largest code yielded on X11 (tested).
|
||||||
button: ButtonSource::Unknown(x as u16),
|
button: ButtonSource::Unknown(x as u16),
|
||||||
|
is_macos_activation_click: false,
|
||||||
},
|
},
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
@@ -1450,6 +1455,7 @@ impl EventProcessor {
|
|||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed,
|
||||||
position,
|
position,
|
||||||
button: ButtonSource::Touch { finger_id, force: None },
|
button: ButtonSource::Touch { finger_id, force: None },
|
||||||
|
is_macos_activation_click: false,
|
||||||
};
|
};
|
||||||
app.window_event(&self.target, window_id, event);
|
app.window_event(&self.target, window_id, event);
|
||||||
},
|
},
|
||||||
@@ -1469,6 +1475,7 @@ impl EventProcessor {
|
|||||||
state: ElementState::Released,
|
state: ElementState::Released,
|
||||||
position,
|
position,
|
||||||
button: ButtonSource::Touch { finger_id, force: None },
|
button: ButtonSource::Touch { finger_id, force: None },
|
||||||
|
is_macos_activation_click: false,
|
||||||
};
|
};
|
||||||
app.window_event(&self.target, window_id, event);
|
app.window_event(&self.target, window_id, event);
|
||||||
let event = WindowEvent::PointerLeft {
|
let event = WindowEvent::PointerLeft {
|
||||||
|
|||||||
@@ -474,8 +474,15 @@ impl ApplicationHandler for Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WindowEvent::PointerButton { button, state, .. } => {
|
WindowEvent::PointerButton { button, state, is_macos_activation_click, .. } => {
|
||||||
info!("Pointer button {button:?} {state:?}");
|
info!("Pointer button {button:?} {state:?}");
|
||||||
|
// On macOS, drop both press and release of the click that activated this
|
||||||
|
// window — real apps would typically skip destructive or button-target
|
||||||
|
// actions for such clicks; this example just logs them.
|
||||||
|
if is_macos_activation_click {
|
||||||
|
info!("(macOS activation click — ignoring)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let mods = window.modifiers;
|
let mods = window.modifiers;
|
||||||
if let Some(action) = state
|
if let Some(action) = state
|
||||||
.is_pressed()
|
.is_pressed()
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ changelog entry.
|
|||||||
window to be shown on the same Space as a fullscreen window
|
window to be shown on the same Space as a fullscreen window
|
||||||
(`NSWindowCollectionBehaviorFullScreenAuxiliary`) instead of triggering a Space switch or Split
|
(`NSWindowCollectionBehaviorFullScreenAuxiliary`) instead of triggering a Space switch or Split
|
||||||
View tiling.
|
View tiling.
|
||||||
|
- Add `WindowEvent::PointerButton::is_macos_activation_click`. On macOS, both the press and
|
||||||
|
matching release of a click that activated a previously inactive window are tagged, so
|
||||||
|
applications can ignore activation clicks for buttons or destructive actions while accepting
|
||||||
|
them for low-risk actions like selection or scrolling. Always `false` on other platforms.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@@ -64,6 +68,13 @@ changelog entry.
|
|||||||
- On older macOS versions (tested up to 12.7.6), applications now receive mouse movement events for unfocused windows, matching the behavior on other platforms.
|
- On older macOS versions (tested up to 12.7.6), applications now receive mouse movement events for unfocused windows, matching the behavior on other platforms.
|
||||||
- On macOS, using the private API `CGSSetWindowBackgroundBlurRadius` for `Window::set_blur` is now disabled by default. It can be re-enabled using the Cargo feature `private-apple-apis`.
|
- On macOS, using the private API `CGSSetWindowBackgroundBlurRadius` for `Window::set_blur` is now disabled by default. It can be re-enabled using the Cargo feature `private-apple-apis`.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- On macOS, remove `WindowAttributesMacOS::with_accepts_first_mouse`. Use the new per-event
|
||||||
|
`WindowEvent::PointerButton::is_macos_activation_click` flag instead. To preserve the old
|
||||||
|
`with_accepts_first_mouse(false)` behavior, ignore `PointerButton` press events (and their
|
||||||
|
matching releases / drags) where `is_macos_activation_click` is `true`.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- On Windows, fix a freeze that occurs when the keyboard layout is switched by
|
- On Windows, fix a freeze that occurs when the keyboard layout is switched by
|
||||||
|
|||||||
Reference in New Issue
Block a user