summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel')
-rw-r--r--src/gui/kernel/qaction.cpp8
-rw-r--r--src/gui/kernel/qactiongroup.cpp24
-rw-r--r--src/gui/kernel/qguiapplication.cpp152
-rw-r--r--src/gui/kernel/qguiapplication_p.h15
-rw-r--r--src/gui/kernel/qguiapplication_platform.h31
-rw-r--r--src/gui/kernel/qhighdpiscaling_p.h4
-rw-r--r--src/gui/kernel/qinputmethod.cpp1
-rw-r--r--src/gui/kernel/qpaintdevicewindow.cpp5
-rw-r--r--src/gui/kernel/qpalette.cpp5
-rw-r--r--src/gui/kernel/qplatformkeymapper.h2
-rw-r--r--src/gui/kernel/qplatformtheme.cpp4
-rw-r--r--src/gui/kernel/qplatformtheme.h2
-rw-r--r--src/gui/kernel/qplatformwindow_p.h2
-rw-r--r--src/gui/kernel/qshortcutmap.cpp2
-rw-r--r--src/gui/kernel/qsimpledrag.cpp2
-rw-r--r--src/gui/kernel/qstylehints.cpp34
-rw-r--r--src/gui/kernel/qstylehints.h5
-rw-r--r--src/gui/kernel/qstylehints_p.h1
-rw-r--r--src/gui/kernel/qwindow.cpp71
-rw-r--r--src/gui/kernel/qwindow_p.h2
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h7
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 &region, 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 {