diff options
Diffstat (limited to 'src/gui/kernel/qguiapplication.cpp')
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 280 |
1 files changed, 186 insertions, 94 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 5baadd425f..b7c61779e6 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -53,6 +53,7 @@ #include <qpa/qplatformdrag.h> #include <QtCore/QAbstractEventDispatcher> +#include <QtCore/QStandardPaths> #include <QtCore/QVariant> #include <QtCore/private/qcoreapplication_p.h> #include <QtCore/private/qabstracteventdispatcher_p.h> @@ -190,7 +191,7 @@ QWindow *QGuiApplicationPrivate::focus_window = 0; static QBasicMutex applicationFontMutex; QFont *QGuiApplicationPrivate::app_font = 0; -QStyleHints *QGuiApplicationPrivate::styleHints = Q_NULLPTR; +QStyleHints *QGuiApplicationPrivate::styleHints = nullptr; bool QGuiApplicationPrivate::obey_desktop_settings = true; QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = 0; @@ -244,6 +245,15 @@ static inline void clearFontUnlocked() QGuiApplicationPrivate::app_font = 0; } +static bool checkRunningUnderFlatpak() +{ +#if QT_CONFIG(dbus) + return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty(); +#else + return false; +#endif // QT_CONFIG(dbus) +} + // Using aggregate initialization instead of ctor so we can have a POD global static #define Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER { Qt::TopLeftCorner, -1, -1, -1, -1 } @@ -748,7 +758,7 @@ QString QGuiApplication::desktopFileName() */ QWindow *QGuiApplication::modalWindow() { - CHECK_QAPP_INSTANCE(Q_NULLPTR) + CHECK_QAPP_INSTANCE(nullptr) if (QGuiApplicationPrivate::self->modalWindowList.isEmpty()) return 0; return QGuiApplicationPrivate::self->modalWindowList.first(); @@ -1140,8 +1150,14 @@ static void init_platform(const QString &pluginArgument, const QString &platform if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) { QStringList keys = QPlatformIntegrationFactory::keys(platformPluginPath); - QString fatalMessage - = QStringLiteral("This application failed to start because it could not find or load the Qt platform plugin \"%1\"\nin \"%2\".\n\n").arg(name, QDir::toNativeSeparators(platformPluginPath)); + QString fatalMessage; + if (keys.contains(name)) { + fatalMessage = QStringLiteral("This application failed to start because it could not load the Qt platform plugin \"%2\"\nin \"%3\", even though it was found. ").arg(name, QDir::toNativeSeparators(platformPluginPath)); + fatalMessage += QStringLiteral("This is usually due to missing dependencies, which you can verify by setting the env variable QT_DEBUG_PLUGINS to 1.\n\n"); + } else { + fatalMessage = QStringLiteral("This application failed to start because it could not find the Qt platform plugin \"%2\"\nin \"%3\".\n\n").arg(name, QDir::toNativeSeparators(platformPluginPath)); + } + if (!keys.isEmpty()) { fatalMessage += QStringLiteral("Available platform plugins are: %1.\n\n").arg( keys.join(QLatin1String(", "))); @@ -1173,16 +1189,21 @@ static void init_platform(const QString &pluginArgument, const QString &platform if (!platformThemeName.isEmpty()) themeNames.append(platformThemeName); - // 2) Ask the platform integration for a list of theme names + // 2) Special case - check whether we are in sandbox to use flatpak platform theme for portals support + if (checkRunningUnderFlatpak()) { + themeNames.append(QStringLiteral("flatpak")); + } + + // 3) Ask the platform integration for a list of theme names themeNames += QGuiApplicationPrivate::platform_integration->themeNames(); - // 3) Look for a theme plugin. + // 4) Look for a theme plugin. for (const QString &themeName : qAsConst(themeNames)) { QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(themeName, platformPluginPath); if (QGuiApplicationPrivate::platform_theme) break; } - // 4) If no theme plugin was found ask the platform integration to + // 5) If no theme plugin was found ask the platform integration to // create a theme if (!QGuiApplicationPrivate::platform_theme) { for (const QString &themeName : qAsConst(themeNames)) { @@ -1193,7 +1214,7 @@ static void init_platform(const QString &pluginArgument, const QString &platform // No error message; not having a theme plugin is allowed. } - // 5) Fall back on the built-in "null" platform theme. + // 6) Fall back on the built-in "null" platform theme. if (!QGuiApplicationPrivate::platform_theme) QGuiApplicationPrivate::platform_theme = new QPlatformTheme; @@ -1527,7 +1548,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() cleanupThreadData(); delete QGuiApplicationPrivate::styleHints; - QGuiApplicationPrivate::styleHints = Q_NULLPTR; + QGuiApplicationPrivate::styleHints = nullptr; delete inputMethod; qt_cleanupFontDatabase(); @@ -1650,10 +1671,10 @@ QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function) QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration(); if (!pi) { qWarning("QGuiApplication::platformFunction(): Must construct a QGuiApplication before accessing a platform function"); - return Q_NULLPTR; + return nullptr; } - return pi->nativeInterface() ? pi->nativeInterface()->platformFunction(function) : Q_NULLPTR; + return pi->nativeInterface() ? pi->nativeInterface()->platformFunction(function) : nullptr; } /*! @@ -1736,7 +1757,6 @@ bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArra void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) { switch(e->type) { - case QWindowSystemInterfacePrivate::FrameStrutMouse: case QWindowSystemInterfacePrivate::Mouse: QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e)); break; @@ -1846,29 +1866,111 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv } } +/*! \internal + + History is silent on why Qt splits mouse events that change position and + button state at the same time. We believe that this was done to emulate mouse + behavior on touch screens. If mouse tracking is enabled, we will get move + events before the button is pressed. A touch panel does not generally give + move events when not pressed, so without event splitting code path we would + only see a press in a new location without any intervening moves. This could + confuse code that is written for a real mouse. The same is true for mouse + release events that change position, see tst_QWidget::touchEventSynthesizedMouseEvent() + and tst_QWindow::generatedMouseMove() auto tests. +*/ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e) { - QEvent::Type type; - Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons; - if (e->globalPos != QGuiApplicationPrivate::lastCursorPosition && (stateChange != Qt::NoButton)) { - // A mouse event should not change both position and buttons at the same time. Instead we - // should first send a move event followed by a button changed event. Since this is not the case - // with the current event, we split it in two. - QWindowSystemInterfacePrivate::MouseEvent mouseButtonEvent( - e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers, e->source); - if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic) - mouseButtonEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; - e->buttons = mouse_buttons; - processMouseEvent(e); - processMouseEvent(&mouseButtonEvent); - return; + QEvent::Type type = QEvent::None; + Qt::MouseButton button = Qt::NoButton; + QWindow *window = e->window.data(); + bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos; + bool mouseMove = false; + bool mousePress = false; + + if (e->enhancedMouseEvent()) { + type = e->buttonType; + button = e->button; + + if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove) + mouseMove = true; + else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress) + mousePress = true; + + if (!mouseMove && positionChanged) { + QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, + e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton, + e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove, + e->source, e->nonClientArea); + if (e->synthetic()) + moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; + processMouseEvent(&moveEvent); // mouse move excluding state change + processMouseEvent(e); // the original mouse event + return; + } + } else { + Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons; + if (positionChanged && (stateChange != Qt::NoButton)) { + QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, e->localPos, + e->globalPos, mouse_buttons, e->modifiers, Qt::NoButton, QEvent::None, e->source, + e->nonClientArea); + if (e->synthetic()) + moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; + processMouseEvent(&moveEvent); // mouse move excluding state change + processMouseEvent(e); // the original mouse event + return; + } + + // In the compatibility path we deduce event type and button that caused the event + if (positionChanged) { + mouseMove = true; + type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove; + } else { + // Check to see if a new button has been pressed/released. + for (uint mask = Qt::LeftButton; mask <= Qt::MaxMouseButton; mask <<= 1) { + if (stateChange & mask) { + button = Qt::MouseButton(mask); + break; + } + } + if (button == Qt::NoButton) { + // Ignore mouse events that don't change the current state. This shouldn't + // really happen, getting here can only mean that the stored button state + // is out of sync with the actual physical button state. + return; + } + if (button & e->buttons) { + mousePress = true; + type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress + : QEvent::MouseButtonPress; + } else { + type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease + : QEvent::MouseButtonRelease; + } + } } - QWindow *window = e->window.data(); modifier_buttons = e->modifiers; - QPointF localPoint = e->localPos; QPointF globalPoint = e->globalPos; + bool doubleClick = false; + + if (mouseMove) { + QGuiApplicationPrivate::lastCursorPosition = globalPoint; + if (qAbs(globalPoint.x() - mousePressX) > mouse_double_click_distance|| + qAbs(globalPoint.y() - mousePressY) > mouse_double_click_distance) + mousePressButton = Qt::NoButton; + } else { + mouse_buttons = e->buttons; + if (mousePress) { + ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval()); + doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton; + mousePressTime = e->timestamp; + mousePressButton = button; + const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint(); + mousePressX = point.x(); + mousePressY = point.y(); + } + } if (e->nullWindow()) { window = QGuiApplication::topLevelAt(globalPoint.toPoint()); @@ -1889,44 +1991,6 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } } - Qt::MouseButton button = Qt::NoButton; - bool doubleClick = false; - const bool frameStrut = e->type == QWindowSystemInterfacePrivate::FrameStrutMouse; - - if (QGuiApplicationPrivate::lastCursorPosition != globalPoint) { - type = frameStrut ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove; - QGuiApplicationPrivate::lastCursorPosition = globalPoint; - if (qAbs(globalPoint.x() - mousePressX) > mouse_double_click_distance|| - qAbs(globalPoint.y() - mousePressY) > mouse_double_click_distance) - mousePressButton = Qt::NoButton; - } else { // Check to see if a new button has been pressed/released. - for (int check = Qt::LeftButton; - check <= int(Qt::MaxMouseButton); - check = check << 1) { - if (check & stateChange) { - button = Qt::MouseButton(check); - break; - } - } - if (button == Qt::NoButton) { - // Ignore mouse events that don't change the current state. - return; - } - mouse_buttons = e->buttons; - if (button & e->buttons) { - ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval()); - doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton; - type = frameStrut ? QEvent::NonClientAreaMouseButtonPress : QEvent::MouseButtonPress; - mousePressTime = e->timestamp; - mousePressButton = button; - const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint(); - mousePressX = point.x(); - mousePressY = point.y(); - } else { - type = frameStrut ? QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease; - } - } - if (!window) return; @@ -1937,14 +2001,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen); const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen); QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint, - button, mouse_buttons, e->modifiers, e->source); + button, e->buttons, e->modifiers, e->source); ev.setTimestamp(e->timestamp); cursor->pointerEvent(ev); } } #endif - QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, mouse_buttons, e->modifiers, e->source); + QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source); ev.setTimestamp(e->timestamp); if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) { @@ -1960,7 +2024,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo QGuiApplication::sendSpontaneousEvent(window, &ev); e->eventAccepted = ev.isAccepted(); if (!e->synthetic() && !ev.isAccepted() - && !frameStrut + && !e->nonClientArea && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) { if (!m_fakeTouchDevice) { m_fakeTouchDevice = new QTouchDevice; @@ -1978,7 +2042,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo point.state = Qt::TouchPointPressed; } else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) { point.state = Qt::TouchPointReleased; - } else if (type == QEvent::MouseMove && (mouse_buttons & Qt::LeftButton)) { + } else if (type == QEvent::MouseMove && (e->buttons & Qt::LeftButton)) { point.state = Qt::TouchPointMoved; } else { return; @@ -1997,9 +2061,9 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo if (doubleClick) { mousePressButton = Qt::NoButton; if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press - const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick; + const QEvent::Type doubleClickType = e->nonClientArea ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick; QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint, - button, mouse_buttons, e->modifiers, e->source); + button, e->buttons, e->modifiers, e->source); dblClickEvent.setTimestamp(e->timestamp); QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent); } @@ -2363,7 +2427,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T localValid = false; } if (type == QEvent::TabletRelease) - pointData.target = Q_NULLPTR; + pointData.target = nullptr; if (!window) return; } @@ -2380,20 +2444,30 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T break; } } - QTabletEvent ev(type, local, e->global, - e->device, e->pointerType, e->pressure, e->xTilt, e->yTilt, - e->tangentialPressure, e->rotation, e->z, - e->modifiers, e->uid, button, e->buttons); - ev.setAccepted(false); - ev.setTimestamp(e->timestamp); - QGuiApplication::sendSpontaneousEvent(window, &ev); + QTabletEvent tabletEvent(type, local, e->global, + e->device, e->pointerType, e->pressure, e->xTilt, e->yTilt, + e->tangentialPressure, e->rotation, e->z, + e->modifiers, e->uid, button, e->buttons); + tabletEvent.setAccepted(false); + tabletEvent.setTimestamp(e->timestamp); + QGuiApplication::sendSpontaneousEvent(window, &tabletEvent); pointData.state = e->buttons; - if (!ev.isAccepted() && !QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse - && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) { - QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp, e->local, e->global, - e->buttons, e->modifiers, Qt::MouseEventSynthesizedByQt); - fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; - processMouseEvent(&fake); + if (!tabletEvent.isAccepted() + && !QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse + && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) { + + const QEvent::Type mouseType = [&]() { + switch (type) { + case QEvent::TabletPress: return QEvent::MouseButtonPress; + case QEvent::TabletMove: return QEvent::MouseMove; + case QEvent::TabletRelease: return QEvent::MouseButtonRelease; + default: Q_UNREACHABLE(); + } + }(); + QWindowSystemInterfacePrivate::MouseEvent mouseEvent(window, e->timestamp, e->local, + e->global, e->buttons, e->modifiers, button, mouseType, Qt::MouseEventSynthesizedByQt); + mouseEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; + processMouseEvent(&mouseEvent); } #else Q_UNUSED(e) @@ -2499,7 +2573,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To ++it; } for (QSet<QWindow *>::const_iterator winIt = windowsNeedingCancel.constBegin(), - winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) { + winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) { touchEvent.setWindow(*winIt); QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent); } @@ -2512,8 +2586,10 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To e->timestamp, synthIt->pos, synthIt->screenPos, - mouse_buttons & ~Qt::LeftButton, + Qt::NoButton, e->modifiers, + Qt::LeftButton, + QEvent::MouseButtonRelease, Qt::MouseEventSynthesizedByQt); fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&fake); @@ -2710,25 +2786,41 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) { // exclude devices which generate their own mouse events if (!(touchEvent.device()->capabilities() & QTouchDevice::MouseEmulation)) { - Qt::MouseButtons b = eventType == QEvent::TouchEnd ? Qt::NoButton : Qt::LeftButton; - if (b == Qt::NoButton) + + if (eventType == QEvent::TouchEnd) self->synthesizedMousePoints.clear(); const QList<QTouchEvent::TouchPoint> &touchPoints = touchEvent.touchPoints(); if (eventType == QEvent::TouchBegin) m_fakeMouseSourcePointId = touchPoints.first().id(); + const QEvent::Type mouseType = [&]() { + switch (eventType) { + case QEvent::TouchBegin: return QEvent::MouseButtonPress; + case QEvent::TouchUpdate: return QEvent::MouseMove; + case QEvent::TouchEnd: return QEvent::MouseButtonRelease; + default: Q_UNREACHABLE(); + } + }(); + + Qt::MouseButton button = mouseType == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton; + Qt::MouseButtons buttons = mouseType == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton; + for (int i = 0; i < touchPoints.count(); ++i) { const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i); if (touchPoint.id() == m_fakeMouseSourcePointId) { - if (b != Qt::NoButton) + if (eventType != QEvent::TouchEnd) self->synthesizedMousePoints.insert(w, SynthesizedMouseData( touchPoint.pos(), touchPoint.screenPos(), w)); + // All touch events that are not accepted by the application will be translated to + // left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs). QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp, touchPoint.pos(), touchPoint.screenPos(), - b | (mouse_buttons & ~Qt::LeftButton), + buttons, e->modifiers, + button, + mouseType, Qt::MouseEventSynthesizedByQt); fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&fake); @@ -3520,7 +3612,7 @@ Qt::LayoutDirection QGuiApplication::layoutDirection() #ifndef QT_NO_CURSOR QCursor *QGuiApplication::overrideCursor() { - CHECK_QAPP_INSTANCE(Q_NULLPTR) + CHECK_QAPP_INSTANCE(nullptr) return qGuiApp->d_func()->cursor_list.isEmpty() ? 0 : &qGuiApp->d_func()->cursor_list.first(); } @@ -3720,7 +3812,7 @@ bool QGuiApplication::desktopSettingsAware() */ QInputMethod *QGuiApplication::inputMethod() { - CHECK_QAPP_INSTANCE(Q_NULLPTR) + CHECK_QAPP_INSTANCE(nullptr) if (!qGuiApp->d_func()->inputMethod) qGuiApp->d_func()->inputMethod = new QInputMethod(); return qGuiApp->d_func()->inputMethod; |