diff options
Diffstat (limited to 'src/gui/kernel')
-rw-r--r-- | src/gui/kernel/qaction.cpp | 8 | ||||
-rw-r--r-- | src/gui/kernel/qactiongroup.cpp | 24 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 152 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication_p.h | 15 | ||||
-rw-r--r-- | src/gui/kernel/qguiapplication_platform.h | 31 | ||||
-rw-r--r-- | src/gui/kernel/qhighdpiscaling_p.h | 4 | ||||
-rw-r--r-- | src/gui/kernel/qinputmethod.cpp | 1 | ||||
-rw-r--r-- | src/gui/kernel/qpaintdevicewindow.cpp | 5 | ||||
-rw-r--r-- | src/gui/kernel/qpalette.cpp | 5 | ||||
-rw-r--r-- | src/gui/kernel/qplatformkeymapper.h | 2 | ||||
-rw-r--r-- | src/gui/kernel/qplatformtheme.cpp | 4 | ||||
-rw-r--r-- | src/gui/kernel/qplatformtheme.h | 2 | ||||
-rw-r--r-- | src/gui/kernel/qplatformwindow_p.h | 2 | ||||
-rw-r--r-- | src/gui/kernel/qshortcutmap.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qsimpledrag.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qstylehints.cpp | 34 | ||||
-rw-r--r-- | src/gui/kernel/qstylehints.h | 5 | ||||
-rw-r--r-- | src/gui/kernel/qstylehints_p.h | 1 | ||||
-rw-r--r-- | src/gui/kernel/qwindow.cpp | 71 | ||||
-rw-r--r-- | src/gui/kernel/qwindow_p.h | 2 | ||||
-rw-r--r-- | src/gui/kernel/qwindowsysteminterface_p.h | 7 |
21 files changed, 341 insertions, 38 deletions
diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp index c67cfd53b1..1768cd8aa1 100644 --- a/src/gui/kernel/qaction.cpp +++ b/src/gui/kernel/qaction.cpp @@ -538,8 +538,10 @@ QList<QObject*> QAction::associatedObjects() const \brief the action's icon In toolbars, the icon is used as the tool button icon; in menus, - it is displayed to the left of the menu text. There is no default - icon. + it is displayed to the left of the menu text, as long as + QAction::iconVisibleInMenu returns \c true. + + There is no default icon. If a null icon (QIcon::isNull()) is passed into this function, the icon of the action is cleared. @@ -1315,8 +1317,6 @@ Q_GUI_EXPORT QDebug operator<<(QDebug d, const QAction *action) QtDebugUtils::formatQEnum(d, action->menuRole()); d << " enabled=" << action->isEnabled(); d << " visible=" << action->isVisible(); - } else { - d << '0'; } d << ')'; return d; diff --git a/src/gui/kernel/qactiongroup.cpp b/src/gui/kernel/qactiongroup.cpp index 7fb5b4ad46..4694d29c93 100644 --- a/src/gui/kernel/qactiongroup.cpp +++ b/src/gui/kernel/qactiongroup.cpp @@ -323,6 +323,30 @@ bool QActionGroup::isVisible() const return d->visible; } +/*! + \fn void QActionGroup::triggered(QAction *action) + + This signal is emitted when the given \a action in the action + group is activated by the user; for example, when the user clicks + a menu option or a toolbar button, or presses an action's shortcut + key combination. + + Connect to this signal for command actions. + + \sa QAction::activate() +*/ + +/*! + \fn void QActionGroup::hovered(QAction *action) + + This signal is emitted when the given \a action in the action + group is highlighted by the user; for example, when the user + pauses with the cursor over a menu option or a toolbar button, + or presses an action's shortcut key combination. + + \sa QAction::activate() +*/ + QT_END_NAMESPACE #include "moc_qactiongroup.cpp" diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index c97374e975..0b53f34200 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -107,6 +107,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcPopup, "qt.gui.popup"); + using namespace Qt::StringLiterals; using namespace QtMiscUtils; @@ -180,12 +182,15 @@ Q_CONSTINIT QClipboard *QGuiApplicationPrivate::qt_clipboard = nullptr; Q_CONSTINIT QList<QScreen *> QGuiApplicationPrivate::screen_list; Q_CONSTINIT QWindowList QGuiApplicationPrivate::window_list; +Q_CONSTINIT QWindowList QGuiApplicationPrivate::popup_list; +Q_CONSTINIT const QWindow *QGuiApplicationPrivate::active_popup_on_press = nullptr; Q_CONSTINIT QWindow *QGuiApplicationPrivate::focus_window = nullptr; Q_CONSTINIT static QBasicMutex applicationFontMutex; Q_CONSTINIT QFont *QGuiApplicationPrivate::app_font = nullptr; Q_CONSTINIT QStyleHints *QGuiApplicationPrivate::styleHints = nullptr; Q_CONSTINIT bool QGuiApplicationPrivate::obey_desktop_settings = true; +Q_CONSTINIT bool QGuiApplicationPrivate::popup_closed_on_press = false; Q_CONSTINIT QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = nullptr; @@ -960,6 +965,43 @@ bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blocking return false; } +QWindow *QGuiApplicationPrivate::activePopupWindow() +{ + // might be the same as focusWindow() if that's a popup + return QGuiApplicationPrivate::popup_list.isEmpty() ? + nullptr : QGuiApplicationPrivate::popup_list.constLast(); +} + +void QGuiApplicationPrivate::activatePopup(QWindow *popup) +{ + if (!popup->isVisible()) + return; + popup_list.removeOne(popup); // ensure that there's only one entry, and it's the last + qCDebug(lcPopup) << "appending popup" << popup << "to existing" << popup_list; + popup_list.append(popup); +} + +bool QGuiApplicationPrivate::closePopup(QWindow *popup) +{ + const auto removed = QGuiApplicationPrivate::popup_list.removeAll(popup); + qCDebug(lcPopup) << "removed?" << removed << "popup" << popup << "; remaining" << popup_list; + return removed; // >= 1 if something was removed +} + +/*! + Returns \c true if there are no more open popups. +*/ +bool QGuiApplicationPrivate::closeAllPopups() +{ + // Close all popups: In case some popup refuses to close, + // we give up after 1024 attempts (to avoid an infinite loop). + int maxiter = 1024; + QWindow *popup; + while ((popup = activePopupWindow()) && maxiter--) + popup->close(); // this will call QApplicationPrivate::closePopup + return QGuiApplicationPrivate::popup_list.isEmpty(); +} + /*! Returns the QWindow that receives events tied to focus, such as key events. @@ -1216,9 +1258,9 @@ QString QGuiApplication::platformName() } } -Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin"); -Q_LOGGING_CATEGORY(lcQpaTheme, "qt.qpa.theme"); -Q_LOGGING_CATEGORY(lcPtrDispatch, "qt.pointer.dispatch"); +Q_STATIC_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin"); +Q_STATIC_LOGGING_CATEGORY(lcQpaTheme, "qt.qpa.theme"); +Q_STATIC_LOGGING_CATEGORY(lcPtrDispatch, "qt.pointer.dispatch"); static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv) { @@ -1354,6 +1396,11 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString fontSmoothingGamma = platformIntegration->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal(); QCoreApplication::setAttribute(Qt::AA_DontShowShortcutsInContextMenus, !QGuiApplication::styleHints()->showShortcutsInContextMenus()); + + if (const auto *platformTheme = QGuiApplicationPrivate::platformTheme()) { + QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, + !platformTheme->themeHint(QPlatformTheme::ShowIconsInMenus).toBool()); + } } static void init_plugins(const QList<QByteArray> &pluginList) @@ -1785,6 +1832,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate() platform_integration = nullptr; window_list.clear(); + popup_list.clear(); screen_list.clear(); self = nullptr; @@ -2228,7 +2276,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo 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); + e->source, e->nonClientArea, device, e->eventPointId); if (e->synthetic()) moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&moveEvent); // mouse move excluding state change @@ -2248,6 +2296,9 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo bool doubleClick = false; auto persistentEPD = devPriv->pointById(0); + if (e->synthetic(); auto *originalDeviceEPD = devPriv->queryPointById(e->eventPointId)) + QMutableEventPoint::update(originalDeviceEPD->eventPoint, persistentEPD->eventPoint); + if (mouseMove) { QGuiApplicationPrivate::lastCursorPosition = globalPoint; const auto doubleClickDistance = (e->device && e->device->type() == QInputDevice::DeviceType::Mouse ? @@ -2306,6 +2357,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } #endif + const auto *activePopup = activePopupWindow(); + if (type == QEvent::MouseButtonPress) + active_popup_on_press = activePopup; + if (window->d_func()->blockedByModalWindow && !activePopup) { + // a modal window is blocking this window, don't allow mouse events through + return; + } + QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source, device); Q_ASSERT(devPriv->pointById(0) == persistentEPD); // we don't expect reallocation in QPlatformCursor::pointerEvenmt() // restore globalLastPosition to avoid invalidating the velocity calculations, @@ -2314,9 +2373,15 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo persistentEPD = nullptr; // incoming and synth events can cause reallocation during delivery, so don't use this again // ev now contains a detached copy of the QEventPoint from QPointingDevicePrivate::activePoints ev.setTimestamp(e->timestamp); - if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) { - // a modal window is blocking this window, don't allow mouse events through - return; + + if (activePopup && activePopup != window && (!popup_closed_on_press || type == QEvent::MouseButtonRelease)) { + // If the popup handles the event, we're done. + auto *handlingPopup = window->d_func()->forwardToPopup(&ev, active_popup_on_press); + if (handlingPopup) { + if (type == QEvent::MouseButtonPress) + active_popup_on_press = handlingPopup; + return; + } } if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) { @@ -2368,6 +2433,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } } if (type == QEvent::MouseButtonRelease && e->buttons == Qt::NoButton) { + popup_closed_on_press = false; if (auto *persistentEPD = devPriv->queryPointById(0)) { ev.setExclusiveGrabber(persistentEPD->eventPoint, nullptr); ev.clearPassiveGrabbers(persistentEPD->eventPoint); @@ -2422,6 +2488,11 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE window = QGuiApplication::focusWindow(); } + if (!window) { + e->eventAccepted = false; + return; + } + #if defined(Q_OS_ANDROID) static bool backKeyPressAccepted = false; static bool menuKeyPressAccepted = false; @@ -2430,7 +2501,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE #if !defined(Q_OS_MACOS) // FIXME: Include OS X in this code path by passing the key event through // QPlatformInputContext::filterEvent(). - if (e->keyType == QEvent::KeyPress && window) { + if (e->keyType == QEvent::KeyPress) { if (QWindowSystemInterface::handleShortcutEvent(window, e->timestamp, e->key, e->modifiers, e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount)) { #if defined(Q_OS_ANDROID) @@ -2447,9 +2518,16 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE e->unicode, e->repeat, e->repeatCount); ev.setTimestamp(e->timestamp); + const auto *activePopup = activePopupWindow(); + if (activePopup && activePopup != window) { + // If the popup handles the event, we're done. + if (window->d_func()->forwardToPopup(&ev, active_popup_on_press)) + return; + } + // only deliver key events when we have a window, and no modal window is blocking this window - if (window && !window->d_func()->blockedByModalWindow) + if (!window->d_func()->blockedByModalWindow) QGuiApplication::sendSpontaneousEvent(window, &ev); #ifdef Q_OS_ANDROID else @@ -2520,10 +2598,15 @@ void QGuiApplicationPrivate::processFocusWindowEvent(QWindowSystemInterfacePriva if (previous == newFocus) return; - if (newFocus) + bool activatedPopup = false; + if (newFocus) { if (QPlatformWindow *platformWindow = newFocus->handle()) if (platformWindow->isAlertState()) platformWindow->setAlertState(false); + activatedPopup = (newFocus->flags() & Qt::WindowType_Mask) == Qt::Popup; + if (activatedPopup) + activatePopup(newFocus); + } QObject *previousFocusObject = previous ? previous->focusObject() : nullptr; @@ -2538,8 +2621,7 @@ void QGuiApplicationPrivate::processFocusWindowEvent(QWindowSystemInterfacePriva if (previous) { Qt::FocusReason r = e->reason; - if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) && - newFocus && (newFocus->flags() & Qt::Popup) == Qt::Popup) + if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) && activatedPopup) r = Qt::PopupFocusReason; QFocusEvent focusOut(QEvent::FocusOut, r); QCoreApplication::sendSpontaneousEvent(previous, &focusOut); @@ -2782,6 +2864,7 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T } if (!window) return; + active_popup_on_press = activePopupWindow(); pointData.target = window; } else { if (e->nullWindow()) { @@ -2809,12 +2892,25 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T } } + const auto *activePopup = activePopupWindow(); + if (window->d_func()->blockedByModalWindow && !activePopup) { + // a modal window is blocking this window, don't allow events through + return; + } + QTabletEvent tabletEvent(type, device, local, e->global, e->pressure, e->xTilt, e->yTilt, e->tangentialPressure, e->rotation, e->z, e->modifiers, button, e->buttons); tabletEvent.setAccepted(false); tabletEvent.setTimestamp(e->timestamp); + + if (activePopup && activePopup != window) { + // If the popup handles the event, we're done. + if (window->d_func()->forwardToPopup(&tabletEvent, active_popup_on_press)) + return; + } + QGuiApplication::sendSpontaneousEvent(window, &tabletEvent); pointData.state = e->buttons; if (!tabletEvent.isAccepted() @@ -2987,6 +3083,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To if (!window) window = QGuiApplication::topLevelAt(tempPt.globalPosition().toPoint()); QMutableEventPoint::setWindow(ep, window); + active_popup_on_press = activePopupWindow(); break; case QEventPoint::State::Released: @@ -3057,7 +3154,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To break; } - if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) { + const auto *activePopup = activePopupWindow(); + if (window->d_func()->blockedByModalWindow && !activePopup) { // a modal window is blocking this window, don't allow touch events through // QTBUG-37371 temporary fix; TODO: revisit when we have a forwarding solution @@ -3071,6 +3169,12 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To continue; } + if (activePopup && activePopup != window) { + // If the popup handles the event, we're done. + if (window->d_func()->forwardToPopup(&touchEvent, active_popup_on_press)) + return; + } + // Note: after the call to sendSpontaneousEvent, touchEvent.position() will have // changed to reflect the local position inside the last (random) widget it tried // to deliver the touch event to, and will therefore be invalid afterwards. @@ -3111,7 +3215,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To } // All touch events that are not accepted by the application will be translated to // left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs). - // TODO why go through QPA? Why not just send a QMouseEvent right from here? + // Sending a QPA event (rather than simply sending a QMouseEvent) takes care of + // side-effects such as double-click synthesis. QWindowSystemInterfacePrivate::MouseEvent fake(window, e->timestamp, window->mapFromGlobal(touchPoint->globalPosition().toPoint()), touchPoint->globalPosition(), @@ -3121,7 +3226,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To mouseEventType, Qt::MouseEventSynthesizedByQt, false, - device); + device, + touchPoint->id()); fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; processMouseEvent(&fake); } @@ -3447,6 +3553,15 @@ void QGuiApplicationPrivate::updatePalette() } } +QEvent::Type QGuiApplicationPrivate::contextMenuEventType() +{ + switch (QGuiApplication::styleHints()->contextMenuTrigger()) { + case Qt::ContextMenuTrigger::Press: return QEvent::MouseButtonPress; + case Qt::ContextMenuTrigger::Release: return QEvent::MouseButtonRelease; + } + return QEvent::None; +} + void QGuiApplicationPrivate::clearPalette() { delete app_pal; @@ -4316,7 +4431,7 @@ const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA8Text() { #ifdef Q_OS_WIN if (!m_a8ColorProfile) - m_a8ColorProfile = QColorTrcLut::fromGamma(2.31); // This is a hard-coded thing for Windows text rendering + m_a8ColorProfile = QColorTrcLut::fromGamma(2.31f); // This is a hard-coded thing for Windows text rendering return m_a8ColorProfile.get(); #else return colorProfileForA32Text(); @@ -4326,7 +4441,7 @@ const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA8Text() const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA32Text() { if (!m_a32ColorProfile) - m_a32ColorProfile = QColorTrcLut::fromGamma(fontSmoothingGamma); + m_a32ColorProfile = QColorTrcLut::fromGamma(float(fontSmoothingGamma)); return m_a32ColorProfile.get(); } @@ -4392,6 +4507,9 @@ void *QGuiApplication::resolveInterface(const char *name, int revision) const #if QT_CONFIG(wayland) QT_NATIVE_INTERFACE_RETURN_IF(QWaylandApplication, platformNativeInterface()); #endif +#if defined(Q_OS_VISIONOS) + QT_NATIVE_INTERFACE_RETURN_IF(QVisionOSApplication, platformIntegration); +#endif return QCoreApplication::resolveInterface(name, revision); } diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index cca79534fc..ac531ef28f 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -40,6 +40,8 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcPopup) + class QColorTrcLut; class QPlatformIntegration; class QPlatformTheme; @@ -196,8 +198,11 @@ public: virtual Qt::WindowModality defaultModality() const; virtual bool windowNeverBlocked(QWindow *window) const; bool isWindowBlocked(QWindow *window, QWindow **blockingWindow = nullptr) const; - virtual bool popupActive() { return false; } - virtual bool closeAllPopups() { return false; } + static qsizetype popupCount() { return QGuiApplicationPrivate::popup_list.size(); } + static QWindow *activePopupWindow(); + static void activatePopup(QWindow *popup); + static bool closePopup(QWindow *popup); + static bool closeAllPopups(); static Qt::MouseButton mousePressButton; static struct QLastCursorPosition { @@ -258,6 +263,8 @@ public: static QPalette *app_pal; static QWindowList window_list; + static QWindowList popup_list; + static const QWindow *active_popup_on_press; static QWindow *focus_window; #ifndef QT_NO_CURSOR @@ -270,6 +277,7 @@ public: static QString styleOverride; static QStyleHints *styleHints; static bool obey_desktop_settings; + static bool popup_closed_on_press; QInputMethod *inputMethod; QString firstWindowTitle; @@ -323,6 +331,8 @@ public: static void updatePalette(); + static QEvent::Type contextMenuEventType(); + protected: virtual void handleThemeChanged(); @@ -338,6 +348,7 @@ private: static void clearPalette(); friend class QDragManager; + friend class QWindowPrivate; static QGuiApplicationPrivate *self; static int m_fakeMouseSourcePointId; diff --git a/src/gui/kernel/qguiapplication_platform.h b/src/gui/kernel/qguiapplication_platform.h index 545bf75c84..98e19427ae 100644 --- a/src/gui/kernel/qguiapplication_platform.h +++ b/src/gui/kernel/qguiapplication_platform.h @@ -32,6 +32,22 @@ struct wl_pointer; struct wl_touch; #endif +#if defined(Q_OS_VISIONOS) || defined(Q_QDOC) +# ifdef __OBJC__ +Q_FORWARD_DECLARE_OBJC_CLASS(CP_OBJECT_cp_layer_renderer_capabilities); +typedef CP_OBJECT_cp_layer_renderer_capabilities *cp_layer_renderer_capabilities_t; +Q_FORWARD_DECLARE_OBJC_CLASS(CP_OBJECT_cp_layer_renderer_configuration); +typedef CP_OBJECT_cp_layer_renderer_configuration *cp_layer_renderer_configuration_t; +Q_FORWARD_DECLARE_OBJC_CLASS(CP_OBJECT_cp_layer_renderer); +typedef CP_OBJECT_cp_layer_renderer *cp_layer_renderer_t; +# else +typedef struct cp_layer_renderer_capabilities_s *cp_layer_renderer_capabilities_t; +typedef struct cp_layer_renderer_configuration_s *cp_layer_renderer_configuration_t; +typedef struct cp_layer_renderer_s *cp_layer_renderer_t; +# endif +#endif + + QT_BEGIN_NAMESPACE namespace QNativeInterface @@ -61,6 +77,21 @@ struct Q_GUI_EXPORT QWaylandApplication }; #endif +#if defined(Q_OS_VISIONOS) || defined(Q_QDOC) +struct Q_GUI_EXPORT QVisionOSApplication +{ + QT_DECLARE_NATIVE_INTERFACE(QVisionOSApplication, 1, QGuiApplication) + struct ImmersiveSpaceCompositorLayer { + virtual void configure(cp_layer_renderer_capabilities_t, cp_layer_renderer_configuration_t) const {} + virtual void render(cp_layer_renderer_t) = 0; + virtual void handleSpatialEvents(const QJsonObject &) {}; + }; + virtual void setImmersiveSpaceCompositorLayer(ImmersiveSpaceCompositorLayer *layer) = 0; + virtual void openImmersiveSpace() = 0; + virtual void dismissImmersiveSpace() = 0; +}; +#endif + } // QNativeInterface QT_END_NAMESPACE diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index 189f31fd0a..d6deb8a72a 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -172,7 +172,7 @@ inline QMargins scale(const QMargins &margins, qreal scaleFactor, QPoint origin template<typename T> QList<T> scale(const QList<T> &list, qreal scaleFactor, QPoint origin = QPoint(0, 0)) { - if (!QHighDpiScaling::isActive()) + if (qFuzzyCompare(scaleFactor, qreal(1))) return list; QList<T> scaled; @@ -184,7 +184,7 @@ QList<T> scale(const QList<T> &list, qreal scaleFactor, QPoint origin = QPoint(0 inline QRegion scale(const QRegion ®ion, qreal scaleFactor, QPoint origin = QPoint(0, 0)) { - if (!QHighDpiScaling::isActive()) + if (qFuzzyCompare(scaleFactor, qreal(1))) return region; QRegion scaled = region.translated(-origin); diff --git a/src/gui/kernel/qinputmethod.cpp b/src/gui/kernel/qinputmethod.cpp index e37e85e246..175450f890 100644 --- a/src/gui/kernel/qinputmethod.cpp +++ b/src/gui/kernel/qinputmethod.cpp @@ -4,7 +4,6 @@ #include <qinputmethod.h> #include <private/qinputmethod_p.h> #include <qguiapplication.h> -#include <qtimer.h> #include <qpa/qplatforminputcontext_p.h> #include <QDebug> diff --git a/src/gui/kernel/qpaintdevicewindow.cpp b/src/gui/kernel/qpaintdevicewindow.cpp index 9e8c6ae5a8..8531aeed51 100644 --- a/src/gui/kernel/qpaintdevicewindow.cpp +++ b/src/gui/kernel/qpaintdevicewindow.cpp @@ -136,6 +136,11 @@ int QPaintDeviceWindow::metric(PaintDeviceMetric metric) const case PdmDevicePixelRatioScaled: return int(QWindow::devicePixelRatio() * devicePixelRatioFScale()); break; + case PdmDevicePixelRatioF_EncodedA: + Q_FALLTHROUGH(); + case PdmDevicePixelRatioF_EncodedB: + return QPaintDevice::encodeMetricF(metric, QWindow::devicePixelRatio()); + break; default: break; } diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp index 256ea52f01..e308b796ab 100644 --- a/src/gui/kernel/qpalette.cpp +++ b/src/gui/kernel/qpalette.cpp @@ -958,7 +958,10 @@ static constexpr QPalette::ResolveMask allResolveMask() /*! Returns a new QPalette that is a union of this instance and \a other. - Color roles set in this instance take precedence. + Color roles set in this instance take precedence. Roles that are not + set in this instance will be taken from \a other. + + \sa isBrushSet */ QPalette QPalette::resolve(const QPalette &other) const { diff --git a/src/gui/kernel/qplatformkeymapper.h b/src/gui/kernel/qplatformkeymapper.h index fb5b0cdb8b..431adc668c 100644 --- a/src/gui/kernel/qplatformkeymapper.h +++ b/src/gui/kernel/qplatformkeymapper.h @@ -18,7 +18,7 @@ QT_BEGIN_NAMESPACE -Q_DECLARE_EXPORTED_LOGGING_CATEGORY(lcQpaKeyMapper, Q_GUI_EXPORT) +QT_DECLARE_EXPORTED_QT_LOGGING_CATEGORY(lcQpaKeyMapper, Q_GUI_EXPORT) class QKeyEvent; diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 3d1319615e..2f0a16fc29 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -652,6 +652,10 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint) return QVariant(QSize(16, 16)); case UnderlineShortcut: return true; + case ShowIconsInMenus: + return true; + case PreferFileIconFromTheme: + return false; } return QVariant(); diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index d007a19675..6c671aff2f 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -97,6 +97,8 @@ public: MouseCursorTheme, MouseCursorSize, UnderlineShortcut, + ShowIconsInMenus, + PreferFileIconFromTheme, }; Q_ENUM(ThemeHint) diff --git a/src/gui/kernel/qplatformwindow_p.h b/src/gui/kernel/qplatformwindow_p.h index 2bbdfd5bf9..0bbddea722 100644 --- a/src/gui/kernel/qplatformwindow_p.h +++ b/src/gui/kernel/qplatformwindow_p.h @@ -58,6 +58,8 @@ struct Q_GUI_EXPORT QCocoaWindow QT_DECLARE_NATIVE_INTERFACE(QCocoaWindow, 1, QWindow) virtual void setContentBorderEnabled(bool enable) = 0; virtual QPoint bottomLeftClippedByNSWindowOffset() const = 0; + + virtual bool inLiveResize() const = 0; }; #endif diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 800e703ac2..7cd273f57c 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -17,7 +17,7 @@ QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcShortcutMap, "qt.gui.shortcutmap") +Q_STATIC_LOGGING_CATEGORY(lcShortcutMap, "qt.gui.shortcutmap") /* \internal Entry data for QShortcutMap diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index a90e8dd33c..bff1ad482b 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -30,7 +30,7 @@ QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcDnd, "qt.gui.dnd") +Q_STATIC_LOGGING_CATEGORY(lcDnd, "qt.gui.dnd") static QWindow* topLevelAt(const QPoint &pos) { diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp index 0d15d114ec..73c6199733 100644 --- a/src/gui/kernel/qstylehints.cpp +++ b/src/gui/kernel/qstylehints.cpp @@ -443,6 +443,40 @@ void QStyleHints::setShowShortcutsInContextMenus(bool s) } /*! + \property QStyleHints::contextMenuTrigger + \since 6.8 + \brief mouse event used to trigger a context menu event. + + The default on UNIX systems is to show context menu on mouse button press event, while on + Windows it is the mouse button release event. This property can be used to override the default + platform behavior. + + \note Developers must use this property with great care, as it changes the default interaction + mode that their users will expect on the platform that they are running on. + + \sa Qt::ContextMenuTrigger +*/ +Qt::ContextMenuTrigger QStyleHints::contextMenuTrigger() const +{ + Q_D(const QStyleHints); + if (d->m_contextMenuTrigger == -1) { + return themeableHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() + ? Qt::ContextMenuTrigger::Release + : Qt::ContextMenuTrigger::Press; + } + return Qt::ContextMenuTrigger(d->m_contextMenuTrigger); +} + +void QStyleHints::setContextMenuTrigger(Qt::ContextMenuTrigger contextMenuTrigger) +{ + Q_D(QStyleHints); + const Qt::ContextMenuTrigger currentTrigger = this->contextMenuTrigger(); + d->m_contextMenuTrigger = int(contextMenuTrigger); + if (currentTrigger != contextMenuTrigger) + emit contextMenuTriggerChanged(contextMenuTrigger); +} + +/*! \property QStyleHints::passwordMaskDelay \brief the time, in milliseconds, a typed letter is displayed unshrouded in a text input field in password mode. diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h index 8981383060..97ef59f3cf 100644 --- a/src/gui/kernel/qstylehints.h +++ b/src/gui/kernel/qstylehints.h @@ -36,6 +36,8 @@ class Q_GUI_EXPORT QStyleHints : public QObject Q_PROPERTY(bool showIsMaximized READ showIsMaximized STORED false CONSTANT FINAL) Q_PROPERTY(bool showShortcutsInContextMenus READ showShortcutsInContextMenus WRITE setShowShortcutsInContextMenus NOTIFY showShortcutsInContextMenusChanged FINAL) + Q_PROPERTY(Qt::ContextMenuTrigger contextMenuTrigger READ contextMenuTrigger WRITE + setContextMenuTrigger NOTIFY contextMenuTriggerChanged FINAL) Q_PROPERTY(int startDragDistance READ startDragDistance NOTIFY startDragDistanceChanged FINAL) Q_PROPERTY(int startDragTime READ startDragTime NOTIFY startDragTimeChanged FINAL) Q_PROPERTY(int startDragVelocity READ startDragVelocity STORED false CONSTANT FINAL) @@ -80,6 +82,8 @@ public: bool showIsMaximized() const; bool showShortcutsInContextMenus() const; void setShowShortcutsInContextMenus(bool showShortcutsInContextMenus); + Qt::ContextMenuTrigger contextMenuTrigger() const; + void setContextMenuTrigger(Qt::ContextMenuTrigger contextMenuTrigger); int passwordMaskDelay() const; QChar passwordMaskCharacter() const; qreal fontSmoothingGamma() const; @@ -108,6 +112,7 @@ Q_SIGNALS: void tabFocusBehaviorChanged(Qt::TabFocusBehavior tabFocusBehavior); void useHoverEffectsChanged(bool useHoverEffects); void showShortcutsInContextMenusChanged(bool); + void contextMenuTriggerChanged(Qt::ContextMenuTrigger contextMenuTrigger); void wheelScrollLinesChanged(int scrollLines); void mouseQuickSelectionThresholdChanged(int threshold); void colorSchemeChanged(Qt::ColorScheme colorScheme); diff --git a/src/gui/kernel/qstylehints_p.h b/src/gui/kernel/qstylehints_p.h index 2b3979512a..497bf95cbf 100644 --- a/src/gui/kernel/qstylehints_p.h +++ b/src/gui/kernel/qstylehints_p.h @@ -35,6 +35,7 @@ public: int m_tabFocusBehavior = -1; int m_uiEffects = -1; int m_showShortcutsInContextMenus = -1; + int m_contextMenuTrigger = -1; int m_wheelScrollLines = -1; int m_mouseQuickSelectionThreshold = -1; int m_mouseDoubleClickDistance = -1; diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index b40fd7e8e8..77655644ed 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -27,6 +27,8 @@ #endif // QT_CONFIG(draganddrop) #include <private/qevent_p.h> +#include <private/qeventpoint_p.h> +#include <private/qguiapplication_p.h> #include <QtCore/QTimer> #include <QtCore/QDebug> @@ -186,6 +188,7 @@ QWindow::~QWindow() // Decouple from parent before window goes under setParent(nullptr); QGuiApplicationPrivate::window_list.removeAll(this); + QGuiApplicationPrivate::popup_list.removeAll(this); if (!QGuiApplicationPrivate::is_app_closing) QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this); @@ -411,6 +414,13 @@ void QWindowPrivate::setVisible(bool visible) QGuiApplicationPrivate::updateBlockedStatus(q); } + if (q->type() == Qt::Popup) { + if (visible) + QGuiApplicationPrivate::activatePopup(q); + else + QGuiApplicationPrivate::closePopup(q); + } + #ifndef QT_NO_CURSOR if (visible && (hasCursor || QGuiApplication::overrideCursor())) applyCursor(); @@ -2361,8 +2371,13 @@ bool QWindow::close() if (!isTopLevel()) return false; - if (!d->platformWindow) + if (!d->platformWindow) { + // dock widgets can transition back and forth to being popups; + // avoid getting stuck + if (QGuiApplicationPrivate::activePopupWindow() == this) + QGuiApplicationPrivate::closePopup(this); return true; + } // The window might be deleted during close, // as a result of delivering the close event. @@ -2402,6 +2417,52 @@ bool QWindowPrivate::treatAsVisible() const return q->isVisible(); } +/*! \internal + Returns the popup window that has consumed \a event, if any. + \a activePopupOnPress is the window that we have observed previously handling the press. +*/ +const QWindow *QWindowPrivate::forwardToPopup(QEvent *event, const QWindow */*activePopupOnPress*/) +{ + Q_Q(const QWindow); + qCDebug(lcPopup) << "checking for popup alternative to" << q << "for" << event + << "active popup?" << QGuiApplicationPrivate::activePopupWindow(); + QWindow *ret = nullptr; + if (QWindow *popupWindow = QGuiApplicationPrivate::activePopupWindow()) { + if (q == popupWindow) + return nullptr; // avoid infinite recursion: we're already handling it + if (event->isPointerEvent()) { + // detach eventPoints before modifying them + QScopedPointer<QPointerEvent> pointerEvent(static_cast<QPointerEvent *>(event)->clone()); + for (int i = 0; i < pointerEvent->pointCount(); ++i) { + QEventPoint &eventPoint = pointerEvent->point(i); + const QPoint globalPos = eventPoint.globalPosition().toPoint(); + const QPointF mapped = popupWindow->mapFromGlobal(globalPos); + QMutableEventPoint::setPosition(eventPoint, mapped); + QMutableEventPoint::setScenePosition(eventPoint, mapped); + } + + /* Popups are expected to be able to directly handle the + drag-release sequence after pressing to open, as well as + any other mouse events that occur within the popup's bounds. */ + if (QCoreApplication::sendEvent(popupWindow, pointerEvent.get())) { + event->setAccepted(pointerEvent->isAccepted()); + if (pointerEvent->isAccepted()) + ret = popupWindow; + } + qCDebug(lcPopup) << q << "forwarded" << event->type() << "to popup" << popupWindow + << "handled?" << (ret != nullptr) << event->isAccepted(); + return ret; + } else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { + if (QCoreApplication::sendEvent(popupWindow, event)) + ret = popupWindow; + qCDebug(lcPopup) << q << "forwarded" << event->type() << "to popup" << popupWindow + << "handled?" << (ret != nullptr) << event->isAccepted(); + return ret; + } + } + return ret; +} + /*! The expose event (\a ev) is sent by the window system when a window moves between the un-exposed and exposed states. @@ -2654,16 +2715,14 @@ bool QWindow::event(QEvent *ev) This logic could be simplified by always synthesizing events in QGuiApplicationPrivate, or perhaps even in each QPA plugin. See QTBUG-93486. */ - static const QEvent::Type contextMenuTrigger = - QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ContextMenuOnMouseRelease).toBool() ? - QEvent::MouseButtonRelease : QEvent::MouseButtonPress; auto asMouseEvent = [](QEvent *ev) { const auto t = ev->type(); return t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease ? static_cast<QMouseEvent *>(ev) : nullptr ; }; - if (QMouseEvent *me = asMouseEvent(ev); me && - ev->type() == contextMenuTrigger && me->button() == Qt::RightButton) { + if (QMouseEvent *me = asMouseEvent(ev); + me && ev->type() == QGuiApplicationPrivate::contextMenuEventType() + && me->button() == Qt::RightButton) { QContextMenuEvent e(QContextMenuEvent::Mouse, me->position().toPoint(), me->globalPosition().toPoint(), me->modifiers()); QGuiApplication::sendEvent(this, &e); diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 40ab06af8b..b3722a6ed8 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -97,6 +97,8 @@ public: virtual bool participatesInLastWindowClosed() const; virtual bool treatAsVisible() const; + const QWindow *forwardToPopup(QEvent *event, const QWindow *activePopupOnPress); + bool isPopup() const { return (windowFlags & Qt::WindowType_Mask) == Qt::Popup; } void setAutomaticPositionAndResizeEnabled(bool a) { positionAutomatic = resizeAutomatic = a; } diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 51ab58fc99..677a5ed628 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -224,9 +224,11 @@ public: Qt::MouseButtons state, Qt::KeyboardModifiers mods, Qt::MouseButton b, QEvent::Type type, Qt::MouseEventSource src = Qt::MouseEventNotSynthesized, bool frame = false, - const QPointingDevice *device = QPointingDevice::primaryPointingDevice()) + const QPointingDevice *device = QPointingDevice::primaryPointingDevice(), + int evPtId = -1) : PointerEvent(w, time, Mouse, mods, device), localPos(local), globalPos(global), - buttons(state), source(src), nonClientArea(frame), button(b), buttonType(type) { } + buttons(state), source(src), nonClientArea(frame), button(b), buttonType(type), + eventPointId(evPtId) { } QPointF localPos; QPointF globalPos; @@ -235,6 +237,7 @@ public: bool nonClientArea; Qt::MouseButton button; QEvent::Type buttonType; + int eventPointId; // from the original device if synth-mouse, otherwise -1 }; class WheelEvent : public PointerEvent { |