summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorEdward Welbourne <edward.welbourne@qt.io>2018-07-31 11:34:23 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2018-07-31 11:34:23 +0000
commitcf2d59bfe8720627e016195903e16cd0c97fa612 (patch)
tree5cc0755d649d606867bf6168a091a91c9d3e6f3d /src/plugins
parent7621bb0f3bba69e0b2849974a335dff4742c8e95 (diff)
parent23c9d4c98f3c6729b56700edc1d7144b444b16db (diff)
Merge "Merge branch '5.11' into dev" into refs/staging/dev
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.h1
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp67
-rw-r--r--src/plugins/platforms/winrt/qwinrtscreen.cpp9
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h7
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp94
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp36
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm2
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 ae2765fc40..dd7959f3cf 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;