Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/gl/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ impl GlContext {
let _: () = msg_send![self.view, setNeedsDisplay: YES];
}
}

/// Pointer to the `NSOpenGLView` this context renders into. Used by
/// the parent `NSView`'s `hitTest:` override to collapse hits on the
/// render subview to the parent, so AppKit routes `mouseDown:` on
/// first click in non-key windows.
pub(crate) fn ns_view(&self) -> id {
self.view
}
}

impl Drop for GlContext {
Expand Down
9 changes: 9 additions & 0 deletions src/gl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,13 @@ impl GlContext {
pub(crate) fn resize(&self, size: cocoa::foundation::NSSize) {
self.context.resize(size);
}

/// Pointer to the `NSOpenGLView` this context renders into. Used by
/// the parent `NSView`'s `hitTest:` override to collapse hits on the
/// render subview to the parent, so AppKit routes `mouseDown:` on
/// first click in non-key windows.
#[cfg(target_os = "macos")]
pub(crate) fn ns_view(&self) -> cocoa::base::id {
self.context.ns_view()
}
}
46 changes: 46 additions & 0 deletions src/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ unsafe fn create_view_class() -> &'static Class {
sel!(viewWillMoveToWindow:),
view_will_move_to_window as extern "C" fn(&Object, Sel, id),
);
class.add_method(sel!(hitTest:), hit_test as extern "C" fn(&Object, Sel, NSPoint) -> id);
class.add_method(
sel!(updateTrackingAreas:),
update_tracking_areas as extern "C" fn(&Object, Sel, id),
Expand Down Expand Up @@ -346,6 +347,51 @@ unsafe fn reinit_tracking_area(this: &Object, tracking_area: *mut Object) {
];
}

/// `hitTest:` override that collapses hits on baseview's internal
/// OpenGL render subview to this NSView.
///
/// `src/gl/macos.rs` attaches an `NSOpenGLView` as a subview of this
/// view so the GL context is isolated from event handling. The side
/// effect is that `[NSView hitTest:]` returns the GL subview for
/// every click inside our frame — `NSOpenGLView` inherits the
/// default `acceptsFirstMouse:` which returns `NO`, so AppKit treats
/// the first click in a non-key window as an activation click and
/// never dispatches `mouseDown:`. That's the "first click dead zone"
/// symptom reported in baseview#129 / #202 / #169.
///
/// Fix: if the hit lands on our own GL render subview (pointer
/// equality against the `NSOpenGLView` stored in `GlContext`),
/// collapse the result to `self`. AppKit then asks US about
/// `acceptsFirstMouse:` (we return `YES`), and `mouseDown:` is
/// dispatched on the first click. Hits on any other subview pass
/// through unchanged — we only redirect our own render child, not
/// anything the consumer may add.
///
/// No-op without the `opengl` feature: there's no GL subview to
/// collapse, so the override pass-through is equivalent to the
/// default implementation.
extern "C" fn hit_test(this: &Object, _sel: Sel, point: NSPoint) -> id {
let super_result: id = unsafe {
let superclass = msg_send![this, superclass];
msg_send![super(this, superclass), hitTest: point]
};
if super_result == nil {
return nil;
}

#[cfg(feature = "opengl")]
unsafe {
let state = WindowState::from_view(this);
if let Some(gl_context) = state.window_inner.gl_context.as_ref() {
if super_result == gl_context.ns_view() {
return this as *const _ as id;
}
}
}
Comment thread
micahrj marked this conversation as resolved.

super_result
}

extern "C" fn view_will_move_to_window(this: &Object, _self: Sel, new_window: id) {
unsafe {
let tracking_areas: *mut Object = msg_send![this, trackingAreas];
Expand Down
2 changes: 1 addition & 1 deletion src/macos/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub(super) struct WindowInner {
ns_view: id,

#[cfg(feature = "opengl")]
gl_context: Option<GlContext>,
pub(super) gl_context: Option<GlContext>,
}

impl WindowInner {
Expand Down
Loading