Skip to content

Commit

Permalink
cocoa: be more careful about rejecting frame strut events
Browse files Browse the repository at this point in the history
The m_buttons property is meant to hold the currently pressed mouse
buttons done on the contents part of a QNSView. But m_buttons can
sometimes get out of sync with AppKit (NSEvent.pressedMouseButtons).
One way this is shown to happen is if you do a mouse press on a native
child widget (that is backed by it's own QNSView), and then convert the
widget to a top-level window before the release. In that case, the
underlying QNSView will be reparented from one NSWindow to another,
which will result in the old NSWindow getting the mouseUp call instead
of the new window. The result is that we don't update m_buttons for
the reparented QNSView, which will instead be left as "pressed".

As a result of m_buttons being stuck in a faulty state, we also refuse
to send out QEvent::NonClientAreaMouseMove events to the top-level
widget. This because QNSView thinks that it's already in a dragging
state that started on the content part of the view (and not on the
strut). As a result, it can sometimes be impossible to dock a
QDockWidget back into a QMainWindow, since we basically don't send
out any frame-drag events to Qt for the new dock window.

We can reason that if you start a mouse press on the frame strut, you
cannot at the same time have an active mouse press on the view contents.
This patch will therefore remove the buttons that we know was pressed
on the frame strut from m_buttons. This will at least (be one way to)
clear the faulty pressed state, and will let us send mouse
press/drag/release (and after that, move) frame strut events to Qt.

Pick-to: 6.1 5.15
Task-number: QTBUG-70137
Change-Id: If51e1fe57d2531b659d39de85658893dae6391e3
Reviewed-by: Tor Arne Vestbø <[email protected]>
  • Loading branch information
Richard Moe Gustavsen authored and torarnv committed May 12, 2021
1 parent 531d12e commit 78b6050
Showing 1 changed file with 16 additions and 7 deletions.
23 changes: 16 additions & 7 deletions src/plugins/platforms/cocoa/qnsview_mouse.mm
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,14 @@ - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
if (!m_platformWindow)
return;

// get m_buttons in sync
// Don't send frme strut events if we are in the middle of a mouse drag.
if (m_buttons != Qt::NoButton)
return;

switch (theEvent.type) {
case NSEventTypeLeftMouseDown:
case NSEventTypeLeftMouseDragged:
m_frameStrutButtons |= Qt::LeftButton;
break;
case NSEventTypeLeftMouseUp:
m_frameStrutButtons &= ~Qt::LeftButton;
break;
case NSEventTypeRightMouseDown:
case NSEventTypeRightMouseDragged:
m_frameStrutButtons |= Qt::RightButton;
break;
case NSEventTypeRightMouseUp:
Expand All @@ -132,6 +125,22 @@ - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
break;
}

// m_buttons can sometimes get out of sync with the button state in AppKit
// E.g if the QNSView where a drag starts is reparented to another window
// while the drag is ongoing, it will not get the corresponding mouseUp
// call. This will result in m_buttons to be stuck on Qt::LeftButton.
// Since we know which buttons was pressed/released directly on the frame
// strut, we can rectify m_buttons here so that we at least don't return early
// from the drag test underneath because of the faulty m_buttons state.
// FIXME: get m_buttons in sync with AppKit/NSEvent all over in QNSView.
m_buttons &= ~m_frameStrutButtons;

if (m_buttons != Qt::NoButton) {
// Don't send frame strut events if we are in the middle of
// a mouse drag that didn't start on the frame strut.
return;
}

NSWindow *window = [self window];
NSPoint windowPoint = [theEvent locationInWindow];

Expand Down

0 comments on commit 78b6050

Please sign in to comment.