NSSplitView
has a divider style called NSSplitViewDividerStyleThin
which has become the norm on recent versions of OS X. It simply draws a 1-pixel wide solid line to represent the divider. However, the actual tracking area for the divider is about 3-5 pixels wide, allowing the user to click a little bit on either side of the divider to initiate a drag.
Since the split view's subview are laid out such that they really are only 1-pixel apart from each other, how is the split view tracking the cursor and mouse down events such that it's able to intercept any that occur slightly outside of the divider's "frame". Normally those events fall through to the underlying view (like a scroll bar flush against the divider).
First Thought:
That NSSplitView
just had a 3-5 pixel wide, transparent subview for the divider that was placed over top of its two (or more) content views. But if I query the splitview for the number of subviews it has, it only returns 2. Likewise if I inspect using something like F-Script.
It's also been discussed in this Stack Overflow question that overlapping sibling views aren't really supported by AppKit:
Is there a proper way to handle overlapping NSView siblings?
Second Thought:
That maybe NSSplitView
was just using an NSTrackingArea
for the divider but if I ask the split view for its tracking areas, none are returned. And even if it was using a tracking area, can tracking areas on parent views override tracking areas on subviews? (I'd assume a subview's scrollbar, for example, would take precedence- but it doesn't in a split view.)
Third Thought:
That maybe NSSplitView
was using some sort of transparent window that is overlaid on top, but unless I'm looking in the wrong place, I don't see any extra windows being created.
Fourth Thought:
That NSSplitView
was using a local event monitor to track all mouse moved and mouse down events that are destined for the application and intercepting any that would be inside the split view's tracking area, even if the events technically over a subview.
So how is NSSplitView
able to intercept mouse events that are outside of the visual 1-pixel wide space drawn for the thin border and instead occur over one of its subviews?
First, it appears that NSSplitView
overrides -resetCursorRects
and, within that method, adds cursor rects using -addCursorRect:cursor:
. That's how it arranges for the cursor to change in the vicinity of its divider(s).
Second, it overrides -hitTest:
. Mouse events are routed to views by -[NSWindow sendEvent:]
. That uses -hitTest:
to ask its views (e.g. contentView
and the theme frame stuff) which descendant view was hit. When it finds which view was hit, it calls -mouseDown:
(or similar, depending on the exact event) on that view. So, a view can prevent mouse events from being routed to its subviews. It can return itself from its override of -hitTest:
even if the point is actually within one of its subviews and the mouse event will be delivered to it rather than the subview.