|
| 1 | +From 78b6050d60ba97ffb66e79bcde6ea306108e41dd Mon Sep 17 00:00:00 2001 |
| 2 | +From: Richard Moe Gustavsen <richard.gustavsen@qt.io> |
| 3 | +Date: Tue, 11 May 2021 13:22:57 +0200 |
| 4 | +Subject: [PATCH] cocoa: be more careful about rejecting frame strut events |
| 5 | + |
| 6 | +The m_buttons property is meant to hold the currently pressed mouse |
| 7 | +buttons done on the contents part of a QNSView. But m_buttons can |
| 8 | +sometimes get out of sync with AppKit (NSEvent.pressedMouseButtons). |
| 9 | +One way this is shown to happen is if you do a mouse press on a native |
| 10 | +child widget (that is backed by it's own QNSView), and then convert the |
| 11 | +widget to a top-level window before the release. In that case, the |
| 12 | +underlying QNSView will be reparented from one NSWindow to another, |
| 13 | +which will result in the old NSWindow getting the mouseUp call instead |
| 14 | +of the new window. The result is that we don't update m_buttons for |
| 15 | +the reparented QNSView, which will instead be left as "pressed". |
| 16 | + |
| 17 | +As a result of m_buttons being stuck in a faulty state, we also refuse |
| 18 | +to send out QEvent::NonClientAreaMouseMove events to the top-level |
| 19 | +widget. This because QNSView thinks that it's already in a dragging |
| 20 | +state that started on the content part of the view (and not on the |
| 21 | +strut). As a result, it can sometimes be impossible to dock a |
| 22 | +QDockWidget back into a QMainWindow, since we basically don't send |
| 23 | +out any frame-drag events to Qt for the new dock window. |
| 24 | + |
| 25 | +We can reason that if you start a mouse press on the frame strut, you |
| 26 | +cannot at the same time have an active mouse press on the view contents. |
| 27 | +This patch will therefore remove the buttons that we know was pressed |
| 28 | +on the frame strut from m_buttons. This will at least (be one way to) |
| 29 | +clear the faulty pressed state, and will let us send mouse |
| 30 | +press/drag/release (and after that, move) frame strut events to Qt. |
| 31 | + |
| 32 | +Pick-to: 6.1 5.15 |
| 33 | +Task-number: QTBUG-70137 |
| 34 | +Change-Id: If51e1fe57d2531b659d39de85658893dae6391e3 |
| 35 | +Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> |
| 36 | +--- |
| 37 | + |
| 38 | +diff --git ./qtbase/src/plugins/platforms/cocoa/qnsview_mouse.mm ./qtbase/src/plugins/platforms/cocoa/qnsview_mouse.mm |
| 39 | +index d00cfb7..54a1f06 100644 |
| 40 | +--- ./qtbase/src/plugins/platforms/cocoa/qnsview_mouse.mm |
| 41 | ++++ ./qtbase/src/plugins/platforms/cocoa/qnsview_mouse.mm |
| 42 | +@@ -103,21 +103,14 @@ |
| 43 | + if (!m_platformWindow) |
| 44 | + return; |
| 45 | + |
| 46 | +- // get m_buttons in sync |
| 47 | +- // Don't send frme strut events if we are in the middle of a mouse drag. |
| 48 | +- if (m_buttons != Qt::NoButton) |
| 49 | +- return; |
| 50 | +- |
| 51 | + switch (theEvent.type) { |
| 52 | + case NSEventTypeLeftMouseDown: |
| 53 | +- case NSEventTypeLeftMouseDragged: |
| 54 | + m_frameStrutButtons |= Qt::LeftButton; |
| 55 | + break; |
| 56 | + case NSEventTypeLeftMouseUp: |
| 57 | + m_frameStrutButtons &= ~Qt::LeftButton; |
| 58 | + break; |
| 59 | + case NSEventTypeRightMouseDown: |
| 60 | +- case NSEventTypeRightMouseDragged: |
| 61 | + m_frameStrutButtons |= Qt::RightButton; |
| 62 | + break; |
| 63 | + case NSEventTypeRightMouseUp: |
| 64 | +@@ -132,6 +125,22 @@ |
| 65 | + break; |
| 66 | + } |
| 67 | + |
| 68 | ++ // m_buttons can sometimes get out of sync with the button state in AppKit |
| 69 | ++ // E.g if the QNSView where a drag starts is reparented to another window |
| 70 | ++ // while the drag is ongoing, it will not get the corresponding mouseUp |
| 71 | ++ // call. This will result in m_buttons to be stuck on Qt::LeftButton. |
| 72 | ++ // Since we know which buttons was pressed/released directly on the frame |
| 73 | ++ // strut, we can rectify m_buttons here so that we at least don't return early |
| 74 | ++ // from the drag test underneath because of the faulty m_buttons state. |
| 75 | ++ // FIXME: get m_buttons in sync with AppKit/NSEvent all over in QNSView. |
| 76 | ++ m_buttons &= ~m_frameStrutButtons; |
| 77 | ++ |
| 78 | ++ if (m_buttons != Qt::NoButton) { |
| 79 | ++ // Don't send frame strut events if we are in the middle of |
| 80 | ++ // a mouse drag that didn't start on the frame strut. |
| 81 | ++ return; |
| 82 | ++ } |
| 83 | ++ |
| 84 | + NSWindow *window = [self window]; |
| 85 | + NSPoint windowPoint = [theEvent locationInWindow]; |
| 86 | + |
0 commit comments