summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel')
-rw-r--r--src/gui/kernel/kernel.pri7
-rw-r--r--src/gui/kernel/qdnd_p.h4
-rw-r--r--src/gui/kernel/qevent.cpp58
-rw-r--r--src/gui/kernel/qevent.h13
-rw-r--r--src/gui/kernel/qguiapplication.cpp132
-rw-r--r--src/gui/kernel/qguiapplication_p.h11
-rw-r--r--src/gui/kernel/qhighdpiscaling.cpp3
-rw-r--r--src/gui/kernel/qkeysequence.cpp5
-rw-r--r--src/gui/kernel/qopenglcontext.cpp100
-rw-r--r--src/gui/kernel/qopenglwindow.cpp6
-rw-r--r--src/gui/kernel/qpalette.cpp43
-rw-r--r--src/gui/kernel/qpalette.h4
-rw-r--r--src/gui/kernel/qplatformdialoghelper.h1
-rw-r--r--src/gui/kernel/qplatformgraphicsbufferhelper.cpp41
-rw-r--r--src/gui/kernel/qplatformintegration.cpp4
-rw-r--r--src/gui/kernel/qplatformmenu.h1
-rw-r--r--src/gui/kernel/qplatformsurface.cpp25
-rw-r--r--src/gui/kernel/qplatformsurface.h9
-rw-r--r--src/gui/kernel/qplatformwindow.cpp82
-rw-r--r--src/gui/kernel/qplatformwindow.h5
-rw-r--r--src/gui/kernel/qplatformwindow_p.h2
-rw-r--r--src/gui/kernel/qshortcutmap.cpp13
-rw-r--r--src/gui/kernel/qsimpledrag.cpp132
-rw-r--r--src/gui/kernel/qsimpledrag_p.h32
-rw-r--r--src/gui/kernel/qsurface.cpp4
-rw-r--r--src/gui/kernel/qsurface.h6
-rw-r--r--src/gui/kernel/qtestsupport_gui.cpp83
-rw-r--r--src/gui/kernel/qtestsupport_gui.h56
-rw-r--r--src/gui/kernel/qwindow.cpp41
-rw-r--r--src/gui/kernel/qwindow_p.h6
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp42
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h18
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h2
33 files changed, 729 insertions, 262 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 3b9afdfe8b..1f137fc46f 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -74,8 +74,8 @@ HEADERS += \
kernel/qplatformgraphicsbufferhelper.h \
kernel/qinputdevicemanager_p.h \
kernel/qinputdevicemanager_p_p.h \
- kernel/qhighdpiscaling_p.h
-
+ kernel/qhighdpiscaling_p.h \
+ kernel/qtestsupport_gui.h
SOURCES += \
kernel/qgenericpluginfactory.cpp \
@@ -128,7 +128,8 @@ SOURCES += \
kernel/qplatformgraphicsbuffer.cpp \
kernel/qplatformgraphicsbufferhelper.cpp \
kernel/qinputdevicemanager.cpp \
- kernel/qhighdpiscaling.cpp
+ kernel/qhighdpiscaling.cpp \
+ kernel/qtestsupport_gui.cpp
qtConfig(draganddrop) {
HEADERS += \
diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h
index cc00bc1442..5f6db07987 100644
--- a/src/gui/kernel/qdnd_p.h
+++ b/src/gui/kernel/qdnd_p.h
@@ -63,10 +63,6 @@
#include "private/qobject_p.h"
#include "QtGui/qbackingstore.h"
-// ### Remove the following include, once everybody includes
-// qinternalmimedata_p.h for QInternalMimeData.
-#include "qinternalmimedata_p.h"
-
QT_REQUIRE_CONFIG(draganddrop);
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 4207697c01..0e35fb7d7b 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -783,7 +783,7 @@ QWheelEvent::QWheelEvent(const QPointF &pos, int delta,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
Qt::Orientation orient)
: QInputEvent(Wheel, modifiers), p(pos), qt4D(delta), qt4O(orient), mouseState(buttons),
- ph(Qt::NoScrollPhase), src(Qt::MouseEventNotSynthesized), invertedScrolling(false)
+ src(Qt::MouseEventNotSynthesized), invertedScrolling(false), ph(Qt::NoScrollPhase)
{
g = QCursor::pos();
if (orient == Qt::Vertical)
@@ -818,7 +818,7 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers,
Qt::Orientation orient)
: QInputEvent(Wheel, modifiers), p(pos), g(globalPos), qt4D(delta), qt4O(orient), mouseState(buttons),
- ph(Qt::NoScrollPhase), src(Qt::MouseEventNotSynthesized), invertedScrolling(false)
+ src(Qt::MouseEventNotSynthesized), invertedScrolling(false), ph(Qt::NoScrollPhase)
{
if (orient == Qt::Vertical)
angleD = QPoint(0, delta);
@@ -959,10 +959,49 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
QPoint pixelDelta, QPoint angleDelta, int qt4Delta, Qt::Orientation qt4Orientation,
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, Qt::MouseEventSource source, bool inverted)
: QInputEvent(Wheel, modifiers), p(pos), g(globalPos), pixelD(pixelDelta),
- angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons), ph(phase), src(source),
- invertedScrolling(inverted)
+ angleD(angleDelta), qt4D(qt4Delta), qt4O(qt4Orientation), mouseState(buttons), src(source),
+ invertedScrolling(inverted), ph(phase)
{}
+/*!
+ Constructs a wheel event object.
+
+ The \a pos provides the location of the mouse cursor
+ within the window. The position in global coordinates is specified
+ by \a globalPos.
+
+ \a pixelDelta contains the scrolling distance in pixels on screen, while
+ \a angleDelta contains the wheel rotation distance. \a pixelDelta is
+ optional and can be null.
+
+ The mouse and keyboard states at the time of the event are specified by
+ \a buttons and \a modifiers.
+
+ The scrolling phase of the event is specified by \a phase.
+
+ If the wheel event comes from a physical mouse wheel, \a source is set to
+ Qt::MouseEventNotSynthesized. If it comes from a gesture detected by the
+ operating system, or from a non-mouse hardware device, such that \a
+ pixelDelta is directly related to finger movement, \a source is set to
+ Qt::MouseEventSynthesizedBySystem. If it comes from Qt, source would be set
+ to Qt::MouseEventSynthesizedByQt.
+
+ If the system is configured to invert the delta values delivered with the
+ event (such as natural scrolling of the touchpad on macOS), \a inverted
+ should be \c true. Otherwise, \a inverted is \c false
+
+ \sa posF(), globalPosF(), angleDelta(), pixelDelta(), phase()
+*/
+QWheelEvent::QWheelEvent(QPointF pos, QPointF globalPos, QPoint pixelDelta, QPoint angleDelta,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase,
+ bool inverted, Qt::MouseEventSource source)
+ : QInputEvent(Wheel, modifiers), p(pos), g(globalPos), pixelD(pixelDelta), angleD(angleDelta),
+ qt4O(qAbs(angleDelta.x()) > qAbs(angleDelta.y()) ? Qt::Horizontal : Qt::Vertical),
+ mouseState(buttons), src(source), invertedScrolling(inverted), ph(phase)
+{
+ qt4D = (qt4O == Qt::Horizontal ? angleDelta.x() : angleDelta.y());
+}
+
#endif // QT_CONFIG(wheelevent)
/*!
@@ -1536,8 +1575,8 @@ QMoveEvent::~QMoveEvent()
\ingroup events
- Expose events are sent to windows when an area of the window is invalidated
- or window exposure in the windowing system changes.
+ Expose events are sent to windows when an area of the window is invalidated,
+ for example when window exposure in the windowing system changes.
A Window with a client area that is completely covered by another window, or
is otherwise not visible may be considered obscured by Qt and may in such
@@ -4031,7 +4070,12 @@ QDebug operator<<(QDebug dbg, const QEvent *e)
# if QT_CONFIG(wheelevent)
case QEvent::Wheel: {
const QWheelEvent *we = static_cast<const QWheelEvent *>(e);
- dbg << "QWheelEvent(" << "pixelDelta=" << we->pixelDelta() << ", angleDelta=" << we->angleDelta() << ')';
+ dbg << "QWheelEvent(" << we->phase();
+ if (!we->pixelDelta().isNull() || !we->angleDelta().isNull())
+ dbg << ", pixelDelta=" << we->pixelDelta() << ", angleDelta=" << we->angleDelta();
+ else if (int qt4Delta = we->delta())
+ dbg << ", delta=" << qt4Delta << ", orientation=" << we->orientation();
+ dbg << ')';
}
break;
# endif // QT_CONFIG(wheelevent)
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 033d24d665..2b1c6a6e31 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -193,6 +193,10 @@ public:
QWheelEvent(const QPointF &pos, const QPointF &globalPos, QPoint pixelDelta, QPoint angleDelta,
int qt4Delta, Qt::Orientation qt4Orientation, Qt::MouseButtons buttons,
Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, Qt::MouseEventSource source, bool inverted);
+
+ QWheelEvent(QPointF pos, QPointF globalPos, QPoint pixelDelta, QPoint angleDelta,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase,
+ bool inverted, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
~QWheelEvent();
@@ -225,13 +229,14 @@ protected:
QPointF g;
QPoint pixelD;
QPoint angleD;
- int qt4D;
- Qt::Orientation qt4O;
+ int qt4D = 0;
+ Qt::Orientation qt4O = Qt::Vertical;
Qt::MouseButtons mouseState;
- uint ph : 2;
+ uint _unused_ : 2; // Kept for binary compatibility
uint src: 2;
bool invertedScrolling : 1;
- int reserved : 27;
+ uint ph : 3;
+ int reserved : 24;
friend class QApplication;
};
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index e81c88cc71..9bf2a33e2a 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -114,6 +114,10 @@
# include <QtCore/QLibraryInfo>
#endif // Q_OS_WIN
+#ifdef Q_OS_WASM
+#include <emscripten.h>
+#endif
+
#include <qtgui_tracepoints_p.h>
#include <ctype.h>
@@ -143,6 +147,8 @@ Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationI
bool QGuiApplicationPrivate::highDpiScalingUpdated = false;
+QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
+
QVector<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints;
QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0;
@@ -250,10 +256,10 @@ static inline void clearFontUnlocked()
QGuiApplicationPrivate::app_font = 0;
}
-static bool checkRunningUnderFlatpak()
+static bool checkNeedPortalSupport()
{
#if QT_CONFIG(dbus)
- return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty();
+ return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty() || qEnvironmentVariableIsSet("SNAP");
#else
return false;
#endif // QT_CONFIG(dbus)
@@ -592,6 +598,9 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
By default, they will be used if the application is not an
instance of QApplication or for Qt Quick Controls 2
applications.
+
+ \li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
+ Qt::GroupSwitchModifier.
\endlist
The following parameter is available for \c {-platform cocoa} (on macOS):
@@ -668,6 +677,7 @@ QGuiApplication::~QGuiApplication()
QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
QGuiApplicationPrivate::highDpiScalingUpdated = false;
+ QGuiApplicationPrivate::currentDragWindow = nullptr;
QGuiApplicationPrivate::tabletDevicePoints.clear();
#ifndef QT_NO_SESSIONMANAGER
QGuiApplicationPrivate::is_fallback_session_management_enabled = true;
@@ -1215,9 +1225,9 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
if (!platformThemeName.isEmpty())
themeNames.append(platformThemeName);
- // 2) Special case - check whether we are in sandbox to use flatpak platform theme for portals support
- if (checkRunningUnderFlatpak()) {
- themeNames.append(QStringLiteral("flatpak"));
+ // 2) Special case - check whether it's a flatpak or snap app to use xdg-desktop-portal platform theme for portals support
+ if (checkNeedPortalSupport()) {
+ themeNames.append(QStringLiteral("xdgdesktopportal"));
}
// 3) Ask the platform integration for a list of theme names
@@ -1409,7 +1419,7 @@ void QGuiApplicationPrivate::eventDispatcherReady()
void QGuiApplicationPrivate::init()
{
- Q_TRACE(qguiapplicationprivate_init_entry);
+ Q_TRACE(QGuiApplicationPrivate_init_entry);
#if defined(Q_OS_MACOS)
QMacAutoReleasePool pool;
@@ -1574,7 +1584,7 @@ void QGuiApplicationPrivate::init()
QObject::connect(q, &QGuiApplication::applicationNameChanged,
q, &QGuiApplication::applicationDisplayNameChanged);
- Q_TRACE(qguiapplicationprivate_init_exit);
+ Q_TRACE(QGuiApplicationPrivate_init_exit);
}
extern void qt_cleanupFontDatabase();
@@ -1614,7 +1624,13 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
qt_gl_set_global_share_context(0);
}
#endif
-
+#ifdef Q_OS_WASM
+ EM_ASM(
+ // unmount persistent directory as IDBFS
+ // see QTBUG-70002
+ FS.unmount('/home/web_user');
+ );
+#endif
platform_integration->destroy();
delete platform_theme;
@@ -1690,7 +1706,7 @@ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
/*!
Returns the current state of the buttons on the mouse. The current state is
- updated syncronously as the event queue is emptied of events that will
+ updated synchronously as the event queue is emptied of events that will
spontaneously change the mouse state (QEvent::MouseButtonPress and
QEvent::MouseButtonRelease events).
@@ -1765,8 +1781,11 @@ int QGuiApplication::exec()
*/
bool QGuiApplication::notify(QObject *object, QEvent *event)
{
- if (object->isWindowType())
- QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event);
+ if (object->isWindowType()) {
+ if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event))
+ return true; // Platform plugin ate the event
+ }
+
return QCoreApplication::notify(object, event);
}
@@ -1788,18 +1807,18 @@ bool QGuiApplication::compressEvent(QEvent *event, QObject *receiver, QPostEvent
return QCoreApplication::compressEvent(event, receiver, postedEvents);
}
-void QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event)
+bool QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event)
{
if (!window)
- return;
+ return false;
QPlatformWindow *platformWindow = window->handle();
if (!platformWindow)
- return;
+ return false;
// spontaneous events come from the platform integration already, we don't need to send the events back
if (event->spontaneous())
- return;
+ return false;
// let the platform window do any handling it needs to as well
- platformWindow->windowEvent(event);
+ return platformWindow->windowEvent(event);
}
bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)
@@ -1809,7 +1828,7 @@ bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArra
void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
{
- Q_TRACE(qguiapplicationprivate_processwsevents_entry, e->type);
+ Q_TRACE(QGuiApplicationPrivate_processWindowSystemEvent_entry, e->type);
switch(e->type) {
case QWindowSystemInterfacePrivate::Mouse:
@@ -1920,7 +1939,7 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
break;
}
- Q_TRACE(qguiapplicationprivate_processwsevents_exit, e->type);
+ Q_TRACE(QGuiApplicationPrivate_processWindowSystemEvent_exit, e->type);
}
/*! \internal
@@ -2332,11 +2351,11 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf
if (QWindow *window = wse->window.data()) {
if (window->screen() == wse->screen.data())
return;
- if (window->isTopLevel()) {
+ if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) {
if (QScreen *screen = wse->screen.data())
- window->d_func()->setTopLevelScreen(screen, false /* recreate */);
+ topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
else // Fall back to default behavior, and try to find some appropriate screen
- window->setScreen(0);
+ topLevelWindow->setScreen(0);
}
// we may have changed scaling, so trigger resize event if needed
if (window->handle()) {
@@ -3047,9 +3066,56 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E
#if QT_CONFIG(draganddrop)
-QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+/*! \internal
+
+ This function updates an internal state to keep the source compatibility. Documentation of
+ QGuiApplication::mouseButtons() states - "The current state is updated synchronously as
+ the event queue is emptied of events that will spontaneously change the mouse state
+ (QEvent::MouseButtonPress and QEvent::MouseButtonRelease events)". But internally we have
+ been updating these state variables from various places to keep buttons returned by
+ mouseButtons() in sync with the systems state. This is not the documented behavior.
+
+ ### Qt6 - Remove QGuiApplication::mouseButtons()/keyboardModifiers() API? And here
+ are the reasons:
+
+ - It is an easy to misuse API by:
+
+ a) Application developers: The only place where the values of this API can be trusted is
+ when using within mouse handling callbacks. In these callbacks we work with the state
+ that was provided directly by the windowing system. Anywhere else it might not reflect what
+ user wrongly expects. We might not always receive a matching mouse release for a press event
+ (e.g. When dismissing a popup window on X11. Or when dnd enter Qt application with mouse
+ button down, we update mouse_buttons and then dnd leaves Qt application and does a drop
+ somewhere else) and hence mouseButtons() will be out-of-sync from users perspective, see
+ for example QTBUG-33161. BUT THIS IS NOT HOW THE API IS SUPPOSED TO BE USED. Since the only
+ safe place to use this API is from mouse event handlers, we might as well deprecate it and
+ pass down the button state if we are not already doing that everywhere where it matters.
+
+ b) Qt framework developers:
+
+ We see users complaining, we start adding hacks everywhere just to keep buttons in sync ;)
+ There are corner cases that can not be solved and adding this kind of hacks is never ending
+ task.
+
+ - Real mouse events, tablet mouse events, etc: all go through QGuiApplication::processMouseEvent,
+ and all share mouse_buttons. What if we want to support multiple mice in future? The API must
+ go.
+
+ - Motivation why this API is public is not clear. Could the same be achieved by a user by
+ installing an event filter?
+*/
+static void updateMouseAndModifierButtonState(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
{
- static QPointer<QWindow> currentDragWindow;
+ QGuiApplicationPrivate::mouse_buttons = buttons;
+ QGuiApplicationPrivate::modifier_buttons = modifiers;
+}
+
+QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+{
+ updateMouseAndModifierButtonState(buttons, modifiers);
+
static Qt::DropAction lastAcceptedDropAction = Qt::IgnoreAction;
QPlatformDrag *platformDrag = platformIntegration()->drag();
if (!platformDrag || (w && w->d_func()->blockedByModalWindow)) {
@@ -3058,15 +3124,13 @@ QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QM
}
if (!dropData) {
- if (currentDragWindow.data() == w)
- currentDragWindow = 0;
+ currentDragWindow = nullptr;
QDragLeaveEvent e;
QGuiApplication::sendEvent(w, &e);
lastAcceptedDropAction = Qt::IgnoreAction;
return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
}
- QDragMoveEvent me(p, supportedActions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ QDragMoveEvent me(p, supportedActions, dropData, buttons, modifiers);
if (w != currentDragWindow) {
lastAcceptedDropAction = Qt::IgnoreAction;
@@ -3075,8 +3139,7 @@ QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QM
QGuiApplication::sendEvent(currentDragWindow, &e);
}
currentDragWindow = w;
- QDragEnterEvent e(p, supportedActions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ QDragEnterEvent e(p, supportedActions, dropData, buttons, modifiers);
QGuiApplication::sendEvent(w, &e);
if (e.isAccepted() && e.dropAction() != Qt::IgnoreAction)
lastAcceptedDropAction = e.dropAction();
@@ -3094,10 +3157,15 @@ QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QM
return QPlatformDragQtResponse(me.isAccepted(), lastAcceptedDropAction, me.answerRect());
}
-QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
{
- QDropEvent de(p, supportedActions, dropData,
- QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+ updateMouseAndModifierButtonState(buttons, modifiers);
+
+ currentDragWindow = nullptr;
+
+ QDropEvent de(p, supportedActions, dropData, buttons, modifiers);
QGuiApplication::sendEvent(w, &de);
Qt::DropAction acceptedAction = de.isAccepted() ? de.dropAction() : Qt::IgnoreAction;
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index f6f7aa7f8c..79c1a1c820 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -163,13 +163,17 @@ public:
#endif
#if QT_CONFIG(draganddrop)
- static QPlatformDragQtResponse processDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
- static QPlatformDropQtResponse processDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
+ static QPlatformDragQtResponse processDrag(QWindow *w, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
+ static QPlatformDropQtResponse processDrop(QWindow *w, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
#endif
static bool processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result);
- static void sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event);
+ static bool sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event);
static inline Qt::Alignment visualAlignment(Qt::LayoutDirection direction, Qt::Alignment alignment)
{
@@ -213,6 +217,7 @@ public:
static QWindow *currentMousePressWindow;
static Qt::ApplicationState applicationState;
static bool highDpiScalingUpdated;
+ static QPointer<QWindow> currentDragWindow;
struct TabletPointData {
TabletPointData(qint64 devId = 0) : deviceId(devId), state(Qt::NoButton), target(nullptr) {}
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index 8689f9f3b1..a455aa639d 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -244,7 +244,8 @@ static inline bool usePixelDensity()
return false;
return QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling)
|| (screenEnvValueOk && screenEnvValue > 0)
- || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && qgetenv(legacyDevicePixelEnvVar).toLower() == "auto");
+ || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) &&
+ qgetenv(legacyDevicePixelEnvVar).compare("auto", Qt::CaseInsensitive) == 0);
}
void QHighDpiScaling::initHighDpiScaling()
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index 9a9677b476..a428da8ca4 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -1062,6 +1062,8 @@ int QKeySequence::decodeString(const QString &str)
int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceFormat format)
{
+ Q_ASSERT(!accel.isEmpty());
+
int ret = 0;
accel = std::move(accel).toLower();
bool nativeText = (format == QKeySequence::NativeText);
@@ -1121,7 +1123,10 @@ int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceForma
sl = accel;
}
}
+ if (accel.isEmpty()) // Incomplete, like for "Meta+Shift+"
+ return Qt::Key_unknown;
#endif
+
int i = 0;
int lastI = 0;
while ((i = sl.indexOf(QLatin1Char('+'), i + 1)) != -1) {
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 4efa5a40f3..c5d5490ea0 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -945,7 +945,7 @@ GLuint QOpenGLContext::defaultFramebufferObject() const
Avoid calling this function from a different thread than the one the
QOpenGLContext instance lives in. If you wish to use QOpenGLContext from a
- different thread you should first call make sure it's not current in the
+ different thread you should first make sure it's not current in the
current thread, by calling doneCurrent() if necessary. Then call
moveToThread(otherThread) before using it in the other thread.
@@ -977,67 +977,66 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
if (!surface->surfaceHandle())
return false;
if (!surface->supportsOpenGL()) {
+#ifndef Q_OS_WASM // ### work around the WASM platform plugin using QOpenGLContext with raster surfaces.
+ // see QTBUG-70076
qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface;
return false;
+#endif
}
- QOpenGLContext *previous = QOpenGLContextPrivate::setCurrentContext(this);
-
- if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) {
- static bool needsWorkaroundSet = false;
- static bool needsWorkaround = false;
+ if (!d->platformGLContext->makeCurrent(surface->surfaceHandle()))
+ return false;
- if (!needsWorkaroundSet) {
- QByteArray env;
-#ifdef Q_OS_ANDROID
- env = qgetenv(QByteArrayLiteral("QT_ANDROID_DISABLE_GLYPH_CACHE_WORKAROUND"));
- needsWorkaround = env.isEmpty() || env == QByteArrayLiteral("0") || env == QByteArrayLiteral("false");
+ QOpenGLContextPrivate::setCurrentContext(this);
+#ifndef QT_NO_DEBUG
+ QOpenGLContextPrivate::toggleMakeCurrentTracker(this, true);
#endif
- env = qgetenv(QByteArrayLiteral("QT_ENABLE_GLYPH_CACHE_WORKAROUND"));
- if (env == QByteArrayLiteral("1") || env == QByteArrayLiteral("true"))
- needsWorkaround = true;
-
- if (!needsWorkaround) {
- const char *rendererString = reinterpret_cast<const char *>(functions()->glGetString(GL_RENDERER));
- if (rendererString)
- needsWorkaround =
- qstrncmp(rendererString, "Mali-4xx", 6) == 0 // Mali-400, Mali-450
- || qstrcmp(rendererString, "Mali-T880") == 0
- || qstrncmp(rendererString, "Adreno (TM) 2xx", 13) == 0 // Adreno 200, 203, 205
- || qstrncmp(rendererString, "Adreno 2xx", 8) == 0 // Same as above but without the '(TM)'
- || qstrncmp(rendererString, "Adreno (TM) 3xx", 13) == 0 // Adreno 302, 305, 320, 330
- || qstrncmp(rendererString, "Adreno 3xx", 8) == 0 // Same as above but without the '(TM)'
- || qstrncmp(rendererString, "Adreno (TM) 4xx", 13) == 0 // Adreno 405, 418, 420, 430
- || qstrncmp(rendererString, "Adreno 4xx", 8) == 0 // Same as above but without the '(TM)'
- || qstrncmp(rendererString, "Adreno (TM) 5xx", 13) == 0 // Adreno 505, 506, 510, 530, 540
- || qstrncmp(rendererString, "Adreno 5xx", 8) == 0 // Same as above but without the '(TM)'
- || qstrncmp(rendererString, "Adreno (TM) 6xx", 13) == 0 // Adreno 610, 620, 630
- || qstrncmp(rendererString, "Adreno 6xx", 8) == 0 // Same as above but without the '(TM)'
- || qstrcmp(rendererString, "GC800 core") == 0
- || qstrcmp(rendererString, "GC1000 core") == 0
- || strstr(rendererString, "GC2000") != 0
- || qstrcmp(rendererString, "Immersion.16") == 0;
- }
- needsWorkaroundSet = true;
- }
-
- if (needsWorkaround)
- d->workaround_brokenFBOReadBack = true;
- d->surface = surface;
+ d->surface = surface;
- d->shareGroup->d_func()->deletePendingResources(this);
+ static bool needsWorkaroundSet = false;
+ static bool needsWorkaround = false;
-#ifndef QT_NO_DEBUG
- QOpenGLContextPrivate::toggleMakeCurrentTracker(this, true);
+ if (!needsWorkaroundSet) {
+ QByteArray env;
+#ifdef Q_OS_ANDROID
+ env = qgetenv(QByteArrayLiteral("QT_ANDROID_DISABLE_GLYPH_CACHE_WORKAROUND"));
+ needsWorkaround = env.isEmpty() || env == QByteArrayLiteral("0") || env == QByteArrayLiteral("false");
#endif
-
- return true;
+ env = qgetenv(QByteArrayLiteral("QT_ENABLE_GLYPH_CACHE_WORKAROUND"));
+ if (env == QByteArrayLiteral("1") || env == QByteArrayLiteral("true"))
+ needsWorkaround = true;
+
+ if (!needsWorkaround) {
+ const char *rendererString = reinterpret_cast<const char *>(functions()->glGetString(GL_RENDERER));
+ if (rendererString)
+ needsWorkaround =
+ qstrncmp(rendererString, "Mali-4xx", 6) == 0 // Mali-400, Mali-450
+ || qstrcmp(rendererString, "Mali-T880") == 0
+ || qstrncmp(rendererString, "Adreno (TM) 2xx", 13) == 0 // Adreno 200, 203, 205
+ || qstrncmp(rendererString, "Adreno 2xx", 8) == 0 // Same as above but without the '(TM)'
+ || qstrncmp(rendererString, "Adreno (TM) 3xx", 13) == 0 // Adreno 302, 305, 320, 330
+ || qstrncmp(rendererString, "Adreno 3xx", 8) == 0 // Same as above but without the '(TM)'
+ || qstrncmp(rendererString, "Adreno (TM) 4xx", 13) == 0 // Adreno 405, 418, 420, 430
+ || qstrncmp(rendererString, "Adreno 4xx", 8) == 0 // Same as above but without the '(TM)'
+ || qstrncmp(rendererString, "Adreno (TM) 5xx", 13) == 0 // Adreno 505, 506, 510, 530, 540
+ || qstrncmp(rendererString, "Adreno 5xx", 8) == 0 // Same as above but without the '(TM)'
+ || qstrncmp(rendererString, "Adreno (TM) 6xx", 13) == 0 // Adreno 610, 620, 630
+ || qstrncmp(rendererString, "Adreno 6xx", 8) == 0 // Same as above but without the '(TM)'
+ || qstrcmp(rendererString, "GC800 core") == 0
+ || qstrcmp(rendererString, "GC1000 core") == 0
+ || strstr(rendererString, "GC2000") != 0
+ || qstrcmp(rendererString, "Immersion.16") == 0;
+ }
+ needsWorkaroundSet = true;
}
- QOpenGLContextPrivate::setCurrentContext(previous);
+ if (needsWorkaround)
+ d->workaround_brokenFBOReadBack = true;
+
+ d->shareGroup->d_func()->deletePendingResources(this);
- return false;
+ return true;
}
/*!
@@ -1078,7 +1077,8 @@ QSurface *QOpenGLContext::surface() const
Swap the back and front buffers of \a surface.
Call this to finish a frame of OpenGL rendering, and make sure to
- call makeCurrent() again before you begin a new frame.
+ call makeCurrent() again before issuing any further OpenGL commands,
+ for example as part of a new frame.
*/
void QOpenGLContext::swapBuffers(QSurface *surface)
{
diff --git a/src/gui/kernel/qopenglwindow.cpp b/src/gui/kernel/qopenglwindow.cpp
index c3a264f1e8..8b052d92ae 100644
--- a/src/gui/kernel/qopenglwindow.cpp
+++ b/src/gui/kernel/qopenglwindow.cpp
@@ -511,7 +511,7 @@ GLuint QOpenGLWindow::defaultFramebufferObject() const
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
/*!
- Returns a 32-bit RGB image of the framebuffer.
+ Returns a copy of the framebuffer.
\note This is a potentially expensive operation because it relies on
glReadPixels() to read back the pixels. This may be slow and can stall the
@@ -531,7 +531,9 @@ QImage QOpenGLWindow::grabFramebuffer()
return QImage();
makeCurrent();
- QImage img = qt_gl_read_framebuffer(size() * devicePixelRatio(), false, false);
+
+ const bool hasAlpha = format().hasAlpha();
+ QImage img = qt_gl_read_framebuffer(size() * devicePixelRatio(), hasAlpha, hasAlpha);
img.setDevicePixelRatio(devicePixelRatio());
return img;
}
diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp
index 4905e51e01..9ccfb9b819 100644
--- a/src/gui/kernel/qpalette.cpp
+++ b/src/gui/kernel/qpalette.cpp
@@ -316,6 +316,21 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
*/
/*!
+ \fn const QBrush & QPalette::placeholderText() const
+ \since 5.12
+
+ Returns the placeholder text brush of the current color group.
+
+ \note Before Qt 5.12, the placeholder text color was hard-coded in the code as
+ QPalette::text().color() where an alpha of 128 was applied.
+ We continue to support this behavior by default, unless you set your own brush.
+ One can get back the original placeholder color setting the special QBrush default
+ constructor as placeholder brush.
+
+ \sa ColorRole, brush()
+*/
+
+/*!
\fn ColorGroup QPalette::currentColorGroup() const
Returns the palette's current color group.
@@ -444,6 +459,9 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
of QPalette, because tool tips are not active
windows.
+ \value PlaceholderText Used as the placeholder color for various text input widgets.
+ This enum value has been introduced in Qt 5.12
+
\value Text The foreground color used with \c Base. This is usually
the same as the \c WindowText, in which case it must provide
good contrast with \c Window and \c Base.
@@ -765,11 +783,32 @@ void QPalette::setBrush(ColorGroup cg, ColorRole cr, const QBrush &b)
cg = Active;
}
+ // For placeholder we want to continue to respect the original behavior, which is
+ // derivating the text color, but only if user has not yet set his own brush.
+ // We then use Qt::NoBrush as an inernal way to know if the brush is customized or not.
+
+ // ### Qt 6 - remove this special case
+ // Part 1 - Restore initial color to the given color group
+ if (cr == PlaceholderText && b == QBrush()) {
+ QColor col = brush(Text).color();
+ col.setAlpha(128);
+ setBrush(cg, PlaceholderText, QBrush(col, Qt::NoBrush));
+ return;
+ }
+
if (d->br[cg][cr] != b) {
detach();
d->br[cg][cr] = b;
}
data.resolve_mask |= (1<<cr);
+
+ // ### Qt 6 - remove this special case
+ // Part 2 - Update initial color to the given color group
+ if (cr == Text && d->br[cg][PlaceholderText].style() == Qt::NoBrush) {
+ QColor col = brush(Text).color();
+ col.setAlpha(128);
+ setBrush(cg, PlaceholderText, QBrush(col, Qt::NoBrush));
+ }
}
/*!
@@ -962,7 +1001,7 @@ QDataStream &operator<<(QDataStream &s, const QPalette &p)
for (int i = 0; i < NumOldRoles; ++i)
s << p.d->br[grp][oldRoles[i]].color();
} else {
- int max = QPalette::ToolTipText + 1;
+ int max = (int)QPalette::NColorRoles;
if (s.version() <= QDataStream::Qt_2_1)
max = QPalette::HighlightedText + 1;
else if (s.version() <= QDataStream::Qt_4_3)
@@ -1159,7 +1198,7 @@ QDebug operator<<(QDebug dbg, const QPalette &p)
{"WindowText", "Button", "Light", "Midlight", "Dark", "Mid", "Text",
"BrightText", "ButtonText", "Base", "Window", "Shadow", "Highlight",
"HighlightedText", "Link", "LinkVisited", "AlternateBase", "NoRole",
- "ToolTipBase","ToolTipText" };
+ "ToolTipBase","ToolTipText", "PlaceholderText" };
QDebugStateSaver saver(dbg);
QDebug nospace = dbg.nospace();
const uint mask = p.resolve();
diff --git a/src/gui/kernel/qpalette.h b/src/gui/kernel/qpalette.h
index 71f3d0c3b8..071eddbc4d 100644
--- a/src/gui/kernel/qpalette.h
+++ b/src/gui/kernel/qpalette.h
@@ -96,7 +96,8 @@ public:
AlternateBase,
NoRole,
ToolTipBase, ToolTipText,
- NColorRoles = ToolTipText + 1,
+ PlaceholderText,
+ NColorRoles = PlaceholderText + 1,
Foreground = WindowText, Background = Window
};
Q_ENUM(ColorRole)
@@ -141,6 +142,7 @@ public:
inline const QBrush &highlightedText() const { return brush(HighlightedText); }
inline const QBrush &link() const { return brush(Link); }
inline const QBrush &linkVisited() const { return brush(LinkVisited); }
+ inline const QBrush &placeholderText() const { return brush(PlaceholderText); }
bool operator==(const QPalette &p) const;
inline bool operator!=(const QPalette &p) const { return !(operator==(p)); }
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index f58dcf17f0..64b703e524 100644
--- a/src/gui/kernel/qplatformdialoghelper.h
+++ b/src/gui/kernel/qplatformdialoghelper.h
@@ -150,6 +150,7 @@ public:
MacModelessLayout,
AndroidLayout
};
+ Q_ENUM(ButtonLayout)
QPlatformDialogHelper();
virtual ~QPlatformDialogHelper();
diff --git a/src/gui/kernel/qplatformgraphicsbufferhelper.cpp b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
index 2afb5e6ba5..924266997d 100644
--- a/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
+++ b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
@@ -57,24 +57,28 @@
QT_BEGIN_NAMESPACE
/*!
- Convenience function to both lock and bind the buffer to a texture. This
- function will first try and lock with texture read and texture write
+ Convenience function to both lock and bind the \a graphicsBuffer to a texture.
+ This function will first try to lock with texture read and texture write
access. If this succeeds it will use the bindToTexture function to bind the
- content to the currently bound texture. If this fail it will try and lock
- with SWReadAccess and then use the bindSWToTexture convenience function.
+ content to the currently bound texture, and if \a premultiplied is provided,
+ it is set to false.
- \a swizzle is suppose to be used by the caller to figure out if the Red and
+ If it fails, it will try to lock with SWReadAccess and then use the
+ bindSWToTexture convenience function. If \a premultiplied is provided, it is
+ passed to the bindSWToTexture() function.
+
+ \a swizzle is meant to be used by the caller to figure out if the Red and
Blue color channels need to be swizzled when rendering.
\a rect is the subrect which is desired to be bounded to the texture. This
- argument has a no less than semantic, meaning more (if not all) of the buffer
+ argument has a not less than semantic, meaning more (if not all) of the buffer
can be bounded to the texture. An empty QRect is interpreted as entire buffer
should be bound.
The user should use the AccessTypes returned by isLocked to figure out what
lock has been obtained.
- returns true if the buffer has successfully been bound to the currently
+ Returns true if the buffer has successfully been bound to the currently
bound texture, otherwise returns false.
*/
bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer,
@@ -103,26 +107,29 @@ bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer
}
/*!
- Convenience function that uploads the current raster content to the currently bound texture.
+ Convenience function that uploads the current raster content to the currently
+ bound texture.
- \a swizzleRandB is suppose to be used by the caller to figure out if the Red and
+ \a swizzleRandB is meant to be used by the caller to decide if the Red and
Blue color channels need to be swizzled when rendering. This is an
optimization. Qt often renders to software buffers interpreting pixels as
unsigned ints. When these buffers are uploaded to textures and each color
channel per pixel is interpreted as a byte (read sequentially), then the
- Red and Blue channels are swapped. Conveniently the Alpha buffer will be
- correct since Qt historically has had the alpha channel as the first
+ Red and Blue channels are swapped. Conveniently, the Alpha buffer will be
+ correct, since Qt historically has had the alpha channel as the first
channel, while OpenGL typically expects the alpha channel to be the last
channel.
- \a subRect is the subrect which is desired to be bounded to the texture. This
- argument has a no less than semantic, meaning more (if not all) of the buffer
- can be bounded to the texture. An empty QRect is interpreted as entire buffer
- should be bound.
+ \a subRect is the region to be bound to the texture. This argument has a
+ not less than semantic, meaning more (if not all) of the buffer can be
+ bound to the texture. An empty QRect is interpreted as meaning the entire
+ buffer should be bound.
- This function fails for buffers not capable of locking to SWAccess.
+ This function fails if the \a graphicsBuffer is not locked to SWAccess.
- Returns true on success, otherwise false.
+ Returns true on success, otherwise false. If \a premultipliedB is
+ provided, it is set according to what happens, if the function returns
+ true.
*/
bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer,
bool *swizzleRandB, bool *premultipliedB,
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index dfb8f60915..6e285a8fa5 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -99,8 +99,8 @@ QPlatformClipboard *QPlatformIntegration::clipboard() const
/*!
Accessor for the platform integration's drag object.
- Default implementation returns 0, implying no drag and drop support.
-
+ Default implementation returns QSimpleDrag. This class supports only drag
+ and drop operations within the same Qt application.
*/
QPlatformDrag *QPlatformIntegration::drag() const
{
diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h
index e3fa5c71b1..28c29a704c 100644
--- a/src/gui/kernel/qplatformmenu.h
+++ b/src/gui/kernel/qplatformmenu.h
@@ -158,6 +158,7 @@ public:
virtual void removeMenu(QPlatformMenu *menu) = 0;
virtual void syncMenu(QPlatformMenu *menuItem) = 0;
virtual void handleReparent(QWindow *newParentWindow) = 0;
+ virtual QWindow *parentWindow() const { return nullptr; }
virtual QPlatformMenu *menuForTag(quintptr tag) const = 0;
virtual QPlatformMenu *createMenu() const;
diff --git a/src/gui/kernel/qplatformsurface.cpp b/src/gui/kernel/qplatformsurface.cpp
index f091c04ebb..fdb2cf567d 100644
--- a/src/gui/kernel/qplatformsurface.cpp
+++ b/src/gui/kernel/qplatformsurface.cpp
@@ -38,6 +38,10 @@
****************************************************************************/
#include "qplatformsurface.h"
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#include <QtGui/qwindow.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -64,5 +68,26 @@ QPlatformSurface::QPlatformSurface(QSurface *surface) : m_surface(surface)
{
}
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QPlatformSurface *surface)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QPlatformSurface(" << (const void *)surface;
+ if (surface) {
+ QSurface *s = surface->surface();
+ auto surfaceClass = s->surfaceClass();
+ debug << ", class=" << surfaceClass;
+ debug << ", type=" << s->surfaceType();
+ if (surfaceClass == QSurface::Window)
+ debug << ", window=" << static_cast<QWindow *>(s);
+ else
+ debug << ", surface=" << s;
+ }
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformsurface.h b/src/gui/kernel/qplatformsurface.h
index 76e8767a05..4d8854fb40 100644
--- a/src/gui/kernel/qplatformsurface.h
+++ b/src/gui/kernel/qplatformsurface.h
@@ -58,6 +58,10 @@ QT_BEGIN_NAMESPACE
class QPlatformScreen;
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+#endif
+
class Q_GUI_EXPORT QPlatformSurface
{
public:
@@ -76,6 +80,11 @@ private:
friend class QPlatformOffscreenSurface;
};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QPlatformSurface *surface);
+#endif
+
QT_END_NAMESPACE
#endif //QPLATFORMSURFACE_H
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index a66420c364..e83f76fb06 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -340,6 +340,20 @@ void QPlatformWindow::setWindowFilePath(const QString &filePath) { Q_UNUSED(file
void QPlatformWindow::setWindowIcon(const QIcon &icon) { Q_UNUSED(icon); }
/*!
+ Reimplement to let the platform handle non-spontaneous window close.
+
+ When reimplementing make sure to call the base class implementation
+ or QWindowSystemInterface::handleCloseEvent(), which will prompt the
+ user to accept the window close (if needed) and then close the QWindow.
+*/
+bool QPlatformWindow::close()
+{
+ bool accepted = false;
+ QWindowSystemInterface::handleCloseEvent<QWindowSystemInterface::SynchronousDelivery>(window(), &accepted);
+ return accepted;
+}
+
+/*!
Reimplement to be able to let Qt raise windows to the top of the desktop
*/
void QPlatformWindow::raise() { qWarning("This plugin does not support raise()"); }
@@ -447,14 +461,26 @@ bool QPlatformWindow::setWindowModified(bool modified)
/*!
Reimplement this method to be able to do any platform specific event
- handling. All events for window() are passed to this function before being
- sent to QWindow::event().
+ handling. All non-synthetic events for window() are passed to this
+ function before being sent to QWindow::event().
- The default implementation is empty and does nothing with \a event.
+ Return true if the event should not be passed on to the QWindow.
+
+ Subclasses should always call the base class implementation.
*/
-void QPlatformWindow::windowEvent(QEvent *event)
+bool QPlatformWindow::windowEvent(QEvent *event)
{
- Q_UNUSED(event);
+ Q_D(QPlatformWindow);
+
+ if (event->type() == QEvent::Timer) {
+ if (static_cast<QTimerEvent *>(event)->timerId() == d->updateTimer.timerId()) {
+ d->updateTimer.stop();
+ deliverUpdateRequest();
+ return true;
+ }
+ }
+
+ return false;
}
/*!
@@ -710,7 +736,7 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w,
QPlatformWindow subclasses can re-implement this function to
provide display refresh synchronized updates. The event
- should be delivered using QWindowPrivate::deliverUpdateRequest()
+ should be delivered using QPlatformWindow::deliverUpdateRequest()
to not get out of sync with the the internal state of QWindow.
The default implementation posts an UpdateRequest event to the
@@ -720,18 +746,44 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w,
*/
void QPlatformWindow::requestUpdate()
{
- static int timeout = -1;
- if (timeout == -1) {
+ Q_D(QPlatformWindow);
+
+ static int updateInterval = []() {
bool ok = false;
- timeout = qEnvironmentVariableIntValue("QT_QPA_UPDATE_IDLE_TIME", &ok);
- if (!ok)
- timeout = 5;
- }
+ int customUpdateInterval = qEnvironmentVariableIntValue("QT_QPA_UPDATE_IDLE_TIME", &ok);
+ return ok ? customUpdateInterval : 5;
+ }();
+
+ Q_ASSERT(!d->updateTimer.isActive());
+ d->updateTimer.start(updateInterval, Qt::PreciseTimer, window());
+}
+
+/*!
+ Returns true if the window has a pending update request.
+
+ \sa requestUpdate(), deliverUpdateRequest()
+*/
+bool QPlatformWindow::hasPendingUpdateRequest() const
+{
+ return qt_window_private(window())->updateRequestPending;
+}
+
+/*!
+ Delivers an QEvent::UpdateRequest event to the window.
+
+ QPlatformWindow subclasses can re-implement this function to
+ provide e.g. logging or tracing of the delivery, but should
+ always call the base class function.
+*/
+void QPlatformWindow::deliverUpdateRequest()
+{
+ Q_ASSERT(hasPendingUpdateRequest());
QWindow *w = window();
- QWindowPrivate *wp = (QWindowPrivate *) QObjectPrivate::get(w);
- Q_ASSERT(wp->updateTimer == 0);
- wp->updateTimer = w->startTimer(timeout, Qt::PreciseTimer);
+ QWindowPrivate *wp = qt_window_private(w);
+ wp->updateRequestPending = false;
+ QEvent request(QEvent::UpdateRequest);
+ QCoreApplication::sendEvent(w, &request);
}
/*!
diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h
index 84dff681d5..1590a10554 100644
--- a/src/gui/kernel/qplatformwindow.h
+++ b/src/gui/kernel/qplatformwindow.h
@@ -100,6 +100,7 @@ public:
virtual void setWindowTitle(const QString &title);
virtual void setWindowFilePath(const QString &title);
virtual void setWindowIcon(const QIcon &icon);
+ virtual bool close();
virtual void raise();
virtual void lower();
@@ -126,7 +127,7 @@ public:
virtual bool setWindowModified(bool modified);
- virtual void windowEvent(QEvent *event);
+ virtual bool windowEvent(QEvent *event);
virtual bool startSystemResize(const QPoint &pos, Qt::Corner corner);
virtual bool startSystemMove(const QPoint &pos);
@@ -143,6 +144,8 @@ public:
const QRect &initialGeometry, int defaultWidth, int defaultHeight);
virtual void requestUpdate();
+ bool hasPendingUpdateRequest() const;
+ virtual void deliverUpdateRequest();
// Window property accessors. Platform plugins should use these
// instead of accessing QWindow directly.
diff --git a/src/gui/kernel/qplatformwindow_p.h b/src/gui/kernel/qplatformwindow_p.h
index 62ecd61d9e..00dae9334c 100644
--- a/src/gui/kernel/qplatformwindow_p.h
+++ b/src/gui/kernel/qplatformwindow_p.h
@@ -52,6 +52,7 @@
//
#include <QtGui/private/qtguiglobal_p.h>
+#include <QtCore/qbasictimer.h>
#include <QtCore/qrect.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,7 @@ class QPlatformWindowPrivate
{
public:
QRect rect;
+ QBasicTimer updateTimer;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp
index fa1eb6f6bf..3bb42c1c0b 100644
--- a/src/gui/kernel/qshortcutmap.cpp
+++ b/src/gui/kernel/qshortcutmap.cpp
@@ -540,6 +540,19 @@ void QShortcutMap::createNewSequences(QKeyEvent *e, QVector<QKeySequence> &ksl,
{
Q_D(QShortcutMap);
QList<int> possibleKeys = QKeyMapper::possibleKeys(e);
+#if defined(DEBUG_QSHORTCUTMAP)
+ {
+ QDebug debug = qDebug().nospace();
+ debug << __FUNCTION__ << '(' << e << ", ignoredModifiers="
+ << Qt::KeyboardModifiers(ignoredModifiers) << "), possibleKeys=(";
+ for (int i = 0, size = possibleKeys.size(); i < size; ++i) {
+ if (i)
+ debug << ", ";
+ debug << QKeySequence(possibleKeys.at(i));
+ }
+ debug << ')';
+ }
+#endif // DEBUG_QSHORTCUTMAP
int pkTotal = possibleKeys.count();
if (!pkTotal)
return;
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index 12e204a09f..a84f873437 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -94,11 +94,7 @@ static QWindow* topLevelAt(const QPoint &pos)
(within the Qt application or outside) accepts the drag and sets the state accordingly.
*/
-QBasicDrag::QBasicDrag() :
- m_current_window(nullptr), m_restoreCursor(false), m_eventLoop(nullptr),
- m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false),
- m_drag(nullptr), m_drag_icon_window(nullptr), m_useCompositing(true),
- m_screen(nullptr)
+QBasicDrag::QBasicDrag()
{
}
@@ -158,7 +154,8 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
case QEvent::MouseMove:
{
QPoint nativePosition = getNativeMousePos(e, m_drag_icon_window);
- move(nativePosition);
+ auto mouseMove = static_cast<QMouseEvent *>(e);
+ move(nativePosition, mouseMove->buttons(), mouseMove->modifiers());
return true; // Eat all mouse move events
}
case QEvent::MouseButtonRelease:
@@ -166,7 +163,8 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
disableEventFilter();
if (canDrop()) {
QPoint nativePosition = getNativeMousePos(e, m_drag_icon_window);
- drop(nativePosition);
+ auto mouseRelease = static_cast<QMouseEvent *>(e);
+ drop(nativePosition, mouseRelease->buttons(), mouseRelease->modifiers());
} else {
cancel();
}
@@ -179,9 +177,9 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
// make the event relative to the window where the drag started. (QTBUG-66103)
const QMouseEvent *release = static_cast<QMouseEvent *>(e);
const QWindow *releaseWindow = topLevelAt(release->globalPos());
- qCDebug(lcDnd) << "mouse released over" << releaseWindow << "after drag from" << m_current_window << "globalPos" << release->globalPos();
+ qCDebug(lcDnd) << "mouse released over" << releaseWindow << "after drag from" << m_sourceWindow << "globalPos" << release->globalPos();
if (!releaseWindow)
- releaseWindow = m_current_window;
+ releaseWindow = m_sourceWindow;
QPoint releaseWindowPos = (releaseWindow ? releaseWindow->mapFromGlobal(release->globalPos()) : release->globalPos());
QMouseEvent *newRelease = new QMouseEvent(release->type(),
releaseWindowPos, releaseWindowPos, release->screenPos(),
@@ -204,18 +202,15 @@ Qt::DropAction QBasicDrag::drag(QDrag *o)
m_drag = o;
m_executed_drop_action = Qt::IgnoreAction;
m_can_drop = false;
- m_restoreCursor = true;
-#ifndef QT_NO_CURSOR
- qApp->setOverrideCursor(Qt::DragCopyCursor);
- updateCursor(m_executed_drop_action);
-#endif
+
startDrag();
m_eventLoop = new QEventLoop;
m_eventLoop->exec();
delete m_eventLoop;
- m_eventLoop = 0;
- m_drag = 0;
+ m_eventLoop = nullptr;
+ m_drag = nullptr;
endDrag();
+
return m_executed_drop_action;
}
@@ -227,16 +222,6 @@ void QBasicDrag::cancelDrag()
}
}
-void QBasicDrag::restoreCursor()
-{
- if (m_restoreCursor) {
-#ifndef QT_NO_CURSOR
- QGuiApplication::restoreOverrideCursor();
-#endif
- m_restoreCursor = false;
- }
-}
-
void QBasicDrag::startDrag()
{
QPoint pos;
@@ -287,7 +272,7 @@ void QBasicDrag::moveShapedPixmapWindow(const QPoint &globalPos)
m_drag_icon_window->updateGeometry(globalPos);
}
-void QBasicDrag::drop(const QPoint &)
+void QBasicDrag::drop(const QPoint &, Qt::MouseButtons, Qt::KeyboardModifiers)
{
disableEventFilter();
restoreCursor();
@@ -318,25 +303,34 @@ void QBasicDrag::updateCursor(Qt::DropAction action)
}
}
- QCursor *cursor = QGuiApplication::overrideCursor();
QPixmap pixmap = m_drag->dragCursor(action);
- if (!cursor) {
- QGuiApplication::changeOverrideCursor((pixmap.isNull()) ? QCursor(cursorShape) : QCursor(pixmap));
+
+ if (!m_dndHasSetOverrideCursor) {
+ QCursor newCursor = !pixmap.isNull() ? QCursor(pixmap) : QCursor(cursorShape);
+ QGuiApplication::setOverrideCursor(newCursor);
+ m_dndHasSetOverrideCursor = true;
} else {
+ QCursor *cursor = QGuiApplication::overrideCursor();
if (!pixmap.isNull()) {
- if ((cursor->pixmap().cacheKey() != pixmap.cacheKey())) {
+ if (cursor->pixmap().cacheKey() != pixmap.cacheKey())
QGuiApplication::changeOverrideCursor(QCursor(pixmap));
- }
- } else {
- if (cursorShape != cursor->shape()) {
- QGuiApplication::changeOverrideCursor(QCursor(cursorShape));
- }
+ } else if (cursorShape != cursor->shape()) {
+ QGuiApplication::changeOverrideCursor(QCursor(cursorShape));
}
}
#endif
updateAction(action);
}
+void QBasicDrag::restoreCursor()
+{
+#ifndef QT_NO_CURSOR
+ if (m_dndHasSetOverrideCursor) {
+ QGuiApplication::restoreOverrideCursor();
+ m_dndHasSetOverrideCursor = false;
+ }
+#endif
+}
static inline QPoint fromNativeGlobalPixels(const QPoint &point)
{
@@ -374,57 +368,83 @@ QSimpleDrag::QSimpleDrag()
void QSimpleDrag::startDrag()
{
+ setExecutedDropAction(Qt::IgnoreAction);
+
QBasicDrag::startDrag();
- m_current_window = topLevelAt(QCursor::pos());
- if (m_current_window) {
- QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_current_window, drag()->mimeData(), QHighDpi::toNativePixels(QCursor::pos(), m_current_window), drag()->supportedActions());
- setCanDrop(response.isAccepted());
- updateCursor(response.acceptedAction());
+ // Here we can be fairly sure that QGuiApplication::mouseButtons/keyboardModifiers() will
+ // contain sensible values as startDrag() normally is called from mouse event handlers
+ // by QDrag::exec(). A better API would be if we could pass something like "input device
+ // pointer" to QDrag::exec(). My guess is that something like that might be required for
+ // QTBUG-52430.
+ m_sourceWindow = topLevelAt(QCursor::pos());
+ m_windowUnderCursor = m_sourceWindow;
+ if (m_sourceWindow) {
+ auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), m_sourceWindow);
+ move(nativePixelPos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
} else {
setCanDrop(false);
updateCursor(Qt::IgnoreAction);
}
- setExecutedDropAction(Qt::IgnoreAction);
- qCDebug(lcDnd) << "drag began from" << m_current_window<< "cursor pos" << QCursor::pos() << "can drop?" << canDrop();
+
+ qCDebug(lcDnd) << "drag began from" << m_sourceWindow << "cursor pos" << QCursor::pos() << "can drop?" << canDrop();
+}
+
+static void sendDragLeave(QWindow *window)
+{
+ QWindowSystemInterface::handleDrag(window, nullptr, QPoint(), Qt::IgnoreAction, 0, 0);
}
void QSimpleDrag::cancel()
{
QBasicDrag::cancel();
- if (drag() && m_current_window) {
- QWindowSystemInterface::handleDrag(m_current_window, 0, QPoint(), Qt::IgnoreAction);
- m_current_window = 0;
+ if (drag() && m_sourceWindow) {
+ sendDragLeave(m_sourceWindow);
+ m_sourceWindow = nullptr;
}
}
-void QSimpleDrag::move(const QPoint &nativeGlobalPos)
+void QSimpleDrag::move(const QPoint &nativeGlobalPos, Qt::MouseButtons buttons,
+ Qt::KeyboardModifiers modifiers)
{
QPoint globalPos = fromNativeGlobalPixels(nativeGlobalPos);
moveShapedPixmapWindow(globalPos);
QWindow *window = topLevelAt(globalPos);
- if (!window)
- return;
+
+ if (!window || window != m_windowUnderCursor) {
+ if (m_windowUnderCursor)
+ sendDragLeave(m_windowUnderCursor);
+ m_windowUnderCursor = window;
+ if (!window) {
+ // QSimpleDrag supports only in-process dnd, we can't drop anywhere else.
+ setCanDrop(false);
+ updateCursor(Qt::IgnoreAction);
+ return;
+ }
+ }
const QPoint pos = nativeGlobalPos - window->handle()->geometry().topLeft();
- const QPlatformDragQtResponse qt_response =
- QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions());
+ const QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(
+ window, drag()->mimeData(), pos, drag()->supportedActions(),
+ buttons, modifiers);
- updateCursor(qt_response.acceptedAction());
setCanDrop(qt_response.isAccepted());
+ updateCursor(qt_response.acceptedAction());
}
-void QSimpleDrag::drop(const QPoint &nativeGlobalPos)
+void QSimpleDrag::drop(const QPoint &nativeGlobalPos, Qt::MouseButtons buttons,
+ Qt::KeyboardModifiers modifiers)
{
QPoint globalPos = fromNativeGlobalPixels(nativeGlobalPos);
- QBasicDrag::drop(nativeGlobalPos);
+ QBasicDrag::drop(nativeGlobalPos, buttons, modifiers);
QWindow *window = topLevelAt(globalPos);
if (!window)
return;
const QPoint pos = nativeGlobalPos - window->handle()->geometry().topLeft();
- const QPlatformDropQtResponse response =
- QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions());
+ const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(
+ window, drag()->mimeData(), pos, drag()->supportedActions(),
+ buttons, modifiers);
if (response.isAccepted()) {
setExecutedDropAction(response.acceptedAction());
} else {
diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h
index d980a3c49d..f9e8a83a39 100644
--- a/src/gui/kernel/qsimpledrag_p.h
+++ b/src/gui/kernel/qsimpledrag_p.h
@@ -55,13 +55,14 @@
#include <qpa/qplatformdrag.h>
#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtGui/QWindow>
QT_REQUIRE_CONFIG(draganddrop);
QT_BEGIN_NAMESPACE
class QMouseEvent;
-class QWindow;
class QEventLoop;
class QDropData;
class QShapedPixmapWindow;
@@ -82,8 +83,8 @@ protected:
virtual void startDrag();
virtual void cancel();
- virtual void move(const QPoint &globalPos) = 0;
- virtual void drop(const QPoint &globalPos) = 0;
+ virtual void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) = 0;
+ virtual void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) = 0;
virtual void endDrag();
@@ -106,7 +107,8 @@ protected:
QDrag *drag() const { return m_drag; }
protected:
- QWindow *m_current_window;
+ QWindow *m_sourceWindow = nullptr;
+ QPointer<QWindow> m_windowUnderCursor = nullptr;
private:
void enableEventFilter();
@@ -114,14 +116,16 @@ private:
void restoreCursor();
void exitDndEventLoop();
- bool m_restoreCursor;
- QEventLoop *m_eventLoop;
- Qt::DropAction m_executed_drop_action;
- bool m_can_drop;
- QDrag *m_drag;
- QShapedPixmapWindow *m_drag_icon_window;
- bool m_useCompositing;
- QScreen *m_screen;
+#ifndef QT_NO_CURSOR
+ bool m_dndHasSetOverrideCursor = false;
+#endif
+ QEventLoop *m_eventLoop = nullptr;
+ Qt::DropAction m_executed_drop_action = Qt::IgnoreAction;
+ bool m_can_drop = false;
+ QDrag *m_drag = nullptr;
+ QShapedPixmapWindow *m_drag_icon_window = nullptr;
+ bool m_useCompositing = true;
+ QScreen *m_screen = nullptr;
};
class Q_GUI_EXPORT QSimpleDrag : public QBasicDrag
@@ -132,8 +136,8 @@ public:
protected:
virtual void startDrag() override;
virtual void cancel() override;
- virtual void move(const QPoint &globalPos) override;
- virtual void drop(const QPoint &globalPos) override;
+ virtual void move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
+ virtual void drop(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardModifiers mods) override;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp
index 63651ee822..415e64b39c 100644
--- a/src/gui/kernel/qsurface.cpp
+++ b/src/gui/kernel/qsurface.cpp
@@ -80,6 +80,10 @@ QT_BEGIN_NAMESPACE
in conjunction with OpenVG contexts.
\value VulkanSurface The surface is a Vulkan compatible surface and can be used
in conjunction with the Vulkan graphics API.
+ \value MetalSurface The surface is a Metal compatible surface and can be used
+ in conjunction with Apple's Metal graphics API. This surface type is supported
+ on macOS only.
+
*/
diff --git a/src/gui/kernel/qsurface.h b/src/gui/kernel/qsurface.h
index 7e09449d12..521593ea5c 100644
--- a/src/gui/kernel/qsurface.h
+++ b/src/gui/kernel/qsurface.h
@@ -55,19 +55,23 @@ class QSurfacePrivate;
class Q_GUI_EXPORT QSurface
{
+ Q_GADGET
public:
enum SurfaceClass {
Window,
Offscreen
};
+ Q_ENUM(SurfaceClass)
enum SurfaceType {
RasterSurface,
OpenGLSurface,
RasterGLSurface,
OpenVGSurface,
- VulkanSurface
+ VulkanSurface,
+ MetalSurface
};
+ Q_ENUM(SurfaceType)
virtual ~QSurface();
diff --git a/src/gui/kernel/qtestsupport_gui.cpp b/src/gui/kernel/qtestsupport_gui.cpp
new file mode 100644
index 0000000000..56e0eb52b3
--- /dev/null
+++ b/src/gui/kernel/qtestsupport_gui.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtestsupport_gui.h"
+#include "qwindow.h"
+
+#include <QtCore/qtestsupport_core.h>
+
+QT_BEGIN_NAMESPACE
+
+/*! \fn bool qWaitForWindowActive(QWindow *window, int timeout)
+ \relates QTest
+ \since 5.0
+
+ Waits for \a timeout milliseconds or until the \a window is active.
+
+ Returns \c true if \c window is active within \a timeout milliseconds, otherwise returns \c false.
+
+ \sa QTest::qWaitForWindowExposed(), QWindow::isActive()
+*/
+Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
+{
+ return QTest::qWaitFor([&]() { return window->isActive(); }, timeout);
+}
+
+/*! \fn bool qWaitForWindowExposed(QWindow *window, int timeout)
+ \relates QTest
+ \since 5.0
+
+ Waits for \a timeout milliseconds or until the \a window is exposed.
+ Returns \c true if \c window is exposed within \a timeout milliseconds, otherwise returns \c false.
+
+ This is mainly useful for asynchronous systems like X11, where a window will be mapped to screen some
+ time after being asked to show itself on the screen.
+
+ Note that a window that is mapped to screen may still not be considered exposed if the window client
+ area is completely covered by other windows, or if the window is otherwise not visible. This function
+ will then time out when waiting for such a window.
+
+ \sa QTest::qWaitForWindowActive(), QWindow::isExposed()
+*/
+Q_GUI_EXPORT bool QTest::qWaitForWindowExposed(QWindow *window, int timeout)
+{
+ return QTest::qWaitFor([&]() { return window->isExposed(); }, timeout);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qtestsupport_gui.h b/src/gui/kernel/qtestsupport_gui.h
new file mode 100644
index 0000000000..82a81e9214
--- /dev/null
+++ b/src/gui/kernel/qtestsupport_gui.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTSUPPORT_GUI_H
+#define QTESTSUPPORT_GUI_H
+
+#include <QtGui/qtguiglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+
+namespace QTest {
+Q_GUI_EXPORT Q_REQUIRED_RESULT bool qWaitForWindowActive(QWindow *window, int timeout = 5000);
+Q_GUI_EXPORT Q_REQUIRED_RESULT bool qWaitForWindowExposed(QWindow *window, int timeout = 5000);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 55fe75d220..3d7d22959d 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -115,9 +115,10 @@ QT_BEGIN_NAMESPACE
physical area of the screen. On windowing systems that have exposure
notifications, the isExposed() accessor describes whether the window should
be treated as directly visible on screen. The exposeEvent() function is
- called whenever the windows exposure in the windowing system changes. On
- windowing systems that do not make this information visible to the
- application, isExposed() will simply return the same value as isVisible().
+ called whenever an area of the window is invalidated, for example due to the
+ exposure in the windowing system changing. On windowing systems that do not
+ make this information visible to the application, isExposed() will simply
+ return the same value as isVisible().
QWindow::Visibility queried through visibility() is a convenience API
combining the functions of visible() and windowStates().
@@ -2150,15 +2151,13 @@ bool QWindow::close()
if (!d->platformWindow)
return true;
- bool accepted = false;
- QWindowSystemInterface::handleCloseEvent(this, &accepted);
- QWindowSystemInterface::flushWindowSystemEvents();
- return accepted;
+ return d->platformWindow->close();
}
/*!
- The expose event (\a ev) is sent by the window system whenever the window's
- exposure on screen changes.
+ The expose event (\a ev) is sent by the window system whenever an area of
+ the window is invalidated, for example due to the exposure in the windowing
+ system changing.
The application can start rendering into the window with QBackingStore
and QOpenGLContext as soon as it gets an exposeEvent() such that
@@ -2335,18 +2334,6 @@ bool QWindow::event(QEvent *ev)
break;
#endif
- case QEvent::Timer: {
- Q_D(QWindow);
- if (static_cast<QTimerEvent *>(ev)->timerId() == d->updateTimer) {
- killTimer(d->updateTimer);
- d->updateTimer = 0;
- d->deliverUpdateRequest();
- } else {
- QObject::event(ev);
- }
- break;
- }
-
case QEvent::PlatformSurface: {
if ((static_cast<QPlatformSurfaceEvent *>(ev))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
#ifndef QT_NO_OPENGL
@@ -2364,14 +2351,6 @@ bool QWindow::event(QEvent *ev)
return true;
}
-void QWindowPrivate::deliverUpdateRequest()
-{
- Q_Q(QWindow);
- updateRequestPending = false;
- QEvent request(QEvent::UpdateRequest);
- QCoreApplication::sendEvent(q, &request);
-}
-
/*!
Schedules a QEvent::UpdateRequest event to be delivered to this window.
@@ -2626,14 +2605,14 @@ void QWindowPrivate::maybeQuitOnLastWindowClosed()
}
}
-QWindow *QWindowPrivate::topLevelWindow() const
+QWindow *QWindowPrivate::topLevelWindow(QWindow::AncestorMode mode) const
{
Q_Q(const QWindow);
QWindow *window = const_cast<QWindow *>(q);
while (window) {
- QWindow *parent = window->parent(QWindow::IncludeTransients);
+ QWindow *parent = window->parent(mode);
if (!parent)
break;
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index 7ef73eb410..bf5e645114 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -97,7 +97,6 @@ public:
, modality(Qt::NonModal)
, blockedByModalWindow(false)
, updateRequestPending(false)
- , updateTimer(0)
, transientParent(0)
, topLevelScreen(0)
#ifndef QT_NO_CURSOR
@@ -124,11 +123,9 @@ public:
bool applyCursor();
#endif
- void deliverUpdateRequest();
-
QPoint globalPosition() const;
- QWindow *topLevelWindow() const;
+ QWindow *topLevelWindow(QWindow::AncestorMode mode = QWindow::IncludeTransients) const;
#if QT_CONFIG(opengl)
virtual QOpenGLContext *shareContext() const;
@@ -194,7 +191,6 @@ public:
bool blockedByModalWindow;
bool updateRequestPending;
- int updateTimer;
QPointer<QWindow> transientParent;
QPointer<QScreen> topLevelScreen;
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 6edcdfc255..07ece5689e 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -339,12 +339,12 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleExposeEvent, QWindow *window, const QReg
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-void QWindowSystemInterface::handleCloseEvent(QWindow *window, bool *accepted)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleCloseEvent, QWindow *window, bool *accepted)
{
if (window) {
QWindowSystemInterfacePrivate::CloseEvent *e =
new QWindowSystemInterfacePrivate::CloseEvent(window, accepted);
- QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
+ QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
}
@@ -795,14 +795,44 @@ void QWindowSystemInterface::handleThemeChange(QWindow *window)
}
#if QT_CONFIG(draganddrop)
-QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+#if QT_DEPRECATED_SINCE(5, 11)
+QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions)
+{
+ return QGuiApplicationPrivate::processDrag(window, dropData, p, supportedActions,
+ QGuiApplication::mouseButtons(),
+ QGuiApplication::keyboardModifiers());
+}
+
+QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions)
+{
+ return QGuiApplicationPrivate::processDrop(window, dropData, p, supportedActions,
+ QGuiApplication::mouseButtons(),
+ QGuiApplication::keyboardModifiers());
+}
+#endif // QT_DEPRECATED_SINCE(5, 11)
+/*!
+ Drag and drop events are sent immediately.
+
+ ### FIXME? Perhaps DnD API should add some convenience APIs that are more
+ intuitive for the possible DND operations. Here passing nullptr as drop data is used to
+ indicate that drop was canceled and QDragLeaveEvent should be sent as a result.
+*/
+QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
{
- return QGuiApplicationPrivate::processDrag(window, dropData, QHighDpi::fromNativeLocalPosition(p, window) ,supportedActions);
+ auto pos = QHighDpi::fromNativeLocalPosition(p, window);
+ return QGuiApplicationPrivate::processDrag(window, dropData, pos, supportedActions, buttons, modifiers);
}
-QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions)
+QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
{
- return QGuiApplicationPrivate::processDrop(window, dropData, QHighDpi::fromNativeLocalPosition(p, window),supportedActions);
+ auto pos = QHighDpi::fromNativeLocalPosition(p, window);
+ return QGuiApplicationPrivate::processDrop(window, dropData, pos, supportedActions, buttons, modifiers);
}
#endif // QT_CONFIG(draganddrop)
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index bba0b05c5a..6bf6ee645c 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -193,6 +193,7 @@ public:
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleExposeEvent(QWindow *window, const QRegion &region);
+ template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleCloseEvent(QWindow *window, bool *accepted = nullptr);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
@@ -215,10 +216,19 @@ public:
static void handleApplicationStateChanged(Qt::ApplicationState newState, bool forcePropagate = false);
#if QT_CONFIG(draganddrop)
- // Drag and drop. These events are sent immediately.
- static QPlatformDragQtResponse handleDrag(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
- static QPlatformDropQtResponse handleDrop(QWindow *window, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions);
-#endif
+#if QT_DEPRECATED_SINCE(5, 11)
+ QT_DEPRECATED static QPlatformDragQtResponse handleDrag(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions);
+ QT_DEPRECATED static QPlatformDropQtResponse handleDrop(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions);
+#endif // #if QT_DEPRECATED_SINCE(5, 11)
+ static QPlatformDragQtResponse handleDrag(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
+ static QPlatformDropQtResponse handleDrop(QWindow *window, const QMimeData *dropData,
+ const QPoint &p, Qt::DropActions supportedActions,
+ Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers);
+#endif // QT_CONFIG(draganddrop)
static bool handleNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result);
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index c3fb19d21a..492f559f22 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -365,7 +365,7 @@ public:
QUrl url;
};
- class TabletEvent : public InputEvent {
+ class Q_GUI_EXPORT TabletEvent : public InputEvent {
public:
static void handleTabletEvent(QWindow *w, const QPointF &local, const QPointF &global,
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,