diff options
author | Edward Welbourne <edward.welbourne@qt.io> | 2018-07-27 11:22:57 +0200 |
---|---|---|
committer | Edward Welbourne <edward.welbourne@qt.io> | 2018-07-31 13:33:14 +0200 |
commit | 23c9d4c98f3c6729b56700edc1d7144b444b16db (patch) | |
tree | 27b20ccbf3c101dbc7bcb1e509882b6c7fc75962 /src/plugins | |
parent | f69a5857d115786f44d053e68c36f74526020e82 (diff) | |
parent | 0ef66e98ccf4946a0e4513ab5fc157df0f0aca4e (diff) |
Merge branch '5.11' into dev
Conflicts:
qmake/library/qmakebuiltins.cpp
src/plugins/platforms/windows/qwindowstabletsupport.h
src/plugins/platforms/xcb/qxcbconnection.cpp
src/plugins/platforms/xcb/qxcbconnection.h
src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
src/plugins/platforms/xcb/qxcbwindow.cpp
src/widgets/styles/qstylesheetstyle.cpp
tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
Done-With: Gatis Paeglis <gatis.paeglis@qt.io>
Change-Id: I000b0eb3cea2a5c7a99b95732bfdd41507cf916e
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/platforms/windows/qwindowstabletsupport.cpp | 9 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowstabletsupport.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp | 67 | ||||
-rw-r--r-- | src/plugins/platforms/winrt/qwinrtscreen.cpp | 9 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 6 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 7 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 94 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 36 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.h | 2 | ||||
-rw-r--r-- | src/plugins/styles/mac/qmacstyle_mac.mm | 2 |
10 files changed, 190 insertions, 43 deletions
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index dad3e9df9f..2ab59b11ca 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -486,11 +486,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0; - // This code is to delay the tablet data one cycle to sync with the mouse location. - QPointF globalPosF = m_oldGlobalPosF; - const QPointF currentGlobalPosF = + QPointF globalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea); - m_oldGlobalPosF = currentGlobalPosF; QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(uniqueId).target; // Pass to window that grabbed it. @@ -498,10 +495,10 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() const QPoint mouseLocation = QWindowsCursor::mousePosition(); if (m_state == PenProximity) { m_state = PenDown; - m_mode = (mouseLocation - currentGlobalPosF).manhattanLength() > m_absoluteRange + m_mode = (mouseLocation - globalPosF).manhattanLength() > m_absoluteRange ? MouseMode : PenMode; qCDebug(lcQpaTablet) << __FUNCTION__ << "mode=" << m_mode << "pen:" - << currentGlobalPosF << "mouse:" << mouseLocation; + << globalPosF << "mouse:" << mouseLocation; } if (m_mode == MouseMode) globalPosF = mouseLocation; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h index d98dbd4de7..d91701d6a5 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.h +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -150,7 +150,6 @@ private: bool m_tiltSupport = false; QVector<QWindowsTabletDeviceData> m_devices; int m_currentDevice = -1; - QPointF m_oldGlobalPosF; Mode m_mode = PenMode; State m_state = PenUp; }; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index de06077890..fad83fb165 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -364,7 +364,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR setVariantBool(accessible->state().focusable, pRetVal); break; case UIA_IsOffscreenPropertyId: - setVariantBool(false, pRetVal); + setVariantBool(accessible->state().offscreen, pRetVal); break; case UIA_IsContentElementPropertyId: setVariantBool(true, pRetVal); @@ -453,30 +453,53 @@ HRESULT QWindowsUiaMainProvider::Navigate(NavigateDirection direction, IRawEleme QAccessibleInterface *targetacc = nullptr; - switch (direction) { - case NavigateDirection_Parent: - targetacc = accessible->parent(); - if (targetacc && (targetacc->role() == QAccessible::Application)) { - targetacc = nullptr; // The app's children are considered top level objects. - } - break; - case NavigateDirection_FirstChild: - targetacc = accessible->child(0); - break; - case NavigateDirection_LastChild: - targetacc = accessible->child(accessible->childCount() - 1); - break; - case NavigateDirection_NextSibling: - case NavigateDirection_PreviousSibling: + if (direction == NavigateDirection_Parent) { if (QAccessibleInterface *parent = accessible->parent()) { - if (parent->isValid()) { - int index = parent->indexOfChild(accessible); - index += (direction == NavigateDirection_NextSibling) ? 1 : -1; - if (index >= 0 && index < parent->childCount()) - targetacc = parent->child(index); + // The Application's children are considered top level objects. + if (parent->isValid() && parent->role() != QAccessible::Application) { + targetacc = parent; + } + } + } else { + QAccessibleInterface *parent = nullptr; + int index = 0; + int incr = 1; + switch (direction) { + case NavigateDirection_FirstChild: + parent = accessible; + index = 0; + incr = 1; + break; + case NavigateDirection_LastChild: + parent = accessible; + index = accessible->childCount() - 1; + incr = -1; + break; + case NavigateDirection_NextSibling: + if ((parent = accessible->parent())) + index = parent->indexOfChild(accessible) + 1; + incr = 1; + break; + case NavigateDirection_PreviousSibling: + if ((parent = accessible->parent())) + index = parent->indexOfChild(accessible) - 1; + incr = -1; + break; + default: + Q_UNREACHABLE(); + break; + } + + if (parent && parent->isValid()) { + for (int count = parent->childCount(); index >= 0 && index < count; index += incr) { + if (QAccessibleInterface *child = parent->child(index)) { + if (child->isValid() && !child->state().invisible) { + targetacc = child; + break; + } + } } } - break; } if (targetacc) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 2e79c3505b..7d6659f5e2 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1253,10 +1253,11 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) boolean isPressed; pointerPoint->get_IsInContact(&isPressed); - // Devices like the Hololens set a static pressure of 0.5 independent - // of the pressed state. In those cases we need to synthesize the - // pressure value. To our knowledge this does not apply to pens - if (pointerDeviceType == PointerDeviceType_Touch && pressure == 0.5f) + // Devices like the Hololens set a static pressure of 0.0 or 0.5 + // (depending on the image) independent of the pressed state. + // In those cases we need to synthesize the pressure value. To our + // knowledge this does not apply to pens + if (pointerDeviceType == PointerDeviceType_Touch && (pressure == 0.0f || pressure == 0.5f)) pressure = isPressed ? 1. : 0.; const QRectF areaRect(area.X * d->scaleFactor, area.Y * d->scaleFactor, diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index b4ccb808a0..327811a7d2 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -591,6 +591,8 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra m_setup = xcb_get_setup(xcb_connection()); + m_xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower(); + initializeAllAtoms(); initializeXSync(); @@ -1691,8 +1693,10 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, continue; if (isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) { auto *touchUpdateNextEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(next); - if (id == touchUpdateNextEvent->detail % INT_MAX) + if (id == touchUpdateNextEvent->detail % INT_MAX && + touchUpdateNextEvent->deviceid == touchUpdateEvent->deviceid) { return true; + } } } return false; diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index fa39bf6874..c24bcf91f3 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -503,6 +503,9 @@ public: void grabServer(); void ungrabServer(); + bool isUnity() const { return m_xdgCurrentDesktop == "unity"; } + bool isGnome() const { return m_xdgCurrentDesktop == "gnome"; } + QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; } QXcbSystemTrayTracker *systemTrayTracker() const; @@ -521,6 +524,7 @@ public: Qt::MouseButton xiToQtMouseButton(uint32_t b); void xi2UpdateScrollingDevices(); bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner); + void abortSystemMoveResizeForTouch(); bool isTouchScreen(int id); #endif QXcbEventReader *eventReader() const { return m_reader; } @@ -565,6 +569,7 @@ private: bool m_xi2Enabled = false; #if QT_CONFIG(xcb_xinput) + QVector<int> m_floatingSlaveDevices; int m_xi2Minor = -1; void initializeXInput2(); void xi2SetupDevice(void *info, bool removeExisting = true); @@ -720,6 +725,8 @@ private: bool m_peekerIndexCacheDirty = false; QHash<qint32, qint32> m_peekerToCachedIndex; friend class QXcbEventReader; + + QByteArray m_xdgCurrentDesktop; }; #if QT_CONFIG(xcb_xinput) #if QT_CONFIG(tabletevent) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 7ed61bff4e..01b1b37bb8 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -113,7 +113,7 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window) } qt_xcb_input_event_mask_t mask; - mask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER; + mask.header.deviceid = XCB_INPUT_DEVICE_ALL; mask.header.mask_len = 1; mask.mask = bitMask; xcb_void_cookie_t cookie = @@ -309,6 +309,7 @@ void QXcbConnection::xi2SetupDevices() m_scrollingDevices.clear(); m_touchDevices.clear(); m_xiMasterPointerIds.clear(); + m_floatingSlaveDevices.clear(); auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, XCB_INPUT_DEVICE_ALL); if (!reply) { @@ -319,6 +320,10 @@ void QXcbConnection::xi2SetupDevices() auto it = xcb_input_xi_query_device_infos_iterator(reply.get()); for (; it.rem; xcb_input_xi_device_info_next(&it)) { xcb_input_xi_device_info_t *deviceInfo = it.data; + if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_FLOATING_SLAVE) { + m_floatingSlaveDevices.append(deviceInfo->deviceid); + continue; + } if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_MASTER_POINTER) { m_xiMasterPointerIds.append(deviceInfo->deviceid); continue; @@ -542,6 +547,72 @@ static inline qreal fixed1616ToReal(xcb_input_fp1616_t val) } #endif // QT_CONFIG(tabletevent) +namespace { + +/*! \internal + + Qt listens for XIAllDevices to avoid losing mouse events. This function + ensures that we don't process the same event twice: from a slave device and + then again from a master device. + + In a normal use case (e.g. mouse press and release inside a window), we will + drop events from master devices as duplicates. Other advantage of processing + events from slave devices is that they don't share button state. All buttons + on a master device share the state. + + Examples of special cases: + + - During system move/resize, window manager (_NET_WM_MOVERESIZE) grabs the + master pointer, in this case we process the matching release from the slave + device. A master device event is not sent by the server, hence no duplicate + event to drop. If we listened for XIAllMasterDevices instead, we would never + see a release event in this case. + + - If we dismiss a context menu by clicking somewhere outside a Qt application, + we will process the mouse press from the master pointer as that is the + device we are grabbing. We are not grabbing slave devices (grabbing on the + slave device is buggy according to 19d289ab1b5bde3e136765e5432b5c7d004df3a4). + And since the event occurs outside our window, the slave device event is + not sent to us by the server, hence no duplicate event to drop. +*/ +bool isDuplicateEvent(xcb_ge_event_t *event) +{ + struct qXIEvent { + bool isValid = false; + uint16_t sourceid; + uint8_t event_type; + uint32_t detail; + int32_t root_x; + int32_t root_y; + }; + static qXIEvent lastSeenEvent; + + bool isDuplicate = false; + auto xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event); + if (lastSeenEvent.isValid) { + isDuplicate = lastSeenEvent.sourceid == xiDeviceEvent->sourceid && + lastSeenEvent.event_type == xiDeviceEvent->event_type && + lastSeenEvent.detail == xiDeviceEvent->detail && + lastSeenEvent.root_x == xiDeviceEvent->root_x && + lastSeenEvent.root_y == xiDeviceEvent->root_y; + } else { + lastSeenEvent.isValid = true; + } + lastSeenEvent.sourceid = xiDeviceEvent->sourceid; + lastSeenEvent.event_type = xiDeviceEvent->event_type; + lastSeenEvent.detail = xiDeviceEvent->detail; + lastSeenEvent.root_x = xiDeviceEvent->root_x; + lastSeenEvent.root_y = xiDeviceEvent->root_y; + + if (isDuplicate) + // This sanity check ensures that special cases like QTBUG-59277 keep working. + lastSeenEvent.isValid = false; // An event can be a duplicate only once. + + return isDuplicate; +} + +} // namespace + void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { auto *xiEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event); @@ -550,15 +621,31 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) xcb_input_enter_event_t *xiEnterEvent = nullptr; QXcbWindowEventListener *eventListener = 0; + bool isTouchEvent = true; switch (xiEvent->event_type) { case XCB_INPUT_BUTTON_PRESS: case XCB_INPUT_BUTTON_RELEASE: case XCB_INPUT_MOTION: + isTouchEvent = false; + if (!xi2MouseEventsDisabled() && isDuplicateEvent(event)) + return; case XCB_INPUT_TOUCH_BEGIN: case XCB_INPUT_TOUCH_UPDATE: case XCB_INPUT_TOUCH_END: { xiDeviceEvent = xiEvent; + + if (m_floatingSlaveDevices.contains(xiDeviceEvent->sourceid)) + return; // Not interested in floating slave device events, only in attached slaves. + + bool isSlaveEvent = xiDeviceEvent->deviceid == xiDeviceEvent->sourceid; + if (!xi2MouseEventsDisabled() && isTouchEvent && isSlaveEvent) { + // For touch events we want events only from master devices, at least + // currently there is no apparent reason why we would need to consider + // events from slave devices. + return; + } + eventListener = windowEventListenerFromId(xiDeviceEvent->event); sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master break; @@ -830,6 +917,11 @@ bool QXcbConnection::startSystemMoveResizeForTouchBegin(xcb_window_t window, con return false; } +void QXcbConnection::abortSystemMoveResizeForTouch() +{ + m_startSystemMoveResizeInfo.window = XCB_NONE; +} + bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) { bool ok = false; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 9e9058e6e9..ed37c6b1f8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2569,18 +2569,41 @@ bool QXcbWindow::startSystemMove(const QPoint &pos) bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner) { +#if QT_CONFIG(xcb_xinput) const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); if (!connection()->wmSupport()->isSupportedByWM(moveResize)) return false; + const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen()); -#if QT_CONFIG(xcb_xinput) - if (connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner)) - return true; -#endif - return doStartSystemMoveResize(globalPos, corner); + // ### FIXME QTBUG-53389 + bool startedByTouch = connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner); + if (startedByTouch) { + if (connection()->isUnity() || connection()->isGnome()) { + // These desktops fail to move/resize via _NET_WM_MOVERESIZE (WM bug?). + connection()->abortSystemMoveResizeForTouch(); + return false; + } + // KWin, Openbox, AwesomeWM have been tested to work with _NET_WM_MOVERESIZE. + } else { // Started by mouse press. + if (!connection()->hasXInput2() || connection()->xi2MouseEventsDisabled()) { + // Without XI2 we can't get button press/move/release events. + return false; + } + if (connection()->isUnity()) + return false; // _NET_WM_MOVERESIZE on this WM is bouncy (WM bug?). + + doStartSystemMoveResize(globalPos, corner); + } + + return true; +#else + Q_UNUSED(pos); + Q_UNUSED(corner); + return false; +#endif // xcb_xinput } -bool QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner) +void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner) { const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); xcb_client_message_event_t xev; @@ -2607,7 +2630,6 @@ bool QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner) xcb_send_event(connection()->xcb_connection(), false, xcbScreen()->root(), XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *)&xev); - return true; } // Sends an XEmbed message. diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index c6bc915b6a..047ee2eae9 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -171,7 +171,7 @@ public: QXcbScreen *xcbScreen() const; bool startSystemMoveResize(const QPoint &pos, int corner); - bool doStartSystemMoveResize(const QPoint &globalPos, int corner); + void doStartSystemMoveResize(const QPoint &globalPos, int corner); bool isTrayIconWindow() const { return m_trayIconWindow; } diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 9d5cc15a4f..2e2d176308 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -1827,6 +1827,8 @@ NSView *QMacStylePrivate::cocoaControl(CocoaControl widget) const auto *button = static_cast<NSButton *>(bv); button.buttonType = buttonType; button.bezelStyle = bezelStyle; + if (widget.type == Button_CheckBox) + button.allowsMixedState = YES; } return bv; |