NSComboBoxCell eats mouseUp events.

Originator:corey.lucier
Number:rdar://22536981 Date Originated:9/2/2015
Status:Open Resolved:
Product:OSX SDK Product Version:
Classification: Reproducible:
 
Summary:
When a combo box is a child of a transient NSPopover and you click outside the popover to dismiss the combo, the NSComboBoxCell dispatches a mousedown but not mouseup.

---

I have an NSComboBox child of an NSPopover. The popover is transient and is configured to dismiss when the user clicks outside its bounds.

When its combobox popup is active and displayed, and when the user mouses down on the popovers owning view, the view receives the mouse down as expected, the popover disappears and the combobox dismisses, however the very next mouseUp is never received by the view.

It turns out the NSComboBoxCell's trackMouse method (tracking loop) is not returning until it receives a mouseUp but unlike the case of mouseDown where it redispatches it nicely to the view that was clicked on, it never propagates the mouseUp.

I had to work around the issue with the following NSComboBoxCell trackMouse override.

Steps to Reproduce:
1. Run Test sample make sure debug console is active and open.
2. Push the button to open NSPopover.
3. Drop the combobox down.
4. Single click outside to the left of the NSPopover to dismiss it, make sure not to move the mouse, then mouse up.
5. 90% of the time you only get mouseDown, not mouseUp reported to console.

Contrast that with the combobox that's parented by the view itself, open the combo there and click outside it ... no mouseDown or mouseUp - this I expect is the desired behavior.

Expected Results:
Should have either seen mouseUp and mouseDown, or neither (per the normal case with combobox), but NEVER a mouseDown and no mouseUp.

Actual Results:
Parent view receivers a mouseDown with no mouseUp...obvious problematic.  NSComboBoxCell trackMouse is dismissing itself with mouseUp but not re-dispatching the mouseUp.

Some notes:

// Normally trackMouse eats all mouse events and doesn't let them get to other controls. However, IF we are inside an NSPopover
    // clicking to dismiss the combobox dropdown will send a mouseDown with no matching mouseUp to the view the user clicked on.
    // We need to prevent such asymmetrical mouseDown/Ups to avoid getting the canvas into a bad state.
    //
    // The NSComboBoxCell trackMouse call blocks and runs an event loop, with different lifespan depending on type of interaction:
    //
    // a) Open dropdown & select item in one gesture, via click-drag - starts on the mouseDown that opens the dropdown and ends
    //      after the drag's mouseUp. Last event processed: NSApplicationDefined (presumably the "select").
    // b) Open drodown via click, click to select an item - starts on the mouseDown that opens the dropdown, continues past that
    //      mouseUp, continues into 2nd mouseDown, and ends after the mouseUp that finalizes that 2nd click. Last event processed:
    //      NSApplicationDefined.
    // c) Open dropdown via click, click-drag to select an item - same as case B.
    // d) Open dropdown via click, click outside dropdown to close - starts on the mouseDown that opens the dropdown, continues
    //      past that click's mouseUp, continues into 2nd mouseDown*, and ends on the 2nd mouseUp. Last event processed: NSLeftMouseUp.
    //      * IF combobox is inside an NSPopover, the 2nd mouseDown (i.e. the one outside the dropdown) is forwarded to whatever
    //        view the mouse is over, but the 2nd mouseUp that follows it is NOT forwarded. *THIS IS THE BUGGY CASE*
    // e) Open dropdown via click, drag outside dropdown to close - starts on the mouseDown that opens the dropdown, continues
    //      past that click's mouseUp, continues into 2nd mouseDown*, and ends on the *very next mouseMove* - does NOT wait for
    //      mouseUp. Last event processed: NSLeftMouseDragged.
    //      * IF combobox is inside an NSPopover, the 2nd mouseDown is forwarded to whatever view the mouse is over, AND the
    //        subsequent mouseDraggeds (after trackMouse exits) and mouseUp are all sent normally to that view. Normally, none of
    //        those events make it to the view.
    // f) Open dropdown via click, press Enter to select an item - starts on the mouseDown of the click, continues past the mouseUp,
    //      and ends on the keyDown of the Enter key. Last event processed: NSKeyDown.
    // g) Open dropdown via click, press Esc to close - same as case G.
    //
    // The "*" behavior in case D is the only reason we need the workaround below - the view the user clicked on gets a mouseDown but
    // no matching mouseUp in that case. Our workaround below ensures the view receives a mouseUp too.

Version:
XCode 6.4

Notes:


Configuration:
Latest OSX SDK - 10.10

Attachments:
'Combobox in popover test.zip' was successfully uploaded.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!