diff options
Diffstat (limited to 'src/gui/kernel')
67 files changed, 2410 insertions, 607 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index af6a417608..73a5a7b6ab 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -75,7 +75,9 @@ HEADERS += \ kernel/qplatformgraphicsbuffer.h \ kernel/qplatformgraphicsbufferhelper.h \ kernel/qinputdevicemanager_p.h \ - kernel/qinputdevicemanager_p_p.h + kernel/qinputdevicemanager_p_p.h \ + kernel/qhighdpiscaling_p.h + SOURCES += \ kernel/qgenericpluginfactory.cpp \ @@ -131,7 +133,9 @@ SOURCES += \ kernel/qrasterwindow.cpp \ kernel/qplatformgraphicsbuffer.cpp \ kernel/qplatformgraphicsbufferhelper.cpp \ - kernel/qinputdevicemanager.cpp + kernel/qinputdevicemanager.cpp \ + kernel/qhighdpiscaling.cpp + contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { HEADERS += \ diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 6b01952647..c25f3c2665 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -43,6 +43,7 @@ #include <qpa/qplatformcursor.h> #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -177,9 +178,14 @@ QT_BEGIN_NAMESPACE */ QPoint QCursor::pos(const QScreen *screen) { - if (screen) - if (const QPlatformCursor *cursor = screen->handle()->cursor()) - return cursor->pos(); + if (screen) { + if (const QPlatformCursor *cursor = screen->handle()->cursor()) { + const QPlatformScreen *ps = screen->handle(); + QPoint nativePos = cursor->pos(); + ps = ps->screenForPosition(nativePos); + return QHighDpi::fromNativePixels(nativePos, ps->screen()); + } + } return QGuiApplicationPrivate::lastCursorPosition.toPoint(); } @@ -231,12 +237,12 @@ void QCursor::setPos(QScreen *screen, int x, int y) { if (screen) { if (QPlatformCursor *cursor = screen->handle()->cursor()) { - const QPoint pos = QPoint(x, y); + const QPoint devicePos = QHighDpi::toNativePixels(QPoint(x, y), screen); // Need to check, since some X servers generate null mouse move // events, causing looping in applications which call setPos() on // every mouse move event. - if (pos != cursor->pos()) - cursor->setPos(pos); + if (devicePos != cursor->pos()) + cursor->setPos(devicePos); } } } diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp index 3ce8ab95ec..b05da1bfd0 100644 --- a/src/gui/kernel/qdnd.cpp +++ b/src/gui/kernel/qdnd.cpp @@ -147,7 +147,9 @@ static QStringList imageReadMimeFormats() { QStringList formats; QList<QByteArray> imageFormats = QImageReader::supportedImageFormats(); - for (int i = 0; i < imageFormats.size(); ++i) { + const int numImageFormats = imageFormats.size(); + formats.reserve(numImageFormats); + for (int i = 0; i < numImageFormats; ++i) { QString format = QLatin1String("image/"); format += QString::fromLatin1(imageFormats.at(i).toLower()); formats.append(format); @@ -166,7 +168,9 @@ static QStringList imageWriteMimeFormats() { QStringList formats; QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats(); - for (int i = 0; i < imageFormats.size(); ++i) { + const int numImageFormats = imageFormats.size(); + formats.reserve(numImageFormats); + for (int i = 0; i < numImageFormats; ++i) { QString format = QLatin1String("image/"); format += QString::fromLatin1(imageFormats.at(i).toLower()); formats.append(format); diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index c231c47576..2ca17692db 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -171,6 +171,8 @@ QInputEvent::~QInputEvent() \fn ulong QInputEvent::timestamp() const Returns the window system's timestamp for this event. + It will normally be in milliseconds since some arbitrary point + in time, such as the time when the system was started. */ /*! \fn void QInputEvent::setTimestamp(ulong atimestamp) @@ -309,6 +311,36 @@ QMouseEvent::QMouseEvent(Type type, const QPointF &localPos, const QPointF &wind {} /*! + \since 5.6 + + Constructs a mouse event object. + + The \a type parameter must be QEvent::MouseButtonPress, + QEvent::MouseButtonRelease, QEvent::MouseButtonDblClick, + or QEvent::MouseMove. + + The points \a localPos, \a windowPos and \a screenPos specify the + mouse cursor's position relative to the receiving widget or item, + window, and screen, respectively. + + The \a button that caused the event is given as a value from the + \l Qt::MouseButton enum. If the event \a type is \l MouseMove, + the appropriate button for this event is Qt::NoButton. \a buttons + is the state of all buttons at the time of the event, \a modifiers + is the state of all keyboard modifiers. + + The source of the event is specified by \a source. + +*/ +QMouseEvent::QMouseEvent(QEvent::Type type, const QPointF &localPos, const QPointF &windowPos, const QPointF &screenPos, + Qt::MouseButton button, Qt::MouseButtons buttons, + Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source) + : QInputEvent(type, modifiers), l(localPos), w(windowPos), s(screenPos), b(button), mouseState(buttons), caps(0) +{ + QGuiApplicationPrivate::setMouseEventSource(this, source); +} + +/*! \internal */ QMouseEvent::~QMouseEvent() @@ -997,8 +1029,10 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, when keys are pressed or released. A key event contains a special accept flag that indicates whether - the receiver will handle the key event. This flag is set by default, - so there is no need to call accept() when acting on a key event. + the receiver will handle the key event. This flag is set by default + for QEvent::KeyPress and QEvent::KeyRelease, so there is no need to + call accept() when acting on a key event. For QEvent::ShortcutOverride + the receiver needs to explicitly accept the event to trigger the override. Calling ignore() on a key event will propagate it to the parent widget. The event is propagated up the parent widget chain until a widget accepts it or an event filter consumes it. @@ -1033,6 +1067,8 @@ QKeyEvent::QKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, const nScanCode(0), nVirtualKey(0), nModifiers(0), c(count), autor(autorep) { + if (type == QEvent::ShortcutOverride) + ignore(); } /*! @@ -1060,6 +1096,8 @@ QKeyEvent::QKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, nScanCode(nativeScanCode), nVirtualKey(nativeVirtualKey), nModifiers(nativeModifiers), c(count), autor(autorep) { + if (type == QEvent::ShortcutOverride) + ignore(); } @@ -1987,6 +2025,11 @@ QInputMethodEvent::QInputMethodEvent(const QInputMethodEvent &other) { } +QInputMethodEvent::~QInputMethodEvent() +{ + // must be empty until ### Qt 6 +} + /*! Sets the commit string to \a commitString. @@ -3374,6 +3417,21 @@ QShowEvent::~QShowEvent() It may be safely ignored. \note This class is currently supported for OS X only. + + \section1 OS X Example + + In order to trigger the event on OS X, the application must be configured + to let the OS know what kind of file(s) it should react on. + + For example, the following \c Info.plist file declares that the application + can act as a viewer for files with a PNG extension: + + \snippet qfileopenevent/Info.plist Custom Info.plist + + The following implementation of a QApplication subclass prints the path to + the file that was, for example, dropped on the Dock icon of the application. + + \snippet qfileopenevent/main.cpp QApplication subclass */ /*! diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index a1f32026ac..b90fce97e0 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -106,6 +106,9 @@ public: QMouseEvent(Type type, const QPointF &localPos, const QPointF &windowPos, const QPointF &screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers); + QMouseEvent(Type type, const QPointF &localPos, const QPointF &windowPos, const QPointF &screenPos, + Qt::MouseButton button, Qt::MouseButtons buttons, + Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source); ~QMouseEvent(); #ifndef QT_NO_INTEGER_EVENT_COORDINATES @@ -519,7 +522,7 @@ public: }; class Attribute { public: - Attribute(AttributeType t, int s, int l, QVariant val) : type(t), start(s), length(l), value(val) {} + Attribute(AttributeType t, int s, int l, QVariant val) : type(t), start(s), length(l), value(qMove(val)) {} AttributeType type; int start; @@ -528,6 +531,8 @@ public: }; QInputMethodEvent(); QInputMethodEvent(const QString &preeditText, const QList<Attribute> &attributes); + ~QInputMethodEvent(); + void setCommitString(const QString &commitString, int replaceFrom = 0, int replaceLength = 0); inline const QList<Attribute> &attributes() const { return attrs; } inline const QString &preeditString() const { return preedit; } @@ -694,7 +699,7 @@ class Q_GUI_EXPORT QActionEvent : public QEvent { QAction *act, *bef; public: - QActionEvent(int type, QAction *action, QAction *before = 0); + QActionEvent(int type, QAction *action, QAction *before = Q_NULLPTR); ~QActionEvent(); inline QAction *action() const { return act; } @@ -871,9 +876,9 @@ public: #endif explicit QTouchEvent(QEvent::Type eventType, - QTouchDevice *device = 0, + QTouchDevice *device = Q_NULLPTR, Qt::KeyboardModifiers modifiers = Qt::NoModifier, - Qt::TouchPointStates touchPointStates = 0, + Qt::TouchPointStates touchPointStates = Qt::TouchPointStates(), const QList<QTouchEvent::TouchPoint> &touchPoints = QList<QTouchEvent::TouchPoint>()); ~QTouchEvent(); diff --git a/src/gui/kernel/qgenericplugin.h b/src/gui/kernel/qgenericplugin.h index cfab34d081..03c1df7fba 100644 --- a/src/gui/kernel/qgenericplugin.h +++ b/src/gui/kernel/qgenericplugin.h @@ -48,7 +48,7 @@ class Q_GUI_EXPORT QGenericPlugin : public QObject { Q_OBJECT public: - explicit QGenericPlugin(QObject *parent = 0); + explicit QGenericPlugin(QObject *parent = Q_NULLPTR); ~QGenericPlugin(); virtual QObject* create(const QString& name, const QString &spec) = 0; diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index c2b561aa93..0f015af2b9 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -99,6 +99,9 @@ #elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) # include <QtCore/qt_windows.h> # include <QtCore/QLibraryInfo> +# if defined(Q_OS_WINPHONE) +# include <Objbase.h> +# endif #endif // Q_OS_WIN && !Q_OS_WINCE #include <ctype.h> @@ -124,8 +127,12 @@ Qt::MouseButtons QGuiApplicationPrivate::tabletState = Qt::NoButton; QWindow *QGuiApplicationPrivate::tabletPressTarget = 0; QWindow *QGuiApplicationPrivate::currentMouseWindow = 0; +QString QGuiApplicationPrivate::styleOverride; + Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive; +bool QGuiApplicationPrivate::highDpiScalingUpdated = false; + QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0; QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0; @@ -156,7 +163,7 @@ int QGuiApplicationPrivate::mouse_double_click_distance = -1; QWindow *QGuiApplicationPrivate::currentMousePressWindow = 0; -static Qt::LayoutDirection layout_direction = Qt::LeftToRight; +static Qt::LayoutDirection layout_direction = Qt::LayoutDirectionAuto; static bool force_reverse = false; QGuiApplicationPrivate *QGuiApplicationPrivate::self = 0; @@ -185,9 +192,6 @@ extern void qRegisterGuiVariant(); #ifndef QT_NO_ANIMATION extern void qRegisterGuiGetInterpolator(); #endif -extern void qInitBlendFunctions(); -extern void qInitDrawhelperAsm(); -extern void qInitImageConversions(); static bool qt_detectRTLLanguage() { @@ -869,7 +873,7 @@ QWindowList QGuiApplication::topLevelWindows() if (!list.at(i)->parent() && list.at(i)->type() != Qt::Desktop) { // Top windows of embedded QAxServers do not have QWindow parents, // but they are not true top level windows, so do not include them. - const bool embedded = list.at(i)->handle() && list.at(i)->handle()->isEmbedded(0); + const bool embedded = list.at(i)->handle() && list.at(i)->handle()->isEmbedded(); if (!embedded) topLevelWindows.prepend(list.at(i)); } @@ -877,16 +881,6 @@ QWindowList QGuiApplication::topLevelWindows() return topLevelWindows; } -/*! - Returns the primary (or default) screen of the application, or null if there is none - - This will be the screen where QWindows are initially shown, unless otherwise specified. - - On some platforms, it may be null when there are actually no screens connected. - It is not possible to start a new QGuiApplication while there are no screens. - Applications which were running at the time the primary screen was removed - will stop rendering graphics until one or more screens are restored. -*/ QScreen *QGuiApplication::primaryScreen() { if (QGuiApplicationPrivate::screen_list.isEmpty()) @@ -908,7 +902,7 @@ QList<QScreen *> QGuiApplication::screens() This signal is emitted whenever a new screen \a screen has been added to the system. - \sa screens(), primaryScreen(), screenRemoved() + \sa screens(), primaryScreen, screenRemoved() */ /*! @@ -925,6 +919,23 @@ QList<QScreen *> QGuiApplication::screens() /*! + \property QGuiApplication::primaryScreen + + \brief the primary (or default) screen of the application, or null if there is none. + + This will be the screen where QWindows are initially shown, unless otherwise specified. + + On some platforms, it may be null when there are actually no screens connected. + It is not possible to start a new QGuiApplication while there are no screens. + Applications which were running at the time the primary screen was removed + will stop rendering graphics until one or more screens are restored. + + The primaryScreenChanged signal was introduced in Qt 5.6. + + \sa screens() +*/ + +/*! Returns the highest screen device pixel ratio found on the system. This is the ratio between physical pixels and device-independent pixels. @@ -955,16 +966,38 @@ qreal QGuiApplication::devicePixelRatio() const */ QWindow *QGuiApplication::topLevelAt(const QPoint &pos) { - QList<QScreen *> screens = QGuiApplication::screens(); - QList<QScreen *>::const_iterator screen = screens.constBegin(); - QList<QScreen *>::const_iterator end = screens.constEnd(); + const QList<QScreen *> screens = QGuiApplication::screens(); + if (!screens.isEmpty()) { + const QList<QScreen *> primaryScreens = screens.first()->virtualSiblings(); + QScreen *windowScreen = Q_NULLPTR; + + // Find the window on the primary virtual desktop first + foreach (QScreen *screen, primaryScreens) { + if (screen->geometry().contains(pos)) { + windowScreen = screen; + break; + } + } - while (screen != end) { - if ((*screen)->geometry().contains(pos)) - return (*screen)->handle()->topLevelAt(pos); - ++screen; + // If the window is not found on primary virtual desktop, find it on all screens + // except the first which was for sure in the previous loop. Some other screens + // may repeat. Find only when there is more than one virtual desktop. + if (!windowScreen && screens.count() != primaryScreens.count()) { + for (int i = 1; i < screens.size(); ++i) { + QScreen *screen = screens[i]; + if (screen->geometry().contains(pos)) { + windowScreen = screen; + break; + } + } + } + + if (windowScreen) { + const QPoint devicePosition = QHighDpi::toNativePixels(pos, windowScreen); + return windowScreen->handle()->topLevelAt(devicePosition); + } } - return 0; + return Q_NULLPTR; } /*! @@ -1041,6 +1074,13 @@ static void init_platform(const QString &pluginArgument, const QString &platform return; } + // Many platforms have created QScreens at this point. Finish initializing + // QHighDpiScaling to be prepared for early calls to qt_defaultDpi(). + if (QGuiApplication::primaryScreen()) { + QGuiApplicationPrivate::highDpiScalingUpdated = true; + QHighDpiScaling::updateHighDpiScaling(); + } + // Create the platform theme: // 1) Fetch the platform name from the environment if present. @@ -1117,6 +1157,9 @@ void QGuiApplicationPrivate::createPlatformIntegration() // this flag. QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); + + QHighDpiScaling::initHighDpiScaling(); + // Load the platform integration QString platformPluginPath = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH")); @@ -1206,6 +1249,11 @@ void QGuiApplicationPrivate::eventDispatcherReady() createPlatformIntegration(); platform_integration->initialize(); + + // All platforms should have added screens at this point. Finish + // QHighDpiScaling initialization if it has not been done so already. + if (!QGuiApplicationPrivate::highDpiScalingUpdated) + QHighDpiScaling::updateHighDpiScaling(); } void QGuiApplicationPrivate::init() @@ -1218,7 +1266,18 @@ void QGuiApplicationPrivate::init() #ifndef QT_NO_SESSIONMANAGER QString session_id; QString session_key; +# if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + wchar_t guidstr[40]; + GUID guid; + CoCreateGuid(&guid); + StringFromGUID2(guid, guidstr, 40); + session_id = QString::fromWCharArray(guidstr); + CoCreateGuid(&guid); + StringFromGUID2(guid, guidstr, 40); + session_key = QString::fromWCharArray(guidstr); +# endif #endif + QString s; int j = argc ? 1 : 0; for (int i=1; i<argc; i++) { if (argv[i] && *argv[i] != '-') { @@ -1233,7 +1292,6 @@ void QGuiApplicationPrivate::init() pluginList << argv[i]; } else if (arg == "-reverse") { force_reverse = true; - QGuiApplication::setLayoutDirection(Qt::RightToLeft); #ifdef Q_OS_MAC } else if (arg.startsWith("-psn_")) { // eat "-psn_xxxx" on Mac, which is passed when starting an app from Finder. @@ -1261,9 +1319,16 @@ void QGuiApplicationPrivate::init() #endif } else if (arg == "-testability") { loadTestability = true; + } else if (arg.indexOf("-style=", 0) != -1) { + s = QString::fromLocal8Bit(arg.right(arg.length() - 7).toLower()); + } else if (arg == "-style" && i < argc-1) { + s = QString::fromLocal8Bit(argv[++i]).toLower(); } else { argv[j++] = argv[i]; } + + if (!s.isEmpty()) + styleOverride = s; } if (j < argc) { @@ -1281,13 +1346,6 @@ void QGuiApplicationPrivate::init() if (platform_integration == 0) createPlatformIntegration(); - // Set up blend function tables. - qInitBlendFunctions(); - // Set up which span functions should be used in raster engine... - qInitDrawhelperAsm(); - // and QImage conversion functions - qInitImageConversions(); - initPalette(); QFont::initialize(); @@ -1330,6 +1388,9 @@ void QGuiApplicationPrivate::init() #endif #ifndef QT_NO_LIBRARY + if (qEnvironmentVariableIntValue("QT_LOAD_TESTABILITY") > 0) + loadTestability = true; + if (loadTestability) { QLibrary testLib(QStringLiteral("qttestability")); if (testLib.load()) { @@ -1344,7 +1405,12 @@ void QGuiApplicationPrivate::init() qCritical() << "Library qttestability load failed:" << testLib.errorString(); } } +#else + Q_UNUSED(loadTestability); #endif // QT_NO_LIBRARY + + if (layout_direction == Qt::LayoutDirectionAuto || force_reverse) + QGuiApplication::setLayoutDirection(qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight); } extern void qt_cleanupFontDatabase(); @@ -1693,12 +1759,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo // A mouse event should not change both position and buttons at the same time. Instead we // should first send a move event followed by a button changed event. Since this is not the case // with the current event, we split it in two. - QWindowSystemInterfacePrivate::MouseEvent *mouseButtonEvent = new QWindowSystemInterfacePrivate::MouseEvent( - e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers); + QWindowSystemInterfacePrivate::MouseEvent mouseButtonEvent( + e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers, e->source); if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic) - mouseButtonEvent->flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; - QWindowSystemInterfacePrivate::windowSystemEventQueue.prepend(mouseButtonEvent); - stateChange = Qt::NoButton; + mouseButtonEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; + e->buttons = buttons; + processMouseEvent(e); + processMouseEvent(&mouseButtonEvent); + return; } QWindow *window = e->window.data(); @@ -1767,17 +1835,23 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo if (!window) return; - QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers); - ev.setTimestamp(e->timestamp); - setMouseEventSource(&ev, e->source); #ifndef QT_NO_CURSOR if (!e->synthetic()) { if (const QScreen *screen = window->screen()) - if (QPlatformCursor *cursor = screen->handle()->cursor()) + if (QPlatformCursor *cursor = screen->handle()->cursor()) { + const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen); + const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen); + QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint, + button, buttons, e->modifiers, e->source); + ev.setTimestamp(e->timestamp); cursor->pointerEvent(ev); + } } #endif + QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers, e->source); + ev.setTimestamp(e->timestamp); + if (window->d_func()->blockedByModalWindow) { // a modal window is blocking this window, don't allow mouse events through return; @@ -1789,6 +1863,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } QGuiApplication::sendSpontaneousEvent(window, &ev); + e->eventAccepted = ev.isAccepted(); if (!e->synthetic() && !ev.isAccepted() && !frameStrut && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) { @@ -1817,7 +1892,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo points << point; QEvent::Type type; - QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); + QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, &type); QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers); fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; @@ -1828,9 +1903,8 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick; QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint, - button, buttons, e->modifiers); + button, buttons, e->modifiers, e->source); dblClickEvent.setTimestamp(e->timestamp); - setMouseEventSource(&dblClickEvent, e->source); QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent); } } @@ -1882,19 +1956,6 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE window = QGuiApplication::focusWindow(); } -#if !defined(Q_OS_OSX) - // On OS X the shortcut override is checked earlier, see: QWindowSystemInterface::handleKeyEvent() - const bool checkShortcut = e->keyType == QEvent::KeyPress && window != 0; - if (checkShortcut) { - QKeyEvent override(QEvent::ShortcutOverride, e->key, e->modifiers, - e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, - e->unicode, e->repeat, e->repeatCount); - override.setTimestamp(e->timestamp); - if (QWindowSystemInterface::tryHandleShortcutOverrideEvent(window, &override)) - return; - } -#endif // Q_OS_OSX - QKeyEvent ev(e->keyType, e->key, e->modifiers, e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount); @@ -1922,6 +1983,7 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE } } #endif + e->eventAccepted = ev.isAccepted(); } void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e) @@ -2030,10 +2092,17 @@ void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfa void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent *wse) { if (QWindow *window = wse->window.data()) { - if (QScreen *screen = wse->screen.data()) - window->d_func()->setTopLevelScreen(screen, false /* recreate */); - else // Fall back to default behavior, and try to find some appropriate screen - window->setScreen(0); + if (window->isTopLevel()) { + if (QScreen *screen = wse->screen.data()) + window->d_func()->setTopLevelScreen(screen, false /* recreate */); + else // Fall back to default behavior, and try to find some appropriate screen + window->setScreen(0); + } + // we may have changed scaling, so trigger resize event if needed + if (window->handle()) { + QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window), QRect()); + processGeometryChangeEvent(&gce); + } } } @@ -3201,7 +3270,10 @@ void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction) Qt::LayoutDirection QGuiApplication::layoutDirection() { - return layout_direction; + // layout_direction is only ever Qt::LayoutDirectionAuto if setLayoutDirection + // was never called, or called with Qt::LayoutDirectionAuto (which is a no-op). + // In that case we return the default LeftToRight. + return layout_direction == Qt::LayoutDirectionAuto ? Qt::LeftToRight : layout_direction; } /*! diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h index c89268d8d4..d995387d66 100644 --- a/src/gui/kernel/qguiapplication.h +++ b/src/gui/kernel/qguiapplication.h @@ -70,6 +70,7 @@ class Q_GUI_EXPORT QGuiApplication : public QCoreApplication Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged) Q_PROPERTY(QString platformName READ platformName STORED false) Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed WRITE setQuitOnLastWindowClosed) + Q_PROPERTY(QScreen *primaryScreen READ primaryScreen NOTIFY primaryScreenChanged STORED false) public: #ifdef Q_QDOC @@ -158,6 +159,7 @@ Q_SIGNALS: void fontDatabaseChanged(); void screenAdded(QScreen *screen); void screenRemoved(QScreen *screen); + void primaryScreenChanged(QScreen *screen); void lastWindowClosed(); void focusObjectChanged(QObject *focusObject); void focusWindowChanged(QWindow *focusWindow); diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 0559442049..7c7da9790b 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -202,6 +202,7 @@ public: static QWindow *currentMouseWindow; static QWindow *currentMousePressWindow; static Qt::ApplicationState applicationState; + static bool highDpiScalingUpdated; #ifndef QT_NO_CLIPBOARD static QClipboard *qt_clipboard; @@ -219,6 +220,7 @@ public: static QFont *app_font; + static QString styleOverride; static QStyleHints *styleHints; static bool obey_desktop_settings; QInputMethod *inputMethod; diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp index ce4a0ec09e..a0769ca671 100644 --- a/src/gui/kernel/qguivariant.cpp +++ b/src/gui/kernel/qguivariant.cpp @@ -175,7 +175,8 @@ static bool convert(const QVariant::Private *d, int t, switch (t) { case QVariant::ByteArray: if (d->type == QVariant::Color) { - *static_cast<QByteArray *>(result) = v_cast<QColor>(d)->name().toLatin1(); + const QColor *c = v_cast<QColor>(d); + *static_cast<QByteArray *>(result) = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb).toLatin1(); return true; } break; @@ -190,9 +191,11 @@ static bool convert(const QVariant::Private *d, int t, case QVariant::Font: *str = v_cast<QFont>(d)->toString(); return true; - case QVariant::Color: - *str = v_cast<QColor>(d)->name(); + case QVariant::Color: { + const QColor *c = v_cast<QColor>(d); + *str = c->name(c->alpha() != 255 ? QColor::HexArgb : QColor::HexRgb); return true; + } default: break; } diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp new file mode 100644 index 0000000000..b0ef2a284f --- /dev/null +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhighdpiscaling_p.h" +#include "qguiapplication.h" +#include "qscreen.h" +#include "qplatformintegration.h" +#include "private/qscreen_p.h" + +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcScaling, "qt.scaling"); + +#ifndef QT_NO_HIGHDPISCALING +static const char legacyDevicePixelEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; +static const char scaleFactorEnvVar[] = "QT_SCALE_FACTOR"; +static const char autoScreenEnvVar[] = "QT_AUTO_SCREEN_SCALE_FACTOR"; +static const char screenFactorsEnvVar[] = "QT_SCREEN_SCALE_FACTORS"; + +static inline qreal initialGlobalScaleFactor() +{ + + qreal result = 1; + if (qEnvironmentVariableIsSet(scaleFactorEnvVar)) { + bool ok; + const qreal f = qgetenv(scaleFactorEnvVar).toDouble(&ok); + if (ok && f > 0) { + qCDebug(lcScaling) << "Apply " << scaleFactorEnvVar << f; + result = f; + } + } else { + if (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar)) { + qWarning() << "Warning:" << legacyDevicePixelEnvVar << "is deprecated. Instead use:" << endl + << " " << autoScreenEnvVar << "to enable platform plugin controlled per-screen factors." << endl + << " " << screenFactorsEnvVar << "to set per-screen factors." << endl + << " " << scaleFactorEnvVar << "to set the application global scale factor."; + + int dpr = qEnvironmentVariableIntValue(legacyDevicePixelEnvVar); + if (dpr > 0) + result = dpr; + } + } + return result; +} + +/*! + \class QHighDpiScaling + \since 5.6 + \internal + \preliminary + \ingroup qpa + + \brief Collection of utility functions for UI scaling. + + QHighDpiScaling implements utility functions for high-dpi scaling for use + on operating systems that provide limited support for native scaling. In + addition this functionality can be used for simulation and testing purposes. + + The functions support scaling between the device independent coordinate + system used by Qt applications and the native coordinate system used by + the platform plugins. Intended usage locations are the low level / platform + plugin interfacing parts of QtGui, for example the QWindow, QScreen and + QWindowSystemInterface implementation. + + There are now up to three active coordinate systems in Qt: + + --------------------------------------------------- + | Application Device Independent Pixels | devicePixelRatio + | Qt Widgets | = + | Qt Gui | + |---------------------------------------------------| Qt Scale Factor + | Qt Gui QPlatform* Native Pixels | * + | Qt platform plugin | + |---------------------------------------------------| OS Scale Factor + | Display Device Pixels | + | (Graphics Buffers) | + ----------------------------------------------------- + + This is an simplification and shows the main coordinate system. All layers + may work with device pixels in specific cases: OpenGL, creating the backing + store, and QPixmap management. The "Native Pixels" coordinate system is + internal to Qt and should not be exposed to Qt users: Seen from the outside + there are only two coordinate systems: device independent pixels and device + pixels. + + The devicePixelRatio seen by applications is the product of the Qt scale + factor and the OS scale factor. The value of the scale factors may be 1, + in which case two or more of the coordinate systems are equivalent. Platforms + that (may) have an OS scale factor include OS X, iOS and Wayland. + + Note that the functions in this file do not work with the OS scale factor + directly and are limited to converting between device independent and native + pixels. The OS scale factor is accunted for by QWindow::devicePixelRatio() + and similar functions. + + Configuration Examples: + + 'Classic': Device Independent Pixels = Native Pixels = Device Pixels + --------------------------------------------------- devicePixelRatio: 1 + | Application / Qt Gui 100 x 100 | + | | Qt Scale Factor: 1 + | Qt Platform / OS 100 x 100 | + | | OS Scale Factor: 1 + | Display 100 x 100 | + ----------------------------------------------------- + + 'Retina Device': Device Independent Pixels = Native Pixels + --------------------------------------------------- devicePixelRatio: 2 + | Application / Qt Gui 100 x 100 | + | | Qt Scale Factor: 1 + | Qt Platform / OS 100 x 100 | + |---------------------------------------------------| OS Scale Factor: 2 + | Display 200 x 200 | + ----------------------------------------------------- + + '2x Qt Scaling': Native Pixels = Device Pixels + --------------------------------------------------- devicePixelRatio: 2 + | Application / Qt Gui 100 x 100 | + |---------------------------------------------------| Qt Scale Factor: 2 + | Qt Platform / OS 200 x 200 | + | | OS Scale Factor: 1 + | Display 200 x 200 | + ----------------------------------------------------- + + The Qt Scale Factor is the product of two sub-scale factors, which + are independently either set or determined by the platform plugin. + Several APIs are offered for this, targeting both developers and + end users. All scale factors are of type qreal. + + 1) A global scale factor + The QT_SCALE_FACTOR environment variable can be used to set + a global scale factor for all windows in the processs. This + is useful for testing and debugging (you can simulate any + devicePixelRatio without needing access to sepcial hardware), + and perhaps also for targeting a specific application to + a specific display type (embedded use cases). + + 2) A per-screen scale factors + Some platform plugins support providing a per-screen scale + factor based on display density information. These platforms + include X11, Windows, and Android. + + There are two APIs for enabling or disabling this behavior: + - The QT_AUTO_SCREEN_SCALE_FACTOR environment variable. + - The AA_EnableHighDpiScaling and AA_DisableHighDpiScaling + application attributes + + Enabling either will make QHighDpiScaling call QPlatformScreen::pixelDensity() + and use the value provided as the scale factor for the screen in + question. Disabling is done on a 'veto' basis where either the + environment or the application source can disable. The intended use + cases are 'My system is not providing correct display density + information' and 'My application needs to work in display pixels', + respectively. + + The QT_SCREEN_SCALE_FACTORS environment variable can be used to set the screen + scale factors manually.Set this to a semicolon-separated + list of scale factors (matching the order of QGuiApplications::screens()), + or to a list of name=value pairs (where name matches QScreen::name()). + + Coordinate conversion functions must be used when writing code that passes + geometry across the Qt Gui / Platform plugin boundary. The main conversion + functions are: + T toNativePixels(T, QWindow *) + T fromNativePixels(T, QWindow*) + + The following classes in QtGui use native pixels, for the convenience of the + plataform plugins: + QPlatformWindow + QPlatformScreen + QWindowSystemInterface (API only - Events are in device independent pixels) + + As a special consideration platform plugin code should be careful about + calling QtGui geometry accessor functions: + QRect r = window->geometry(); + Here the returned geometry is in device independent pixels. Add a conversion call: + QRect r = QHighDpi::toNativePixels(window->geometry()); + (Avoiding calling QWindow and instead using the QPlatformWindow geometry + might be a better course of action in this case.) +*/ + +qreal QHighDpiScaling::m_factor = 1.0; +bool QHighDpiScaling::m_active = false; //"overall active" - is there any scale factor set. +bool QHighDpiScaling::m_usePixelDensity = false; // use scale factor from platform plugin +bool QHighDpiScaling::m_pixelDensityScalingActive = false; // pixel density scale factor > 1 +bool QHighDpiScaling::m_globalScalingActive = false; // global scale factor is active +bool QHighDpiScaling::m_screenFactorSet = false; // QHighDpiScaling::setScreenFactor has been used +QDpi QHighDpiScaling::m_logicalDpi = QDpi(-1,-1); // The scaled logical DPI of the primary screen + +/* + Initializes the QHighDpiScaling global variables. Called before the + platform plugin is created. +*/ + +static inline bool usePixelDensity() +{ + // Determine if we should set a scale factor based on the pixel density + // reported by the platform plugin. There are several enablers and several + // disablers. A single disable may veto all other enablers. + if (QCoreApplication::testAttribute(Qt::AA_DisableHighDpiScaling)) + return false; + bool screenEnvValueOk; + const int screenEnvValue = qEnvironmentVariableIntValue(autoScreenEnvVar, &screenEnvValueOk); + if (screenEnvValueOk && screenEnvValue < 1) + return false; + return QCoreApplication::testAttribute(Qt::AA_EnableHighDpiScaling) + || (screenEnvValueOk && screenEnvValue > 0) + || (qEnvironmentVariableIsSet(legacyDevicePixelEnvVar) && qgetenv(legacyDevicePixelEnvVar).toLower() == "auto"); +} + +void QHighDpiScaling::initHighDpiScaling() +{ + // Determine if there is a global scale factor set. + m_factor = initialGlobalScaleFactor(); + m_globalScalingActive = !qFuzzyCompare(m_factor, qreal(1)); + + m_usePixelDensity = usePixelDensity(); + + m_pixelDensityScalingActive = false; //set in updateHighDpiScaling below + + // we update m_active in updateHighDpiScaling, but while we create the + // screens, we have to assume that m_usePixelDensity implies scaling + m_active = m_globalScalingActive || m_usePixelDensity; +} + +void QHighDpiScaling::updateHighDpiScaling() +{ + if (QCoreApplication::testAttribute(Qt::AA_DisableHighDpiScaling)) + return; + + if (m_usePixelDensity && !m_pixelDensityScalingActive) { + Q_FOREACH (QScreen *screen, QGuiApplication::screens()) { + if (!qFuzzyCompare(screenSubfactor(screen->handle()), qreal(1))) { + m_pixelDensityScalingActive = true; + break; + } + } + } + if (qEnvironmentVariableIsSet(screenFactorsEnvVar)) { + int i = 0; + Q_FOREACH (const QByteArray &spec, qgetenv(screenFactorsEnvVar).split(';')) { + QScreen *screen = 0; + int equalsPos = spec.lastIndexOf('='); + double factor = 0; + if (equalsPos > 0) { + // support "name=factor" + QByteArray name = spec.mid(0, equalsPos); + QByteArray f = spec.mid(equalsPos + 1); + bool ok; + factor = f.toDouble(&ok); + if (ok) { + Q_FOREACH (QScreen *s, QGuiApplication::screens()) { + if (s->name() == QString::fromLocal8Bit(name)) { + screen = s; + break; + } + } + } + } else { + // listing screens in order + bool ok; + factor = spec.toDouble(&ok); + if (ok && i < QGuiApplication::screens().count()) + screen = QGuiApplication::screens().at(i); + } + if (screen) + setScreenFactor(screen, factor); + ++i; + } + } + m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive; + + QPlatformScreen *primaryScreen = QGuiApplication::primaryScreen()->handle(); + qreal sf = screenSubfactor(primaryScreen); + QDpi primaryDpi = primaryScreen->logicalDpi(); + m_logicalDpi = QDpi(primaryDpi.first / sf, primaryDpi.second / sf); +} + +/* + Sets the global scale factor which is applied to all windows. +*/ +void QHighDpiScaling::setGlobalFactor(qreal factor) +{ + if (qFuzzyCompare(factor, m_factor)) + return; + if (!QGuiApplication::allWindows().isEmpty()) + qWarning("QHighDpiScaling::setFactor: Should only be called when no windows exist."); + + m_globalScalingActive = !qFuzzyCompare(factor, qreal(1)); + m_factor = m_globalScalingActive ? factor : qreal(1); + m_active = m_globalScalingActive || m_screenFactorSet || m_pixelDensityScalingActive; + Q_FOREACH (QScreen *screen, QGuiApplication::screens()) + screen->d_func()->updateHighDpi(); +} + +static const char scaleFactorProperty[] = "_q_scaleFactor"; + +/* + Sets a per-screen scale factor. +*/ +void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor) +{ + m_screenFactorSet = true; + m_active = true; + screen->setProperty(scaleFactorProperty, QVariant(factor)); + + // hack to force re-evaluation of screen geometry + if (screen->handle()) + screen->d_func()->setPlatformScreen(screen->handle()); // updates geometries based on scale factor +} + +QPoint QHighDpiScaling::mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen) +{ + if (!platformScreen) + return pos; + const qreal scaleFactor = factor(platformScreen); + const QPoint topLeft = platformScreen->geometry().topLeft(); + return (pos - topLeft) * scaleFactor + topLeft; +} + +QPoint QHighDpiScaling::mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen) +{ + if (!platformScreen) + return pos; + const qreal scaleFactor = factor(platformScreen); + const QPoint topLeft = platformScreen->geometry().topLeft(); + return (pos - topLeft) / scaleFactor + topLeft; +} + +qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen) +{ + qreal factor = qreal(1.0); + if (screen) { + if (m_usePixelDensity) + factor *= screen->pixelDensity(); + if (m_screenFactorSet) { + QVariant screenFactor = screen->screen()->property(scaleFactorProperty); + if (screenFactor.isValid()) + factor *= screenFactor.toReal(); + } + } + return factor; +} + +QDpi QHighDpiScaling::logicalDpi() +{ + return m_logicalDpi; +} + +qreal QHighDpiScaling::factor(const QScreen *screen) +{ + // Fast path for when scaling in Qt is not used at all. + if (!m_active) + return qreal(1.0); + + // The effective factor for a given screen is the product of the + // screen and global sub-factors + qreal factor = m_factor; + if (screen) + factor *= screenSubfactor(screen->handle()); + return factor; +} + +qreal QHighDpiScaling::factor(const QPlatformScreen *platformScreen) +{ + if (!m_active) + return qreal(1.0); + + return m_factor * screenSubfactor(platformScreen); +} + +qreal QHighDpiScaling::factor(const QWindow *window) +{ + if (!m_active) + return qreal(1.0); + + return factor(window ? window->screen() : QGuiApplication::primaryScreen()); +} + +QPoint QHighDpiScaling::origin(const QScreen *screen) +{ + return screen->geometry().topLeft(); +} + +QPoint QHighDpiScaling::origin(const QPlatformScreen *platformScreen) +{ + return platformScreen->geometry().topLeft(); +} + +#endif //QT_NO_HIGHDPISCALING +QT_END_NAMESPACE diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h new file mode 100644 index 0000000000..9e33787f53 --- /dev/null +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -0,0 +1,514 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHIGHDPISCALING_P_H +#define QHIGHDPISCALING_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qmargins.h> +#include <QtCore/qrect.h> +#include <QtCore/qvector.h> +#include <QtCore/qloggingcategory.h> +#include <QtGui/qregion.h> +#include <QtGui/qscreen.h> +#include <QtGui/qwindow.h> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcScaling); + +class QScreen; +class QPlatformScreen; +typedef QPair<qreal, qreal> QDpi; + +#ifndef QT_NO_HIGHDPISCALING +class Q_GUI_EXPORT QHighDpiScaling { +public: + static void initHighDpiScaling(); + static void updateHighDpiScaling(); + static void setGlobalFactor(qreal factor); + static void setScreenFactor(QScreen *window, qreal factor); + + static bool isActive() { return m_active; } + static qreal factor(const QWindow *window); + static qreal factor(const QScreen *screen); + static qreal factor(const QPlatformScreen *platformScreen); + static QPoint origin(const QScreen *screen); + static QPoint origin(const QPlatformScreen *platformScreen); + static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen); + static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen); + static QDpi logicalDpi(); + +private: + static qreal screenSubfactor(const QPlatformScreen *screen); + + static qreal m_factor; + static bool m_active; + static bool m_usePixelDensity; + static bool m_globalScalingActive; + static bool m_pixelDensityScalingActive; + static bool m_screenFactorSet; + static QDpi m_logicalDpi; +}; + +// Coordinate system conversion functions: +// QHighDpi::fromNativePixels : from physical(screen/backing) to logical pixels +// QHighDpi::toNativePixels : from logical to physical pixels + +namespace QHighDpi { + +inline QPointF fromNative(const QPointF &pos, qreal scaleFactor, const QPointF &origin) +{ + return (pos - origin) / scaleFactor + origin; +} + +inline QPointF toNative(const QPointF &pos, qreal scaleFactor, const QPointF &origin) +{ + return (pos - origin) * scaleFactor + origin; +} + +inline QPoint fromNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin) +{ + return (pos - origin) / scaleFactor + origin; +} + +inline QPoint toNative(const QPoint &pos, qreal scaleFactor, const QPoint &origin) +{ + return (pos - origin) * scaleFactor + origin; +} + +inline QPoint fromNative(const QPoint &pos, qreal scaleFactor) +{ + return pos / scaleFactor; +} + +inline QPoint toNative(const QPoint &pos, qreal scaleFactor) +{ + return pos * scaleFactor; +} + +inline QSize fromNative(const QSize &size, qreal scaleFactor) +{ + return size / scaleFactor; // TODO: should we round up? +} + +inline QSize toNative(const QSize &size, qreal scaleFactor) +{ + return size * scaleFactor; +} + +inline QSizeF fromNative(const QSizeF &size, qreal scaleFactor) +{ + return size / scaleFactor; +} + +inline QSizeF toNative(const QSizeF &size, qreal scaleFactor) +{ + return size * scaleFactor; +} + +inline QRect fromNative(const QRect &rect, qreal scaleFactor, const QPoint &origin) +{ + return QRect(fromNative(rect.topLeft(), scaleFactor, origin), fromNative(rect.size(), scaleFactor)); +} + +inline QRect toNative(const QRect &rect, qreal scaleFactor, const QPoint &origin) +{ + return QRect(toNative(rect.topLeft(), scaleFactor, origin), toNative(rect.size(), scaleFactor)); + +} + +inline QRect fromNative(const QRect &rect, const QScreen *screen, const QPoint &screenOrigin) +{ + return toNative(rect, QHighDpiScaling::factor(screen), screenOrigin); +} + +inline QRect fromNativeScreenGeometry(const QRect &nativeScreenGeometry, const QScreen *screen) +{ + return QRect(nativeScreenGeometry.topLeft(), + fromNative(nativeScreenGeometry.size(), QHighDpiScaling::factor(screen))); +} + +inline QPoint fromNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos / scaleFactor; +} + +inline QPoint toNativeLocalPosition(const QPoint &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos * scaleFactor; +} + +inline QPointF fromNativeLocalPosition(const QPointF &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos / scaleFactor; +} + +inline QPointF toNativeLocalPosition(const QPointF &pos, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return pos * scaleFactor; +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QPlatformScreen *platformScreen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); + const QPoint origin = QHighDpiScaling::origin(platformScreen); + return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QPlatformScreen *platformScreen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); + const QPoint origin = QHighDpiScaling::origin(platformScreen); + return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect fromNativePixels(const QRect &pixelRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return fromNativePixels(pixelRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRect(pixelRect.topLeft() / scaleFactor, fromNative(pixelRect.size(), scaleFactor)); + } +} + +inline QRectF toNativePixels(const QRectF &pointRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRectF(toNative(pointRect.topLeft(), scaleFactor, origin), + toNative(pointRect.size(), scaleFactor)); +} + +inline QRect toNativePixels(const QRect &pointRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return toNativePixels(pointRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRect(pointRect.topLeft() * scaleFactor, toNative(pointRect.size(), scaleFactor)); + } +} + +inline QRectF fromNativePixels(const QRectF &pixelRect, const QScreen *screen) +{ + const qreal scaleFactor = QHighDpiScaling::factor(screen); + const QPoint origin = QHighDpiScaling::origin(screen); + return QRectF(fromNative(pixelRect.topLeft(), scaleFactor, origin), + fromNative(pixelRect.size(), scaleFactor)); +} + +inline QRectF fromNativePixels(const QRectF &pixelRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return fromNativePixels(pixelRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRectF(pixelRect.topLeft() / scaleFactor, pixelRect.size() / scaleFactor); + } +} + +inline QRectF toNativePixels(const QRectF &pointRect, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) { + return toNativePixels(pointRect, window->screen()); + } else { + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QRectF(pointRect.topLeft() * scaleFactor, pointRect.size() * scaleFactor); + } +} + +inline QSize fromNativePixels(const QSize &pixelSize, const QWindow *window) +{ + return pixelSize / QHighDpiScaling::factor(window); +} + +inline QSize toNativePixels(const QSize &pointSize, const QWindow *window) +{ + return pointSize * QHighDpiScaling::factor(window); +} + +inline QSizeF fromNativePixels(const QSizeF &pixelSize, const QWindow *window) +{ + return pixelSize / QHighDpiScaling::factor(window); +} + +inline QSizeF toNativePixels(const QSizeF &pointSize, const QWindow *window) +{ + return pointSize * QHighDpiScaling::factor(window); +} + +inline QPoint fromNativePixels(const QPoint &pixelPoint, const QScreen *screen) +{ + return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPoint fromNativePixels(const QPoint &pixelPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return fromNativePixels(pixelPoint, window->screen()); + else + return pixelPoint / QHighDpiScaling::factor(window); +} + +inline QPoint toNativePixels(const QPoint &pointPoint, const QScreen *screen) +{ + return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPoint toNativePixels(const QPoint &pointPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return toNativePixels(pointPoint, window->screen()); + else + return pointPoint * QHighDpiScaling::factor(window); +} + +inline QPointF fromNativePixels(const QPointF &pixelPoint, const QScreen *screen) +{ + return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPointF fromNativePixels(const QPointF &pixelPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return fromNativePixels(pixelPoint, window->screen()); + else + return pixelPoint / QHighDpiScaling::factor(window); +} + +inline QPointF toNativePixels(const QPointF &pointPoint, const QScreen *screen) +{ + return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); +} + +inline QPointF toNativePixels(const QPointF &pointPoint, const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return toNativePixels(pointPoint, window->screen()); + else + return pointPoint * QHighDpiScaling::factor(window); +} + +inline QMargins fromNativePixels(const QMargins &pixelMargins, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QMargins(pixelMargins.left() / scaleFactor, pixelMargins.top() / scaleFactor, + pixelMargins.right() / scaleFactor, pixelMargins.bottom() / scaleFactor); +} + +inline QMargins toNativePixels(const QMargins &pointMargins, const QWindow *window) +{ + const qreal scaleFactor = QHighDpiScaling::factor(window); + return QMargins(pointMargins.left() * scaleFactor, pointMargins.top() * scaleFactor, + pointMargins.right() * scaleFactor, pointMargins.bottom() * scaleFactor); +} + +inline QRegion fromNativeLocalRegion(const QRegion &pixelRegion, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelRegion; + + qreal scaleFactor = QHighDpiScaling::factor(window); + QRegion pointRegion; + foreach (const QRect &rect, pixelRegion.rects()) { + pointRegion += QRect(fromNative(rect.topLeft(), scaleFactor), + fromNative(rect.size(), scaleFactor)); + } + return pointRegion; +} + +inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointRegion; + + qreal scaleFactor = QHighDpiScaling::factor(window); + QRegion pixelRegon; + foreach (const QRect &rect, pointRegion.rects()) { + pixelRegon += QRect(toNative(rect.topLeft(), scaleFactor), + toNative(rect.size(), scaleFactor)); + } + return pixelRegon; +} + +// Any T that has operator/() +template <typename T> +T fromNativePixels(const T &pixelValue, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelValue; + + return pixelValue / QHighDpiScaling::factor(window); + +} + + //##### ????? +template <typename T> +T fromNativePixels(const T &pixelValue, const QScreen *screen) +{ + if (!QHighDpiScaling::isActive()) + return pixelValue; + + return pixelValue / QHighDpiScaling::factor(screen); + +} + +// Any T that has operator*() +template <typename T> +T toNativePixels(const T &pointValue, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointValue; + + return pointValue * QHighDpiScaling::factor(window); +} + +template <typename T> +T toNativePixels(const T &pointValue, const QScreen *screen) +{ + if (!QHighDpiScaling::isActive()) + return pointValue; + + return pointValue * QHighDpiScaling::factor(screen); +} + + +// Any QVector<T> where T has operator/() +template <typename T> +QVector<T> fromNativePixels(const QVector<T> &pixelValues, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pixelValues; + + QVector<T> pointValues; + foreach (const T& pixelValue, pixelValues) + pointValues.append(pixelValue / QHighDpiScaling::factor(window)); + return pointValues; +} + +// Any QVector<T> where T has operator*() +template <typename T> +QVector<T> toNativePixels(const QVector<T> &pointValues, const QWindow *window) +{ + if (!QHighDpiScaling::isActive()) + return pointValues; + + QVector<T> pixelValues; + foreach (const T& pointValue, pointValues) + pixelValues.append(pointValue * QHighDpiScaling::factor(window)); + return pixelValues; +} + +} // namespace QHighDpi +#else // QT_NO_HIGHDPISCALING +class Q_GUI_EXPORT QHighDpiScaling { +public: + static inline void initHighDpiScaling() {} + static inline void updateHighDpiScaling() {} + static inline void setGlobalFactor(qreal) {} + static inline void setScreenFactor(QScreen *, qreal) {} + + static inline bool isActive() { return false; } + static inline qreal factor(const QWindow *) { return 1.0; } + static inline qreal factor(const QScreen *) { return 1.0; } + static inline qreal factor(const QPlatformScreen *) { return 1.0; } + static inline QPoint origin(const QScreen *) { return QPoint(); } + static inline QPoint origin(const QPlatformScreen *) { return QPoint(); } + static inline QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *) { return pos; } + static inline QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *) { return pos; } + static inline QDpi logicalDpi() { return QDpi(-1,-1); } +}; + +namespace QHighDpi { + template <typename T> inline + T toNative(const T &value, ...) { return value; } + template <typename T> inline + T fromNative(const T &value, ...) { return value; } + + template <typename T> inline + T fromNativeLocalPosition(const T &value, ...) { return value; } + template <typename T> inline + T toNativeLocalPosition(const T &value, ...) { return value; } + + template <typename T> inline + T fromNativeLocalRegion(const T &value, ...) { return value; } + template <typename T> inline + T toNativeLocalRegion(const T &value, ...) { return value; } + + template <typename T> inline + T fromNativeScreenGeometry(const T &value, ...) { return value; } + + template <typename T, typename U> inline + T toNativePixels(const T &value, const U*) {return value;} + template <typename T, typename U> inline + T fromNativePixels(const T &value, const U*) {return value;} +} +#endif // QT_NO_HIGHDPISCALING +QT_END_NAMESPACE + +#endif // QHIGHDPISCALING_P_H diff --git a/src/gui/kernel/qinputmethod.cpp b/src/gui/kernel/qinputmethod.cpp index 8d51be853a..2684c43518 100644 --- a/src/gui/kernel/qinputmethod.cpp +++ b/src/gui/kernel/qinputmethod.cpp @@ -147,6 +147,9 @@ QRectF QInputMethod::cursorRectangle() const /*! \property QInputMethod::keyboardRectangle \brief Virtual keyboard's geometry in window coordinates. + + This might be an empty rectangle if it is not possible to know the geometry + of the keyboard. This is the case for a floating keyboard on android. */ QRectF QInputMethod::keyboardRectangle() const { diff --git a/src/gui/kernel/qinputmethod.h b/src/gui/kernel/qinputmethod.h index 3e801bff3c..d7a7b1db8a 100644 --- a/src/gui/kernel/qinputmethod.h +++ b/src/gui/kernel/qinputmethod.h @@ -82,7 +82,7 @@ public: QLocale locale() const; Qt::LayoutDirection inputDirection() const; - static QVariant queryFocusObject(Qt::InputMethodQuery query, QVariant argument); + static QVariant queryFocusObject(Qt::InputMethodQuery query, QVariant argument); // ### Qt 6: QVariant by const-ref public Q_SLOTS: void show(); diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index 20dcbbc139..34003cdf41 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -50,7 +50,6 @@ #include <qlist.h> #include <qlocale.h> #include <qevent.h> -#include <qhash.h> QT_BEGIN_NAMESPACE diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 5bf22b9394..881d7cc76a 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -39,6 +39,7 @@ #ifndef QT_NO_SHORTCUT #include "qdebug.h" +#include <QtCore/qhashfunctions.h> #ifndef QT_NO_REGEXP # include "qregexp.h" #endif @@ -290,6 +291,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni \row \li InsertParagraphSeparator \li Enter \li Enter \li Enter \li Enter \row \li InsertLineSeparator \li Shift+Enter \li Meta+Enter, Meta+O \li Shift+Enter \li Shift+Enter \row \li Backspace \li (none) \li Meta+H \li (none) \li (none) + \row \li Cancel \li Escape \li Escape, Ctrl+. \li Escape \li Escape \endtable Note that, since the key sequences used for the standard shortcuts differ @@ -751,6 +753,7 @@ static const struct { \value ZoomIn Zoom in. \value ZoomOut Zoom out. \value FullScreen Toggle the window state to/from full screen. + \value Cancel Cancel the current operation. */ /*! @@ -818,6 +821,7 @@ QKeySequence::QKeySequence(const QString &key, QKeySequence::SequenceFormat form assign(key, format); } +Q_STATIC_ASSERT_X(QKeySequencePrivate::MaxKeyCount == 4, "Change docs and ctor impl below"); /*! Constructs a key sequence with up to 4 keys \a k1, \a k2, \a k3 and \a k4. @@ -876,26 +880,19 @@ QKeySequence::~QKeySequence() void QKeySequence::setKey(int key, int index) { - Q_ASSERT_X(index >= 0 && index < 4, "QKeySequence::setKey", "index out of range"); + Q_ASSERT_X(index >= 0 && index < QKeySequencePrivate::MaxKeyCount, "QKeySequence::setKey", "index out of range"); qAtomicDetach(d); d->key[index] = key; } +Q_STATIC_ASSERT_X(QKeySequencePrivate::MaxKeyCount == 4, "Change docs below"); /*! Returns the number of keys in the key sequence. The maximum is 4. */ int QKeySequence::count() const { - if (!d->key[0]) - return 0; - if (!d->key[1]) - return 1; - if (!d->key[2]) - return 2; - if (!d->key[3]) - return 3; - return 4; + return int(std::distance(d->key, std::find(d->key, d->key + QKeySequencePrivate::MaxKeyCount, 0))); } @@ -987,8 +984,8 @@ int QKeySequence::assign(const QString &ks, QKeySequence::SequenceFormat format) int p = 0, diff = 0; // Run through the whole string, but stop - // if we have 4 keys before the end. - while (keyseq.length() && n < 4) { + // if we have MaxKeyCount keys before the end. + while (keyseq.length() && n < QKeySequencePrivate::MaxKeyCount) { // We MUST use something to separate each sequence, and space // does not cut it, since some of the key names have space // in them.. (Let's hope no one translate with a comma in it:) @@ -1022,9 +1019,10 @@ struct QModifKeyName { int qt_key; QString name; }; +Q_DECLARE_TYPEINFO(QModifKeyName, Q_MOVABLE_TYPE); -Q_GLOBAL_STATIC(QList<QModifKeyName>, globalModifs) -Q_GLOBAL_STATIC(QList<QModifKeyName>, globalPortableModifs) +Q_GLOBAL_STATIC(QVector<QModifKeyName>, globalModifs) +Q_GLOBAL_STATIC(QVector<QModifKeyName>, globalPortableModifs) /*! Constructs a single key from the string \a str. @@ -1040,7 +1038,7 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence QString accel = str.toLower(); bool nativeText = (format == QKeySequence::NativeText); - QList<QModifKeyName> *gmodifs; + QVector<QModifKeyName> *gmodifs; if (nativeText) { gmodifs = globalModifs(); if (gmodifs->isEmpty()) { @@ -1076,7 +1074,7 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence if (!gmodifs) return ret; - QList<QModifKeyName> modifs; + QVector<QModifKeyName> modifs; if (nativeText) { modifs << QModifKeyName(Qt::CTRL, QCoreApplication::translate("QShortcut", "Ctrl").toLower().append(QLatin1Char('+'))) << QModifKeyName(Qt::SHIFT, QCoreApplication::translate("QShortcut", "Shift").toLower().append(QLatin1Char('+'))) @@ -1100,7 +1098,7 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence int i = 0; int lastI = 0; while ((i = sl.indexOf(QLatin1Char('+'), i + 1)) != -1) { - const QString sub = sl.mid(lastI, i - lastI + 1); + const QStringRef sub = sl.midRef(lastI, i - lastI + 1); // If we get here the shortcuts contains at least one '+'. We break up // along the following strategy: // Meta+Ctrl++ ( "Meta+", "Ctrl+", "+" ) @@ -1366,7 +1364,7 @@ QKeySequence::operator QVariant() const */ int QKeySequence::operator[](uint index) const { - Q_ASSERT_X(index < 4, "QKeySequence::operator[]", "index out of range"); + Q_ASSERT_X(index < QKeySequencePrivate::MaxKeyCount, "QKeySequence::operator[]", "index out of range"); return d->key[index]; } @@ -1409,6 +1407,16 @@ bool QKeySequence::operator==(const QKeySequence &other) const d->key[3] == other.d->key[3]); } +/*! + \since 5.6 + + Calculates the hash value of \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QKeySequence &key, uint seed) Q_DECL_NOTHROW +{ + return qHashRange(key.d->key, key.d->key + QKeySequencePrivate::MaxKeyCount, seed); +} /*! Provides an arbitrary comparison of this key sequence and @@ -1424,10 +1432,8 @@ bool QKeySequence::operator==(const QKeySequence &other) const */ bool QKeySequence::operator< (const QKeySequence &other) const { - for (int i = 0; i < 4; ++i) - if (d->key[i] != other.d->key[i]) - return d->key[i] < other.d->key[i]; - return false; + return std::lexicographical_compare(d->key, d->key + QKeySequencePrivate::MaxKeyCount, + other.d->key, other.d->key + QKeySequencePrivate::MaxKeyCount); } /*! @@ -1523,6 +1529,7 @@ QList<QKeySequence> QKeySequence::listFromString(const QString &str, SequenceFor QList<QKeySequence> result; QStringList strings = str.split(QLatin1String("; ")); + result.reserve(strings.count()); foreach (const QString &string, strings) { result << fromString(string, format); } @@ -1565,15 +1572,14 @@ QString QKeySequence::listToString(const QList<QKeySequence> &list, SequenceForm */ QDataStream &operator<<(QDataStream &s, const QKeySequence &keysequence) { - QList<quint32> list; - list << keysequence.d->key[0]; - - if (s.version() >= 5 && keysequence.count() > 1) { - list << keysequence.d->key[1]; - list << keysequence.d->key[2]; - list << keysequence.d->key[3]; + Q_STATIC_ASSERT_X(QKeySequencePrivate::MaxKeyCount == 4, "Forgot to adapt QDataStream &operator<<(QDataStream &s, const QKeySequence &keysequence) to new QKeySequence::MaxKeyCount"); + const bool extended = s.version() >= 5 && keysequence.count() > 1; + s << quint32(extended ? 4 : 1) << quint32(keysequence.d->key[0]); + if (extended) { + s << quint32(keysequence.d->key[1]) + << quint32(keysequence.d->key[2]) + << quint32(keysequence.d->key[3]); } - s << list; return s; } @@ -1588,11 +1594,19 @@ QDataStream &operator<<(QDataStream &s, const QKeySequence &keysequence) */ QDataStream &operator>>(QDataStream &s, QKeySequence &keysequence) { + const quint32 MaxKeys = QKeySequencePrivate::MaxKeyCount; + quint32 c; + s >> c; + quint32 keys[MaxKeys] = {0}; + for (uint i = 0; i < qMin(c, MaxKeys); ++i) { + if (s.atEnd()) { + qWarning("Premature EOF while reading QKeySequence"); + return s; + } + s >> keys[i]; + } qAtomicDetach(keysequence.d); - QList<quint32> list; - s >> list; - for (int i = 0; i < 4; ++i) - keysequence.d->key[i] = list.value(i); + std::copy(keys, keys + MaxKeys, keysequence.d->key); return s; } diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h index cd7af5718f..98a611aab5 100644 --- a/src/gui/kernel/qkeysequence.h +++ b/src/gui/kernel/qkeysequence.h @@ -43,11 +43,12 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_SHORTCUT +class QKeySequence; + /***************************************************************************** QKeySequence stream functions *****************************************************************************/ #ifndef QT_NO_DATASTREAM -class QKeySequence; Q_GUI_EXPORT QDataStream &operator<<(QDataStream &in, const QKeySequence &ks); Q_GUI_EXPORT QDataStream &operator>>(QDataStream &out, QKeySequence &ks); #endif @@ -59,6 +60,8 @@ void qt_set_sequence_auto_mnemonic(bool b); class QVariant; class QKeySequencePrivate; +Q_GUI_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QKeySequence &key, uint seed = 0) Q_DECL_NOTHROW; + class Q_GUI_EXPORT QKeySequence { Q_GADGET @@ -134,7 +137,8 @@ public: FullScreen, Deselect, DeleteCompleteLine, - Backspace + Backspace, + Cancel }; Q_ENUM(StandardKey) @@ -177,10 +181,10 @@ public: int operator[](uint i) const; QKeySequence &operator=(const QKeySequence &other); #ifdef Q_COMPILER_RVALUE_REFS - inline QKeySequence &operator=(QKeySequence &&other) - { qSwap(d, other.d); return *this; } + QKeySequence &operator=(QKeySequence &&other) Q_DECL_NOTHROW { swap(other); return *this; } #endif - inline void swap(QKeySequence &other) { qSwap(d, other.d); } + void swap(QKeySequence &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + bool operator==(const QKeySequence &other) const; inline bool operator!= (const QKeySequence &other) const { return !(*this == other); } @@ -204,6 +208,7 @@ private: friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &in, const QKeySequence &ks); friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &in, QKeySequence &ks); + friend Q_GUI_EXPORT uint qHash(const QKeySequence &key, uint seed) Q_DECL_NOTHROW; friend class QShortcutMap; friend class QShortcut; diff --git a/src/gui/kernel/qkeysequence_p.h b/src/gui/kernel/qkeysequence_p.h index 97416943d0..3e4c5bae88 100644 --- a/src/gui/kernel/qkeysequence_p.h +++ b/src/gui/kernel/qkeysequence_p.h @@ -47,6 +47,8 @@ #include "qkeysequence.h" +#include <algorithm> + QT_BEGIN_NAMESPACE #ifndef QT_NO_SHORTCUT @@ -61,20 +63,17 @@ struct Q_AUTOTEST_EXPORT QKeyBinding class Q_AUTOTEST_EXPORT QKeySequencePrivate { public: - enum { MaxKeyCount = 4 }; // used in QKeySequenceEdit + enum { MaxKeyCount = 4 }; // also used in QKeySequenceEdit inline QKeySequencePrivate() : ref(1) { - key[0] = key[1] = key[2] = key[3] = 0; + std::fill_n(key, uint(MaxKeyCount), 0); } inline QKeySequencePrivate(const QKeySequencePrivate ©) : ref(1) { - key[0] = copy.key[0]; - key[1] = copy.key[1]; - key[2] = copy.key[2]; - key[3] = copy.key[3]; + std::copy(copy.key, copy.key + MaxKeyCount, key); } QAtomicInt ref; - int key[4]; + int key[MaxKeyCount]; static QString encodeString(int key, QKeySequence::SequenceFormat format); static int decodeString(const QString &keyStr, QKeySequence::SequenceFormat format); }; diff --git a/src/gui/kernel/qoffscreensurface.h b/src/gui/kernel/qoffscreensurface.h index 909a1ef256..17bc8a7d17 100644 --- a/src/gui/kernel/qoffscreensurface.h +++ b/src/gui/kernel/qoffscreensurface.h @@ -51,7 +51,7 @@ class Q_GUI_EXPORT QOffscreenSurface : public QObject, public QSurface public: - explicit QOffscreenSurface(QScreen *screen = 0); + explicit QOffscreenSurface(QScreen *screen = Q_NULLPTR); virtual ~QOffscreenSurface(); SurfaceType surfaceType() const Q_DECL_OVERRIDE; diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 56a3729a4a..3c033ea39e 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -226,7 +226,7 @@ public: QOpenGLContext *context; }; -static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage; +Q_GLOBAL_STATIC(QThreadStorage<QGuiGLThreadContext *>, qwindow_context_storage); static QOpenGLContext *global_share_context = 0; #ifndef QT_NO_DEBUG @@ -336,14 +336,14 @@ QOpenGLContext *qt_gl_global_share_context() */ QOpenGLContext *QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context) { - QGuiGLThreadContext *threadContext = qwindow_context_storage.localData(); + QGuiGLThreadContext *threadContext = qwindow_context_storage()->localData(); if (!threadContext) { if (!QThread::currentThread()) { qWarning("No QTLS available. currentContext won't work"); return 0; } threadContext = new QGuiGLThreadContext; - qwindow_context_storage.setLocalData(threadContext); + qwindow_context_storage()->setLocalData(threadContext); } QOpenGLContext *previous = threadContext->context; threadContext->context = context; @@ -412,8 +412,8 @@ int QOpenGLContextPrivate::maxTextureSize() */ QOpenGLContext* QOpenGLContext::currentContext() { - QGuiGLThreadContext *threadContext = qwindow_context_storage.localData(); - if(threadContext) { + QGuiGLThreadContext *threadContext = qwindow_context_storage()->localData(); + if (threadContext) { return threadContext->context; } return 0; @@ -462,8 +462,7 @@ QPlatformOpenGLContext *QOpenGLContext::shareHandle() const QOpenGLContext::QOpenGLContext(QObject *parent) : QObject(*new QOpenGLContextPrivate(), parent) { - Q_D(QOpenGLContext); - d->screen = QGuiApplication::primaryScreen(); + setScreen(QGuiApplication::primaryScreen()); } /*! @@ -499,9 +498,20 @@ void QOpenGLContext::setShareContext(QOpenGLContext *shareContext) void QOpenGLContext::setScreen(QScreen *screen) { Q_D(QOpenGLContext); + if (d->screen) + disconnect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(_q_screenDestroyed(QObject*))); d->screen = screen; if (!d->screen) d->screen = QGuiApplication::primaryScreen(); + if (d->screen) + connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(_q_screenDestroyed(QObject*))); +} + +void QOpenGLContextPrivate::_q_screenDestroyed(QObject *object) +{ + Q_Q(QOpenGLContext); + if (object == static_cast<QObject *>(screen)) + q->setScreen(0); } /*! @@ -719,6 +729,28 @@ QOpenGLFunctions *QOpenGLContext::functions() const } /*! + Get the QOpenGLExtraFunctions instance for this context. + + QOpenGLContext offers this as a convenient way to access QOpenGLExtraFunctions + without having to manage it manually. + + The context or a sharing context must be current. + + The returned QOpenGLExtraFunctions instance is ready to be used and it + does not need initializeOpenGLFunctions() to be called. + + \note QOpenGLExtraFunctions contains functionality that is not guaranteed to + be available at runtime. Runtime availability depends on the platform, + graphics driver, and the OpenGL version requested by the application. + + \sa QOpenGLFunctions, QOpenGLExtraFunctions +*/ +QOpenGLExtraFunctions *QOpenGLContext::extraFunctions() const +{ + return static_cast<QOpenGLExtraFunctions *>(functions()); +} + +/*! \fn T *QOpenGLContext::versionFunctions() const \overload versionFunctions() @@ -1427,11 +1459,11 @@ void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx) { QMutexLocker locker(&m_mutex); - QList<QOpenGLSharedResource *> pending = m_pendingDeletion; + const QList<QOpenGLSharedResource *> pending = m_pendingDeletion; m_pendingDeletion.clear(); - QList<QOpenGLSharedResource *>::iterator it = pending.begin(); - QList<QOpenGLSharedResource *>::iterator end = pending.end(); + QList<QOpenGLSharedResource *>::const_iterator it = pending.begin(); + QList<QOpenGLSharedResource *>::const_iterator end = pending.end(); while (it != end) { (*it)->freeResource(ctx); delete *it; @@ -1604,4 +1636,6 @@ void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContextGroup *group, QOpenG m_groups.removeOne(group); } +#include "moc_qopenglcontext.cpp" + QT_END_NAMESPACE diff --git a/src/gui/kernel/qopenglcontext.h b/src/gui/kernel/qopenglcontext.h index a529957ad6..841967a545 100644 --- a/src/gui/kernel/qopenglcontext.h +++ b/src/gui/kernel/qopenglcontext.h @@ -54,7 +54,10 @@ #include <QtGui/qopengl.h> #include <QtGui/qopenglversionfunctions.h> +#if QT_DEPRECATED_SINCE(5, 5) #include <QtCore/qhash.h> +#endif +#include <QtCore/qhashfunctions.h> #include <QtCore/qpair.h> #include <QtCore/qvariant.h> @@ -63,6 +66,7 @@ QT_BEGIN_NAMESPACE class QOpenGLContextPrivate; class QOpenGLContextGroupPrivate; class QOpenGLFunctions; +class QOpenGLExtraFunctions; class QPlatformOpenGLContext; class QScreen; @@ -140,7 +144,7 @@ class Q_GUI_EXPORT QOpenGLContext : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QOpenGLContext) public: - explicit QOpenGLContext(QObject *parent = 0); + explicit QOpenGLContext(QObject *parent = Q_NULLPTR); ~QOpenGLContext(); void setFormat(const QSurfaceFormat &format); @@ -174,6 +178,7 @@ public: QPlatformOpenGLContext *shareHandle() const; QOpenGLFunctions *functions() const; + QOpenGLExtraFunctions *extraFunctions() const; QAbstractOpenGLFunctions *versionFunctions(const QOpenGLVersionProfile &versionProfile = QOpenGLVersionProfile()) const; @@ -236,6 +241,8 @@ private: void setTextureFunctions(QOpenGLTextureHelper* textureFuncs); void destroy(); + + Q_PRIVATE_SLOT(d_func(), void _q_screenDestroyed(QObject *object)) }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h index f9f3ce2c5f..4a746bf12b 100644 --- a/src/gui/kernel/qopenglcontext_p.h +++ b/src/gui/kernel/qopenglcontext_p.h @@ -270,6 +270,8 @@ public: static QHash<QOpenGLContext *, bool> makeCurrentTracker; static QMutex makeCurrentTrackerMutex; #endif + + void _q_screenDestroyed(QObject *object); }; Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); diff --git a/src/gui/kernel/qopenglwindow.cpp b/src/gui/kernel/qopenglwindow.cpp index b2025faaf1..3a1126d318 100644 --- a/src/gui/kernel/qopenglwindow.cpp +++ b/src/gui/kernel/qopenglwindow.cpp @@ -664,15 +664,10 @@ int QOpenGLWindow::metric(PaintDeviceMetric metric) const if (d->paintDevice) return d->paintDevice->depth(); break; - case PdmDevicePixelRatio: - if (d->paintDevice) - return devicePixelRatio(); - break; default: break; } return QPaintDeviceWindow::metric(metric); - } /*! diff --git a/src/gui/kernel/qopenglwindow.h b/src/gui/kernel/qopenglwindow.h index f274275c3f..0c2b44c1c7 100644 --- a/src/gui/kernel/qopenglwindow.h +++ b/src/gui/kernel/qopenglwindow.h @@ -58,8 +58,8 @@ public: PartialUpdateBlend }; - explicit QOpenGLWindow(UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = 0); - explicit QOpenGLWindow(QOpenGLContext *shareContext, UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = 0); + explicit QOpenGLWindow(UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = Q_NULLPTR); + explicit QOpenGLWindow(QOpenGLContext *shareContext, UpdateBehavior updateBehavior = NoPartialUpdate, QWindow *parent = Q_NULLPTR); ~QOpenGLWindow(); UpdateBehavior updateBehavior() const; diff --git a/src/gui/kernel/qpaintdevicewindow.cpp b/src/gui/kernel/qpaintdevicewindow.cpp index ff661d017d..cd894866c3 100644 --- a/src/gui/kernel/qpaintdevicewindow.cpp +++ b/src/gui/kernel/qpaintdevicewindow.cpp @@ -155,8 +155,10 @@ int QPaintDeviceWindow::metric(PaintDeviceMetric metric) const return qRound(screen->physicalDotsPerInchY()); break; case PdmDevicePixelRatio: - if (screen) - return screen->devicePixelRatio(); + return int(QWindow::devicePixelRatio()); + break; + case PdmDevicePixelRatioScaled: + return int(QWindow::devicePixelRatio() * devicePixelRatioFScale()); break; default: break; diff --git a/src/gui/kernel/qpaintdevicewindow_p.h b/src/gui/kernel/qpaintdevicewindow_p.h index e234906fe0..071f2ee54c 100644 --- a/src/gui/kernel/qpaintdevicewindow_p.h +++ b/src/gui/kernel/qpaintdevicewindow_p.h @@ -34,6 +34,17 @@ #ifndef QPAINTDEVICEWINDOW_P_H #define QPAINTDEVICEWINDOW_P_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtGui/QPaintDeviceWindow> #include <QtCore/QCoreApplication> #include <QtGui/private/qwindow_p.h> diff --git a/src/gui/kernel/qplatformcursor.cpp b/src/gui/kernel/qplatformcursor.cpp index 7239ac7ba4..cd43fc42fe 100644 --- a/src/gui/kernel/qplatformcursor.cpp +++ b/src/gui/kernel/qplatformcursor.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the QtOpenVG module of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage diff --git a/src/gui/kernel/qplatformcursor.h b/src/gui/kernel/qplatformcursor.h index 4f4f9cc6ae..8c788fd27b 100644 --- a/src/gui/kernel/qplatformcursor.h +++ b/src/gui/kernel/qplatformcursor.h @@ -3,7 +3,7 @@ ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** -** This file is part of the QtOpenVG module of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp index 3d37088182..f69efe0935 100644 --- a/src/gui/kernel/qplatformdialoghelper.cpp +++ b/src/gui/kernel/qplatformdialoghelper.cpp @@ -36,7 +36,6 @@ #include <QtCore/QVariant> #include <QtCore/QSharedData> #include <QtCore/QSettings> -#include <QtCore/QHash> #include <QtCore/QUrl> #include <QtGui/QColor> @@ -120,6 +119,8 @@ static const int buttonRoleLayouts[2][5][14] = QPlatformDialogHelper::QPlatformDialogHelper() { + qRegisterMetaType<StandardButton>(); + qRegisterMetaType<ButtonRole>(); } QPlatformDialogHelper::~QPlatformDialogHelper() @@ -423,6 +424,7 @@ public: QUrl initialDirectory; QString initiallySelectedNameFilter; QList<QUrl> initiallySelectedFiles; + QStringList supportedSchemes; }; QFileDialogOptions::QFileDialogOptions() : d(new QFileDialogOptionsPrivate) @@ -614,6 +616,18 @@ void QFileDialogOptions::setInitiallySelectedFiles(const QList<QUrl> &files) d->initiallySelectedFiles = files; } +// Schemes supported by the application +void QFileDialogOptions::setSupportedSchemes(const QStringList &schemes) +{ + d->supportedSchemes = schemes; +} + +QStringList QFileDialogOptions::supportedSchemes() const +{ + return d->supportedSchemes; +} + +// Return true if the URL is supported by the filedialog implementation *and* by the application. bool QPlatformFileDialogHelper::isSupportedUrl(const QUrl &url) const { return url.isLocalFile(); @@ -639,12 +653,13 @@ void QPlatformFileDialogHelper::setOptions(const QSharedPointer<QFileDialogOptio } const char *QPlatformFileDialogHelper::filterRegExp = -"^(.*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$"; +"^(.*)\\(([a-zA-Z0-9_.,*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$"; // Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)" QStringList QPlatformFileDialogHelper::cleanFilterList(const QString &filter) { QRegExp regexp(QString::fromLatin1(filterRegExp)); + Q_ASSERT(regexp.isValid()); QString f = filter; int i = regexp.indexIn(f); if (i >= 0) diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h index 8b2b9881b7..5b2f4ece77 100644 --- a/src/gui/kernel/qplatformdialoghelper.h +++ b/src/gui/kernel/qplatformdialoghelper.h @@ -104,6 +104,7 @@ public: }; Q_DECLARE_FLAGS(StandardButtons, StandardButton) + Q_FLAG(StandardButtons) enum ButtonRole { // keep this in sync with QDialogButtonBox::ButtonRole and QMessageBox::ButtonRole @@ -128,6 +129,7 @@ public: Reverse = 0x40000000, EOL = InvalidRole }; + Q_ENUM(ButtonRole) enum ButtonLayout { // keep this in sync with QDialogButtonBox::ButtonLayout and QMessageBox::ButtonLayout @@ -160,8 +162,14 @@ Q_SIGNALS: void reject(); }; +QT_END_NAMESPACE +Q_DECLARE_METATYPE(QPlatformDialogHelper::StandardButton) +Q_DECLARE_METATYPE(QPlatformDialogHelper::ButtonRole) +QT_BEGIN_NAMESPACE + class Q_GUI_EXPORT QColorDialogOptions { + Q_GADGET public: enum ColorDialogOption { ShowAlphaChannel = 0x00000001, @@ -170,6 +178,7 @@ public: }; Q_DECLARE_FLAGS(ColorDialogOptions, ColorDialogOption) + Q_FLAG(ColorDialogOptions) QColorDialogOptions(); QColorDialogOptions(const QColorDialogOptions &rhs); @@ -221,6 +230,7 @@ private: class Q_GUI_EXPORT QFontDialogOptions { + Q_GADGET public: enum FontDialogOption { NoButtons = 0x00000001, @@ -232,6 +242,7 @@ public: }; Q_DECLARE_FLAGS(FontDialogOptions, FontDialogOption) + Q_FLAG(FontDialogOptions) QFontDialogOptions(); QFontDialogOptions(const QFontDialogOptions &rhs); @@ -274,11 +285,19 @@ private: class Q_GUI_EXPORT QFileDialogOptions { + Q_GADGET public: enum ViewMode { Detail, List }; + Q_ENUM(ViewMode) + enum FileMode { AnyFile, ExistingFile, Directory, ExistingFiles, DirectoryOnly }; + Q_ENUM(FileMode) + enum AcceptMode { AcceptOpen, AcceptSave }; + Q_ENUM(AcceptMode) + enum DialogLabel { LookIn, FileName, FileType, Accept, Reject, DialogLabelCount }; + Q_ENUM(DialogLabel) enum FileDialogOption { @@ -292,6 +311,7 @@ public: DontUseCustomDirectoryIcons = 0x00000080 }; Q_DECLARE_FLAGS(FileDialogOptions, FileDialogOption) + Q_FLAG(FileDialogOptions) QFileDialogOptions(); QFileDialogOptions(const QFileDialogOptions &rhs); @@ -348,6 +368,9 @@ public: QList<QUrl> initiallySelectedFiles() const; void setInitiallySelectedFiles(const QList<QUrl> &); + void setSupportedSchemes(const QStringList &schemes); + QStringList supportedSchemes() const; + private: QSharedDataPointer<QFileDialogOptionsPrivate> d; }; @@ -388,9 +411,11 @@ private: class Q_GUI_EXPORT QMessageDialogOptions { + Q_GADGET public: // Keep in sync with QMessageBox::Icon enum Icon { NoIcon, Information, Warning, Critical, Question }; + Q_ENUM(Icon) QMessageDialogOptions(); QMessageDialogOptions(const QMessageDialogOptions &rhs); diff --git a/src/gui/kernel/qplatformgraphicsbufferhelper.cpp b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp index 2749b05691..c0c51b8d5e 100644 --- a/src/gui/kernel/qplatformgraphicsbufferhelper.cpp +++ b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp @@ -40,6 +40,14 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLFunctions> +#ifndef GL_RGB10_A2 +#define GL_RGB10_A2 0x8059 +#endif + +#ifndef GL_UNSIGNED_INT_2_10_10_10_REV +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#endif + QT_BEGIN_NAMESPACE /*! @@ -64,23 +72,25 @@ QT_BEGIN_NAMESPACE bound texture, otherwise returns false. */ bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, - bool *swizzle, + bool *swizzle, bool *premultiplied, const QRect &rect) { if (graphicsBuffer->lock(QPlatformGraphicsBuffer::TextureAccess)) { if (!graphicsBuffer->bindToTexture(rect)) { - qWarning() << Q_FUNC_INFO << "Failed to bind graphicsbuffer to texture"; + qWarning("Failed to bind %sgraphicsbuffer to texture", ""); return false; } if (swizzle) *swizzle = false; + if (premultiplied) + *premultiplied = false; } else if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) { - if (!bindSWToTexture(graphicsBuffer, swizzle, rect)) { - qWarning() << Q_FUNC_INFO << "Failed to bind SW graphcisbuffer to texture"; + if (!bindSWToTexture(graphicsBuffer, swizzle, premultiplied, rect)) { + qWarning("Failed to bind %sgraphicsbuffer to texture", "SW "); return false; } } else { - qWarning() << Q_FUNC_INFO << "Failed to lock"; + qWarning("Failed to lock"); return false; } return true; @@ -109,11 +119,12 @@ bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer Returns true on success, otherwise false. */ bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, - bool *swizzleRandB, + bool *swizzleRandB, bool *premultipliedB, const QRect &subRect) { #ifndef QT_NO_OPENGL - if (!QOpenGLContext::currentContext()) + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) return false; if (!(graphicsBuffer->isLocked() & QPlatformGraphicsBuffer::SWReadAccess)) @@ -123,27 +134,70 @@ bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffe Q_ASSERT(subRect.isEmpty() || QRect(QPoint(0,0), size).contains(subRect)); + GLenum internalFormat = GL_RGBA; + GLuint pixelType = GL_UNSIGNED_BYTE; + + bool needsConversion = false; bool swizzle = false; + bool premultiplied = false; QImage::Format imageformat = QImage::toImageFormat(graphicsBuffer->format()); QImage image(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), imageformat); if (graphicsBuffer->bytesPerLine() != (size.width() * 4)) { - image = image.convertToFormat(QImage::Format_RGBA8888); - } else if (imageformat == QImage::Format_RGB32) { - swizzle = true; - } else if (imageformat != QImage::Format_RGBA8888) { - image = image.convertToFormat(QImage::Format_RGBA8888); + needsConversion = true; + } else { + switch (imageformat) { + case QImage::Format_ARGB32_Premultiplied: + premultiplied = true; + // no break + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + swizzle = true; + break; + case QImage::Format_RGBA8888_Premultiplied: + premultiplied = true; + // no break + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + break; + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { + pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; + internalFormat = GL_RGB10_A2; + premultiplied = true; + } else { + needsConversion = true; + } + break; + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: + if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { + pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; + internalFormat = GL_RGB10_A2; + premultiplied = true; + swizzle = true; + } else { + needsConversion = true; + } + break; + default: + needsConversion = true; + break; + } } + if (needsConversion) + image = image.convertToFormat(QImage::Format_RGBA8888); - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); + QOpenGLFunctions *funcs = ctx->functions(); QRect rect = subRect; if (rect.isNull() || rect == QRect(QPoint(0,0),size)) { - funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); + funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.width(), size.height(), 0, GL_RGBA, pixelType, image.constBits()); } else { #ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isOpenGLES()) { + if (!ctx->isOpenGLES()) { funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width()); - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType, image.constScanLine(rect.y()) + rect.x() * 4); funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); } else @@ -160,16 +214,18 @@ bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffe // OpenGL instead of copying, since there's no gap between scanlines if (rect.width() == size.width()) { - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType, image.constScanLine(rect.y())); } else { - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType, image.copy(rect).constBits()); } } } if (swizzleRandB) *swizzleRandB = swizzle; + if (premultipliedB) + *premultipliedB = premultiplied; return true; diff --git a/src/gui/kernel/qplatformgraphicsbufferhelper.h b/src/gui/kernel/qplatformgraphicsbufferhelper.h index ded7810608..cc1a4918cd 100644 --- a/src/gui/kernel/qplatformgraphicsbufferhelper.h +++ b/src/gui/kernel/qplatformgraphicsbufferhelper.h @@ -39,8 +39,8 @@ QT_BEGIN_NAMESPACE namespace QPlatformGraphicsBufferHelper { - bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, const QRect &rect = QRect()); - bool bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB = Q_NULLPTR, const QRect &rect = QRect()); + bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, bool *premultipliedB, const QRect &rect = QRect()); + bool bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB = Q_NULLPTR, bool *premultipliedB = Q_NULLPTR, const QRect &rect = QRect()); } QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatforminputcontextfactory.cpp b/src/gui/kernel/qplatforminputcontextfactory.cpp index a7660e76ae..fedf940dda 100644 --- a/src/gui/kernel/qplatforminputcontextfactory.cpp +++ b/src/gui/kernel/qplatforminputcontextfactory.cpp @@ -56,48 +56,34 @@ QStringList QPlatformInputContextFactory::keys() #endif } -QPlatformInputContext *QPlatformInputContextFactory::create(const QString& key) +QString QPlatformInputContextFactory::requested() { - QStringList paramList = key.split(QLatin1Char(':')); - const QString platform = paramList.takeFirst().toLower(); - -#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) - if (QPlatformInputContext *ret = qLoadPlugin1<QPlatformInputContext, QPlatformInputContextPlugin>(loader(), platform, paramList)) - return ret; -#endif - return 0; + QByteArray env = qgetenv("QT_IM_MODULE"); + return env.isNull() ? QString() : QString::fromLocal8Bit(env); } -QPlatformInputContext *QPlatformInputContextFactory::create() +QPlatformInputContext *QPlatformInputContextFactory::create(const QString& key) { - QPlatformInputContext *ic = 0; - - QString icString = QString::fromLatin1(qgetenv("QT_IM_MODULE")); - - if (icString == QLatin1String("none")) - return 0; - - ic = create(icString); - if (ic && ic->isValid()) - return ic; - - delete ic; - ic = 0; +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + if (!key.isEmpty()) { + QStringList paramList = key.split(QLatin1Char(':')); + const QString platform = paramList.takeFirst().toLower(); - QStringList k = keys(); - for (int i = 0; i < k.size(); ++i) { - if (k.at(i) == icString) - continue; - ic = create(k.at(i)); + QPlatformInputContext *ic = qLoadPlugin1<QPlatformInputContext, QPlatformInputContextPlugin> + (loader(), platform, paramList); if (ic && ic->isValid()) return ic; + delete ic; - ic = 0; } - +#endif return 0; } +QPlatformInputContext *QPlatformInputContextFactory::create() +{ + return create(requested()); +} QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatforminputcontextfactory_p.h b/src/gui/kernel/qplatforminputcontextfactory_p.h index a74c4f5f80..38f4358287 100644 --- a/src/gui/kernel/qplatforminputcontextfactory_p.h +++ b/src/gui/kernel/qplatforminputcontextfactory_p.h @@ -56,6 +56,7 @@ class Q_GUI_EXPORT QPlatformInputContextFactory { public: static QStringList keys(); + static QString requested(); static QPlatformInputContext *create(const QString &key); static QPlatformInputContext *create(); }; diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 4d973d47a5..14633d8b30 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -39,7 +39,6 @@ #include <qpa/qplatformtheme.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qpixmap_raster_p.h> -#include <qpa/qplatformscreen_p.h> #include <private/qdnd_p.h> #include <private/qsimpledrag_p.h> @@ -209,8 +208,7 @@ QPlatformServices *QPlatformIntegration::services() const behavior for desktop platforms. \value ForeignWindows The platform allows creating QWindows which represent - native windows created by other processes or anyway created by using native - libraries. + native windows created by other processes or by using native libraries. \value NonFullScreenWindows The platform supports top-level windows which do not fill the screen. The default implementation returns \c true. Returning false for @@ -450,13 +448,31 @@ QList<int> QPlatformIntegration::possibleKeys(const QKeyEvent *) const void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) { QScreen *screen = new QScreen(ps); - ps->d_func()->screen = screen; + if (isPrimary) { QGuiApplicationPrivate::screen_list.prepend(screen); } else { QGuiApplicationPrivate::screen_list.append(screen); } emit qGuiApp->screenAdded(screen); + + if (isPrimary) + emit qGuiApp->primaryScreenChanged(screen); +} + +/*! + Just removes the screen, call destroyScreen instead. + + \sa destroyScreen() +*/ + +void QPlatformIntegration::removeScreen(QScreen *screen) +{ + const bool wasPrimary = (!QGuiApplicationPrivate::screen_list.isEmpty() && QGuiApplicationPrivate::screen_list[0] == screen); + QGuiApplicationPrivate::screen_list.removeOne(screen); + + if (wasPrimary && qGuiApp && !QGuiApplicationPrivate::screen_list.isEmpty()) + emit qGuiApp->primaryScreenChanged(QGuiApplicationPrivate::screen_list[0]); } /*! @@ -469,11 +485,31 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) */ void QPlatformIntegration::destroyScreen(QPlatformScreen *screen) { - QGuiApplicationPrivate::screen_list.removeOne(screen->d_func()->screen); - delete screen->d_func()->screen; + QScreen *qScreen = screen->screen(); + removeScreen(qScreen); + delete qScreen; delete screen; } +/*! + Should be called whenever the primary screen changes. + + When the screen specified as primary changes, this method will notify + QGuiApplication and emit the QGuiApplication::primaryScreenChanged signal. + */ + +void QPlatformIntegration::setPrimaryScreen(QPlatformScreen *newPrimary) +{ + QScreen* newPrimaryScreen = newPrimary->screen(); + int idx = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen); + Q_ASSERT(idx >= 0); + if (idx == 0) + return; + + QGuiApplicationPrivate::screen_list.swap(0, idx); + emit qGuiApp->primaryScreenChanged(newPrimaryScreen); +} + QStringList QPlatformIntegration::themeNames() const { return QStringList(); diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h index 2aa502b3d2..af89a73455 100644 --- a/src/gui/kernel/qplatformintegration.h +++ b/src/gui/kernel/qplatformintegration.h @@ -91,7 +91,8 @@ public: SyncState, RasterGLSurface, AllGLFunctionsQueryable, - ApplicationIcon + ApplicationIcon, + SwitchableWidgetComposition }; virtual ~QPlatformIntegration() { } @@ -172,9 +173,13 @@ public: virtual QOpenGLContext::OpenGLModuleType openGLModuleType(); #endif virtual void setApplicationIcon(const QIcon &icon) const; + + void removeScreen(QScreen *screen); + protected: void screenAdded(QPlatformScreen *screen, bool isPrimary = false); void destroyScreen(QPlatformScreen *screen); + void setPrimaryScreen(QPlatformScreen *newPrimary); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformintegrationfactory.cpp b/src/gui/kernel/qplatformintegrationfactory.cpp index d58ac3a33f..5a1fb3ca83 100644 --- a/src/gui/kernel/qplatformintegrationfactory.cpp +++ b/src/gui/kernel/qplatformintegrationfactory.cpp @@ -72,6 +72,12 @@ QPlatformIntegration *QPlatformIntegrationFactory::create(const QString &platfor } if (QPlatformIntegration *ret = loadIntegration(loader(), platform, paramList, argc, argv)) return ret; +#else + Q_UNUSED(platform); + Q_UNUSED(paramList); + Q_UNUSED(argc); + Q_UNUSED(argv); + Q_UNUSED(platformPluginPath); #endif return 0; } @@ -102,6 +108,7 @@ QStringList QPlatformIntegrationFactory::keys(const QString &platformPluginPath) list.append(loader()->keyMap().values()); return list; #else + Q_UNUSED(platformPluginPath); return QStringList(); #endif } diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h index 1022d0ed4a..bc0b3a4870 100644 --- a/src/gui/kernel/qplatformmenu.h +++ b/src/gui/kernel/qplatformmenu.h @@ -63,6 +63,7 @@ public: // They could be added as public QAction roles if necessary. CutRole, CopyRole, PasteRole, SelectAllRole, RoleCount }; + Q_ENUM(MenuRole) virtual void setTag(quintptr tag) = 0; virtual quintptr tag()const = 0; @@ -91,6 +92,7 @@ class Q_GUI_EXPORT QPlatformMenu : public QObject Q_OBJECT public: enum MenuType { DefaultMenu = 0, EditMenu }; + Q_ENUM(MenuType) virtual void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) = 0; virtual void removeMenuItem(QPlatformMenuItem *menuItem) = 0; diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index edf546799f..8e9767d69e 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -40,6 +40,7 @@ #include <qpa/qplatformintegration.h> #include <QtGui/qscreen.h> #include <QtGui/qwindow.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -55,7 +56,7 @@ QPlatformScreen::~QPlatformScreen() Q_D(QPlatformScreen); if (d->screen) { qWarning("Manually deleting a QPlatformScreen. Call QPlatformIntegration::destroyScreen instead."); - QGuiApplicationPrivate::screen_list.removeOne(d->screen); + QGuiApplicationPrivate::platformIntegration()->removeScreen(d->screen); delete d->screen; } } @@ -89,7 +90,7 @@ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const QWindowList list = QGuiApplication::topLevelWindows(); for (int i = list.size()-1; i >= 0; --i) { QWindow *w = list[i]; - if (w->isVisible() && w->geometry().contains(pos)) + if (w->isVisible() && QHighDpi::toNativePixels(w->geometry(), w).contains(pos)) return w; } @@ -97,6 +98,23 @@ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const } /*! + Find the sibling screen corresponding to \a globalPos. + + Returns this screen if no suitable screen is found at the position. + */ +const QPlatformScreen *QPlatformScreen::screenForPosition(const QPoint &point) const +{ + if (!geometry().contains(point)) { + Q_FOREACH (const QPlatformScreen* screen, virtualSiblings()) { + if (screen->geometry().contains(point)) + return screen; + } + } + return this; +} + + +/*! Returns a list of all the platform screens that are part of the same virtual desktop. @@ -156,11 +174,13 @@ QDpi QPlatformScreen::logicalDpi() const } /*! - Reimplement this function in subclass to return the device pixel - ratio for the screen. This is the ratio between physical pixels - and device-independent pixels. + Reimplement this function in subclass to return the device pixel ratio + for the screen. This is the ratio between physical pixels and the + device-independent pixels of the windowing system. The default + implementation returns 1.0. - \sa QPlatformWindow::devicePixelRatio(); + \sa QPlatformWindow::devicePixelRatio() + \sa QPlatformScreen::pixelDensity() */ qreal QPlatformScreen::devicePixelRatio() const { @@ -168,6 +188,24 @@ qreal QPlatformScreen::devicePixelRatio() const } /*! + Reimplement this function in subclass to return the pixel density of the + screen. This is the scale factor needed to make a low-dpi application + usable on this screen. The default implementation returns 1.0. + + Returning something else than 1.0 from this function causes Qt to + apply the scale factor to the application's coordinate system. + This is different from devicePixelRatio, which reports a scale + factor already applied by the windowing system. A platform plugin + typically implements one (or none) of these two functions. + + \sa QPlatformWindow::devicePixelRatio() +*/ +qreal QPlatformScreen::pixelDensity() const +{ + return 1.0; +} + +/*! Reimplement this function in subclass to return the vertical refresh rate of the screen, in Hz. @@ -290,8 +328,8 @@ void QPlatformScreen::resizeMaximizedWindows() // 'screen()' still has the old geometry info while 'this' has the new geometry info const QRect oldGeometry = screen()->geometry(); const QRect oldAvailableGeometry = screen()->availableGeometry(); - const QRect newGeometry = geometry(); - const QRect newAvailableGeometry = availableGeometry(); + const QRect newGeometry = deviceIndependentGeometry(); + const QRect newAvailableGeometry = QHighDpi::fromNative(availableGeometry(), QHighDpiScaling::factor(this), newGeometry.topLeft()); // make sure maximized and fullscreen windows are updated for (int i = 0; i < windows.size(); ++i) { @@ -324,7 +362,7 @@ static int log2(uint i) int QPlatformScreen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b) { if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) { - qWarning() << "Use QScreen version of" << __FUNCTION__ << "when passing Qt::PrimaryOrientation"; + qWarning("Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "angle"); return 0; } @@ -346,7 +384,7 @@ int QPlatformScreen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation QTransform QPlatformScreen::transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target) { if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) { - qWarning() << "Use QScreen version of" << __FUNCTION__ << "when passing Qt::PrimaryOrientation"; + qWarning("Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "transform"); return QTransform(); } @@ -377,7 +415,7 @@ QTransform QPlatformScreen::transformBetween(Qt::ScreenOrientation a, Qt::Screen QRect QPlatformScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect) { if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) { - qWarning() << "Use QScreen version of" << __FUNCTION__ << "when passing Qt::PrimaryOrientation"; + qWarning("Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "map"); return rect; } @@ -393,6 +431,13 @@ QRect QPlatformScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation return rect; } +QRect QPlatformScreen::deviceIndependentGeometry() const +{ + qreal scaleFactor = QHighDpiScaling::factor(this); + QRect nativeGeometry = geometry(); + return QRect(nativeGeometry.topLeft(), QHighDpi::fromNative(nativeGeometry.size(), scaleFactor)); +} + /*! Returns a hint about this screen's subpixel layout structure. @@ -420,4 +465,22 @@ QPlatformScreen::SubpixelAntialiasingType QPlatformScreen::subpixelAntialiasingT return static_cast<QPlatformScreen::SubpixelAntialiasingType>(type); } +/*! + Returns the current power state. + + The default implementation always returns PowerStateOn. +*/ +QPlatformScreen::PowerState QPlatformScreen::powerState() const +{ + return PowerStateOn; +} + +/*! + Sets the power state for this screen. +*/ +void QPlatformScreen::setPowerState(PowerState state) +{ + Q_UNUSED(state); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h index 551cb788c9..b32f9cf97c 100644 --- a/src/gui/kernel/qplatformscreen.h +++ b/src/gui/kernel/qplatformscreen.h @@ -82,6 +82,13 @@ public: Subpixel_VBGR }; + enum PowerState { + PowerStateOn, + PowerStateStandby, + PowerStateSuspend, + PowerStateOff + }; + QPlatformScreen(); virtual ~QPlatformScreen(); @@ -96,6 +103,7 @@ public: virtual QSizeF physicalSize() const; virtual QDpi logicalDpi() const; virtual qreal devicePixelRatio() const; + virtual qreal pixelDensity() const; virtual qreal refreshRate() const; @@ -105,6 +113,7 @@ public: virtual QWindow *topLevelAt(const QPoint &point) const; virtual QList<QPlatformScreen *> virtualSiblings() const; + const QPlatformScreen *screenForPosition(const QPoint &point) const; QScreen *screen() const; @@ -117,10 +126,16 @@ public: virtual QPlatformCursor *cursor() const; virtual SubpixelAntialiasingType subpixelAntialiasingTypeHint() const; + virtual PowerState powerState() const; + virtual void setPowerState(PowerState state); + static int angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b); static QTransform transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target); static QRect mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect); + // The platform screen's geometry in device independent coordinates + QRect deviceIndependentGeometry() const; + protected: void resizeMaximizedWindows(); @@ -129,7 +144,7 @@ protected: private: Q_DISABLE_COPY(QPlatformScreen) - friend class QPlatformIntegration; + friend class QScreenPrivate; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformsystemtrayicon.h b/src/gui/kernel/qplatformsystemtrayicon.h index 437f5e02b1..6ef2d1538f 100644 --- a/src/gui/kernel/qplatformsystemtrayicon.h +++ b/src/gui/kernel/qplatformsystemtrayicon.h @@ -57,8 +57,10 @@ public: Trigger, MiddleClick }; + Q_ENUM(ActivationReason) enum MessageIcon { NoIcon, Information, Warning, Critical }; + Q_ENUM(MessageIcon) QPlatformSystemTrayIcon(); ~QPlatformSystemTrayIcon(); diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp index 36a71fe2da..ce8548f628 100644 --- a/src/gui/kernel/qplatformtheme.cpp +++ b/src/gui/kernel/qplatformtheme.cpp @@ -323,7 +323,9 @@ const QKeyBinding QPlatformThemePrivate::keyBindings[] = { {QKeySequence::FullScreen, 1, Qt::Key_F11, KB_Win | KB_KDE}, {QKeySequence::Deselect, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_A, KB_X11}, {QKeySequence::DeleteCompleteLine, 0, Qt::CTRL | Qt::Key_U, KB_X11}, - {QKeySequence::Backspace, 0, Qt::META | Qt::Key_H, KB_Mac} + {QKeySequence::Backspace, 0, Qt::META | Qt::Key_H, KB_Mac}, + {QKeySequence::Cancel, 0, Qt::Key_Escape, KB_All}, + {QKeySequence::Cancel, 0, Qt::CTRL | Qt::Key_Period, KB_Mac} }; const uint QPlatformThemePrivate::numberOfKeyBindings = sizeof(QPlatformThemePrivate::keyBindings)/(sizeof(QKeyBinding)); diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h index 69cc2f90af..36fa7a65aa 100644 --- a/src/gui/kernel/qplatformtheme.h +++ b/src/gui/kernel/qplatformtheme.h @@ -164,6 +164,8 @@ public: SmallFont, MiniFont, FixedFont, + GroupBoxTitleFont, + TabButtonFont, NFonts }; diff --git a/src/gui/kernel/qplatformthemefactory.cpp b/src/gui/kernel/qplatformthemefactory.cpp index d4902ac163..bcc37dad06 100644 --- a/src/gui/kernel/qplatformthemefactory.cpp +++ b/src/gui/kernel/qplatformthemefactory.cpp @@ -63,6 +63,9 @@ QPlatformTheme *QPlatformThemeFactory::create(const QString& key, const QString } if (QPlatformTheme *ret = qLoadPlugin1<QPlatformTheme, QPlatformThemePlugin>(loader(), platform, paramList)) return ret; +#else + Q_UNUSED(key); + Q_UNUSED(platformPluginPath); #endif return 0; } @@ -93,6 +96,7 @@ QStringList QPlatformThemeFactory::keys(const QString &platformPluginPath) list += loader()->keyMap().values(); return list; #else + Q_UNUSED(platformPluginPath); return QStringList(); #endif } diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index 114fcf8062..aea029b7f5 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -39,8 +39,10 @@ #include <qpa/qwindowsysteminterface.h> #include <QtGui/qwindow.h> #include <QtGui/qscreen.h> +#include <private/qhighdpiscaling_p.h> #include <private/qwindow_p.h> + QT_BEGIN_NAMESPACE /*! @@ -481,13 +483,27 @@ QString QPlatformWindow::formatWindowTitle(const QString &title, const QString & QPlatformScreen *QPlatformWindow::screenForGeometry(const QRect &newGeometry) const { QPlatformScreen *currentScreen = screen(); - if (!parent() && currentScreen && !currentScreen->geometry().intersects(newGeometry)) { + QPlatformScreen *fallback = currentScreen; + //QRect::center can return a value outside the rectangle if it's empty + const QPoint center = newGeometry.isEmpty() ? newGeometry.topLeft() : newGeometry.center(); + + if (!parent() && currentScreen && !currentScreen->geometry().contains(center)) { Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) { - if (screen->geometry().intersects(newGeometry)) + if (screen->geometry().contains(center)) return screen; + if (screen->geometry().intersects(newGeometry)) + fallback = screen; } } - return currentScreen; + return fallback; +} + +/*! + Returns a size with both dimensions bounded to [0, QWINDOWSIZE_MAX] +*/ +QSize QPlatformWindow::constrainWindowSize(const QSize &size) +{ + return size.expandedTo(QSize(0, 0)).boundedTo(QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)); } /*! @@ -565,7 +581,10 @@ void QPlatformWindow::invalidateSurface() QRect QPlatformWindow::initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight) { - QRect rect(initialGeometry); + const QScreen *screen = effectiveScreen(w); + if (!screen) + return initialGeometry; + QRect rect(QHighDpi::fromNativePixels(initialGeometry, w)); if (rect.width() == 0) { const int minWidth = w->minimumWidth(); rect.setWidth(minWidth > 0 ? minWidth : defaultWidth); @@ -575,25 +594,23 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, rect.setHeight(minHeight > 0 ? minHeight : defaultHeight); } if (w->isTopLevel() && qt_window_private(const_cast<QWindow*>(w))->positionAutomatic - && w->type() != Qt::Popup) { - if (const QScreen *screen = effectiveScreen(w)) { - const QRect availableGeometry = screen->availableGeometry(); - // Center unless the geometry ( + unknown window frame) is too large for the screen). - if (rect.height() < (availableGeometry.height() * 8) / 9 + && w->type() != Qt::Popup) { + const QRect availableGeometry = screen->availableGeometry(); + // Center unless the geometry ( + unknown window frame) is too large for the screen). + if (rect.height() < (availableGeometry.height() * 8) / 9 && rect.width() < (availableGeometry.width() * 8) / 9) { - const QWindow *tp = w->transientParent(); - if (tp) { - // A transient window should be centered w.r.t. its transient parent. - rect.moveCenter(tp->geometry().center()); - } else { - // Center the window on the screen. (Only applicable on platforms - // which do not provide a better way.) - rect.moveCenter(availableGeometry.center()); - } + const QWindow *tp = w->transientParent(); + if (tp) { + // A transient window should be centered w.r.t. its transient parent. + rect.moveCenter(tp->geometry().center()); + } else { + // Center the window on the screen. (Only applicable on platforms + // which do not provide a better way.) + rect.moveCenter(availableGeometry.center()); } } } - return rect; + return QHighDpi::toNativePixels(rect, screen); } /*! @@ -627,6 +644,82 @@ void QPlatformWindow::requestUpdate() } /*! + Returns the QWindow minimum size. +*/ +QSize QPlatformWindow::windowMinimumSize() const +{ + return constrainWindowSize(QHighDpi::toNativePixels(window()->minimumSize(), window())); +} + +/*! + Returns the QWindow maximum size. +*/ +QSize QPlatformWindow::windowMaximumSize() const +{ + return constrainWindowSize(QHighDpi::toNativePixels(window()->maximumSize(), window())); +} + +/*! + Returns the QWindow base size. +*/ +QSize QPlatformWindow::windowBaseSize() const +{ + return QHighDpi::toNativePixels(window()->baseSize(), window()); +} + +/*! + Returns the QWindow size increment. +*/ +QSize QPlatformWindow::windowSizeIncrement() const +{ + QSize increment = window()->sizeIncrement(); + if (!QHighDpiScaling::isActive()) + return increment; + + // Normalize the increment. If not set the increment can be + // (-1, -1) or (0, 0). Make that (1, 1) which is scalable. + if (increment.isEmpty()) + increment = QSize(1, 1); + + return QHighDpi::toNativePixels(increment, window()); +} + +/*! + Returns the QWindow geometry. +*/ +QRect QPlatformWindow::windowGeometry() const +{ + return QHighDpi::toNativePixels(window()->geometry(), window()); +} + +/*! + Returns the QWindow frame geometry. +*/ +QRect QPlatformWindow::windowFrameGeometry() const +{ + return QHighDpi::toNativePixels(window()->frameGeometry(), window()); +} + +/*! + Returns the closest acceptable geometry for a given geometry before + a resize/move event for platforms that support it, for example to + implement heightForWidth(). +*/ + +QRectF QPlatformWindow::closestAcceptableGeometry(const QWindow *qWindow, const QRectF &nativeRect) +{ + const QRectF rectF = QHighDpi::fromNativePixels(nativeRect, qWindow); + const QRectF correctedGeometryF = qt_window_private(const_cast<QWindow *>(qWindow))->closestAcceptableGeometry(rectF); + return !correctedGeometryF.isEmpty() && rectF != correctedGeometryF + ? QHighDpi::toNativePixels(correctedGeometryF, qWindow) : nativeRect; +} + +QRectF QPlatformWindow::windowClosestAcceptableGeometry(const QRectF &nativeRect) const +{ + return QPlatformWindow::closestAcceptableGeometry(window(), nativeRect); +} + +/*! \class QPlatformWindow \since 4.8 \internal diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index c7c1efdc58..850e2b4bfe 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -95,7 +95,7 @@ public: virtual bool isExposed() const; virtual bool isActive() const; - virtual bool isEmbedded(const QPlatformWindow *parentWindow) const; + virtual bool isEmbedded(const QPlatformWindow *parentWindow = 0) const; virtual QPoint mapToGlobal(const QPoint &pos) const; virtual QPoint mapFromGlobal(const QPoint &pos) const; @@ -130,9 +130,22 @@ public: const QRect &initialGeometry, int defaultWidth, int defaultHeight); virtual void requestUpdate(); + + // Window property accessors. Platform plugins should use these + // instead of accessing QWindow directly. + QSize windowMinimumSize() const; + QSize windowMaximumSize() const; + QSize windowBaseSize() const; + QSize windowSizeIncrement() const; + QRect windowGeometry() const; + QRect windowFrameGeometry() const; + QRectF windowClosestAcceptableGeometry(const QRectF &nativeRect) const; + static QRectF closestAcceptableGeometry(const QWindow *w, const QRectF &nativeRect); + protected: static QString formatWindowTitle(const QString &title, const QString &separator); QPlatformScreen *screenForGeometry(const QRect &newGeometry) const; + static QSize constrainWindowSize(const QSize &size); QScopedPointer<QPlatformWindowPrivate> d_ptr; private: diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp index c04eb71420..fc1739ca0e 100644 --- a/src/gui/kernel/qrasterwindow.cpp +++ b/src/gui/kernel/qrasterwindow.cpp @@ -108,8 +108,6 @@ int QRasterWindow::metric(PaintDeviceMetric metric) const switch (metric) { case PdmDepth: return d->backingstore->paintDevice()->depth(); - case PdmDevicePixelRatio: - return d->backingstore->paintDevice()->devicePixelRatio(); default: break; } diff --git a/src/gui/kernel/qrasterwindow.h b/src/gui/kernel/qrasterwindow.h index 4912efad37..6db6baa8f5 100644 --- a/src/gui/kernel/qrasterwindow.h +++ b/src/gui/kernel/qrasterwindow.h @@ -46,7 +46,7 @@ class Q_GUI_EXPORT QRasterWindow : public QPaintDeviceWindow Q_DECLARE_PRIVATE(QRasterWindow) public: - explicit QRasterWindow(QWindow *parent = 0); + explicit QRasterWindow(QWindow *parent = Q_NULLPTR); protected: int metric(PaintDeviceMetric metric) const Q_DECL_OVERRIDE; diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp index 038be09dc7..52e7686439 100644 --- a/src/gui/kernel/qscreen.cpp +++ b/src/gui/kernel/qscreen.cpp @@ -36,7 +36,9 @@ #include "qpixmap.h" #include "qguiapplication_p.h" #include <qpa/qplatformscreen.h> +#include <qpa/qplatformscreen_p.h> +#include <QtCore/QDebug> #include <QtCore/private/qobject_p.h> QT_BEGIN_NAMESPACE @@ -62,8 +64,33 @@ QT_BEGIN_NAMESPACE */ QScreen::QScreen(QPlatformScreen *screen) - : QObject(*new QScreenPrivate(screen), 0) + : QObject(*new QScreenPrivate(), 0) { + Q_D(QScreen); + d->setPlatformScreen(screen); +} + +void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen) +{ + Q_Q(QScreen); + platformScreen = screen; + platformScreen->d_func()->screen = q; + orientation = platformScreen->orientation(); + geometry = platformScreen->deviceIndependentGeometry(); + availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft()); + logicalDpi = platformScreen->logicalDpi(); + refreshRate = platformScreen->refreshRate(); + // safeguard ourselves against buggy platform behavior... + if (refreshRate < 1.0) + refreshRate = 60.0; + + updatePrimaryOrientation(); + + filteredOrientation = orientation; + if (filteredOrientation == Qt::PrimaryOrientation) + filteredOrientation = primaryOrientation; + + updateHighDpi(); } @@ -89,8 +116,8 @@ QScreen::~QScreen() bool movingFromVirtualSibling = primaryScreen && primaryScreen->handle()->virtualSiblings().contains(handle()); // Move any leftover windows to the primary screen - foreach (QWindow *window, QGuiApplication::topLevelWindows()) { - if (window->screen() != this) + foreach (QWindow *window, QGuiApplication::allWindows()) { + if (!window->isTopLevel() || window->screen() != this) continue; const bool wasVisible = window->isVisible(); @@ -207,6 +234,8 @@ qreal QScreen::physicalDotsPerInch() const qreal QScreen::logicalDotsPerInchX() const { Q_D(const QScreen); + if (QHighDpiScaling::isActive()) + return QHighDpiScaling::logicalDpi().first; return d->logicalDpi.first; } @@ -221,6 +250,8 @@ qreal QScreen::logicalDotsPerInchX() const qreal QScreen::logicalDotsPerInchY() const { Q_D(const QScreen); + if (QHighDpiScaling::isActive()) + return QHighDpiScaling::logicalDpi().second; return d->logicalDpi.second; } @@ -239,7 +270,7 @@ qreal QScreen::logicalDotsPerInchY() const qreal QScreen::logicalDotsPerInch() const { Q_D(const QScreen); - QDpi dpi = d->logicalDpi; + QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi() : d->logicalDpi; return (dpi.first + dpi.second) * qreal(0.5); } @@ -258,7 +289,7 @@ qreal QScreen::logicalDotsPerInch() const qreal QScreen::devicePixelRatio() const { Q_D(const QScreen); - return d->platformScreen->devicePixelRatio(); + return d->platformScreen->devicePixelRatio() * QHighDpiScaling::factor(this); } /*! @@ -328,6 +359,7 @@ QList<QScreen *> QScreen::virtualSiblings() const Q_D(const QScreen); QList<QPlatformScreen *> platformScreens = d->platformScreen->virtualSiblings(); QList<QScreen *> screens; + screens.reserve(platformScreens.count()); foreach (QPlatformScreen *platformScreen, platformScreens) screens << platformScreen->screen(); return screens; @@ -589,7 +621,7 @@ bool QScreen::isLandscape(Qt::ScreenOrientation o) const \fn void QScreen::orientationChanged(Qt::ScreenOrientation orientation) This signal is emitted when the orientation of the screen - changes. + changes with \a orientation as an argument. \sa orientation() */ @@ -598,7 +630,7 @@ bool QScreen::isLandscape(Qt::ScreenOrientation o) const \fn void QScreen::primaryOrientationChanged(Qt::ScreenOrientation orientation) This signal is emitted when the primary orientation of the screen - changes. + changes with \a orientation as an argument. \sa primaryOrientation() */ @@ -648,10 +680,47 @@ QPixmap QScreen::grabWindow(WId window, int x, int y, int width, int height) { const QPlatformScreen *platformScreen = handle(); if (!platformScreen) { - qWarning("%s invoked with handle==0", Q_FUNC_INFO); + qWarning("invoked with handle==0"); return QPixmap(); } return platformScreen->grabWindow(window, x, y, width, height); } +#ifndef QT_NO_DEBUG_STREAM + +static inline void formatRect(QDebug &debug, const QRect r) +{ + debug << r.width() << 'x' << r.height() + << forcesign << r.x() << r.y() << noforcesign; +} + +Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QScreen *screen) +{ + const QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QScreen(" << (const void *)screen; + if (screen) { + debug << ", name=" << screen->name(); + if (debug.verbosity() > 2) { + if (screen == QGuiApplication::primaryScreen()) + debug << ", primary"; + debug << ", geometry="; + formatRect(debug, screen->geometry()); + debug << ", available="; + formatRect(debug, screen->availableGeometry()); + debug << ", logical DPI=" << screen->logicalDotsPerInchX() + << ',' << screen->logicalDotsPerInchY() + << ", physical DPI=" << screen->physicalDotsPerInchX() + << ',' << screen->physicalDotsPerInchY() + << ", devicePixelRatio=" << screen->devicePixelRatio() + << ", orientation=" << screen->orientation() + << ", physical size=" << screen->physicalSize().width() + << 'x' << screen->physicalSize().height() << "mm"; + } + } + debug << ')'; + return debug; +} +#endif // !QT_NO_DEBUG_STREAM + QT_END_NAMESPACE diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h index 255e735baf..a6018128e2 100644 --- a/src/gui/kernel/qscreen.h +++ b/src/gui/kernel/qscreen.h @@ -52,6 +52,9 @@ class QScreenPrivate; class QWindow; class QRect; class QPixmap; +#ifndef QT_NO_DEBUG_STREAM +class QDebug; +#endif class Q_GUI_EXPORT QScreen : public QObject { @@ -151,8 +154,13 @@ private: friend class QGuiApplicationPrivate; friend class QPlatformIntegration; friend class QPlatformScreen; + friend class QHighDpiScaling; }; +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug, const QScreen *); +#endif + QT_END_NAMESPACE #endif // QSCREEN_H diff --git a/src/gui/kernel/qscreen_p.h b/src/gui/kernel/qscreen_p.h index d341b71932..4492eddd45 100644 --- a/src/gui/kernel/qscreen_p.h +++ b/src/gui/kernel/qscreen_p.h @@ -47,6 +47,7 @@ #include <QtGui/qscreen.h> #include <qpa/qplatformscreen.h> +#include "qhighdpiscaling_p.h" #include <QtCore/private/qobject_p.h> @@ -54,25 +55,19 @@ QT_BEGIN_NAMESPACE class QScreenPrivate : public QObjectPrivate { + Q_DECLARE_PUBLIC(QScreen) public: - QScreenPrivate(QPlatformScreen *screen) - : platformScreen(screen) + QScreenPrivate() + : platformScreen(0) , orientationUpdateMask(0) { - orientation = platformScreen->orientation(); - geometry = platformScreen->geometry(); - availableGeometry = platformScreen->availableGeometry(); - logicalDpi = platformScreen->logicalDpi(); - refreshRate = platformScreen->refreshRate(); - // safeguard ourselves against buggy platform behavior... - if (refreshRate < 1.0) - refreshRate = 60.0; - - updatePrimaryOrientation(); + } - filteredOrientation = orientation; - if (filteredOrientation == Qt::PrimaryOrientation) - filteredOrientation = primaryOrientation; + void setPlatformScreen(QPlatformScreen *screen); + void updateHighDpi() + { + geometry = platformScreen->deviceIndependentGeometry(); + availableGeometry = QHighDpi::fromNative(platformScreen->availableGeometry(), QHighDpiScaling::factor(platformScreen), geometry.topLeft()); } void updatePrimaryOrientation(); diff --git a/src/gui/kernel/qshapedpixmapdndwindow.cpp b/src/gui/kernel/qshapedpixmapdndwindow.cpp index 8f80789fb0..d77b6dc262 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow.cpp +++ b/src/gui/kernel/qshapedpixmapdndwindow.cpp @@ -35,12 +35,16 @@ #include <QtGui/QPainter> #include <QtGui/QCursor> +#include <QtGui/QGuiApplication> +#include <QtGui/QPalette> +#include <QtGui/QBitmap> QT_BEGIN_NAMESPACE -QShapedPixmapWindow::QShapedPixmapWindow() - : QWindow(), - m_backingStore(0) +QShapedPixmapWindow::QShapedPixmapWindow(QScreen *screen) + : QWindow(screen), + m_backingStore(0), + m_useCompositing(true) { QSurfaceFormat format; format.setAlphaBufferSize(8); @@ -68,7 +72,10 @@ void QShapedPixmapWindow::render() { QPainter p(device); - p.setCompositionMode(QPainter::CompositionMode_Source); + if (m_useCompositing) + p.setCompositionMode(QPainter::CompositionMode_Source); + else + p.fillRect(rect, QGuiApplication::palette().base()); p.drawPixmap(0, 0, m_pixmap); } @@ -79,6 +86,8 @@ void QShapedPixmapWindow::render() void QShapedPixmapWindow::setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; + if (!m_useCompositing) + setMask(m_pixmap.mask()); } void QShapedPixmapWindow::setHotspot(const QPoint &hotspot) diff --git a/src/gui/kernel/qshapedpixmapdndwindow_p.h b/src/gui/kernel/qshapedpixmapdndwindow_p.h index fc311cff92..3d7974fa82 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow_p.h +++ b/src/gui/kernel/qshapedpixmapdndwindow_p.h @@ -55,11 +55,12 @@ class QShapedPixmapWindow : public QWindow { Q_OBJECT public: - QShapedPixmapWindow(); + explicit QShapedPixmapWindow(QScreen *screen = 0); ~QShapedPixmapWindow(); void render(); + void setUseCompositing(bool on) { m_useCompositing = on; } void setPixmap(const QPixmap &pixmap); void setHotspot(const QPoint &hotspot); @@ -72,6 +73,7 @@ private: QBackingStore *m_backingStore; QPixmap m_pixmap; QPoint m_hotSpot; + bool m_useCompositing; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 3e267f2e0b..3941f7233f 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -84,7 +84,7 @@ struct QShortcutEntry QShortcutMap::ContextMatcher contextMatcher; }; -#if 0 //ndef QT_NO_DEBUG_STREAM +#ifdef Dump_QShortcutMap /*! \internal QDebug operator<< for easy debug output of the shortcut entries. */ @@ -99,7 +99,7 @@ static QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se) << "), owner(" << se->owner << ')'; return dbg; } -#endif // QT_NO_DEBUGSTREAM +#endif // Dump_QShortcutMap /* \internal Private data for QShortcutMap @@ -309,59 +309,46 @@ QKeySequence::SequenceMatch QShortcutMap::state() } /*! \internal - Uses ShortcutOverride event to see if any widgets want to override - the event. If not, uses nextState(QKeyEvent) to check for a grabbed - Shortcut, and dispatchEvent() is found and identical. + Uses nextState(QKeyEvent) to check for a grabbed shortcut. - \note that this function should only be called from QWindowSystemInterface, - otherwise it will result in duplicate events. + If so, it is dispatched using dispatchEvent(). + + Returns true if a shortcut handled the event. \sa nextState, dispatchEvent */ -bool QShortcutMap::tryShortcutEvent(QObject *o, QKeyEvent *e) +bool QShortcutMap::tryShortcut(QKeyEvent *e) { Q_D(QShortcutMap); if (e->key() == Qt::Key_unknown) return false; - bool wasAccepted = e->isAccepted(); - bool wasSpontaneous = e->spont; - if (d->currentState == QKeySequence::NoMatch) { - ushort orgType = e->t; - e->t = QEvent::ShortcutOverride; - e->ignore(); - QCoreApplication::sendEvent(o, e); - e->t = orgType; - e->spont = wasSpontaneous; - if (e->isAccepted()) { - if (!wasAccepted) - e->ignore(); - return false; - } - } - - QKeySequence::SequenceMatch result = nextState(e); - bool stateWasAccepted = e->isAccepted(); - if (wasAccepted) - e->accept(); - else - e->ignore(); - - int identicalMatches = d->identicals.count(); + QKeySequence::SequenceMatch previousState = state(); - switch(result) { + switch (nextState(e)) { case QKeySequence::NoMatch: - return stateWasAccepted; - case QKeySequence::ExactMatch: + // In the case of going from a partial match to no match we handled the + // event, since we already stated that we did for the partial match. But + // in the normal case of directly going to no match we say we didn't. + return previousState == QKeySequence::PartialMatch; + case QKeySequence::PartialMatch: + // For a partial match we don't know yet if we will handle the shortcut + // but we need to say we did, so that we get the follow-up key-presses. + return true; + case QKeySequence::ExactMatch: { + // Save number of identical matches before dispatching + // to keep QShortcutMap and tryShortcut reentrant. + const int identicalMatches = d->identicals.count(); resetState(); dispatchEvent(e); + // If there are no identicals we've only found disabled shortcuts, and + // shouldn't say that we handled the event. + return identicalMatches > 0; + } default: - break; + Q_UNREACHABLE(); } - // If nextState is QKeySequence::ExactMatch && identicals.count == 0 - // we've only found disabled shortcuts - return identicalMatches > 0 || result == QKeySequence::PartialMatch; } /*! \internal @@ -396,10 +383,6 @@ QKeySequence::SequenceMatch QShortcutMap::nextState(QKeyEvent *e) } } - // Should we eat this key press? - if (d->currentState == QKeySequence::PartialMatch - || (d->currentState == QKeySequence::ExactMatch && d->identicals.count())) - e->accept(); // Does the new state require us to clean up? if (result == QKeySequence::NoMatch) clearSequence(d->currentSequences); diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h index 2376d27c78..16542b078a 100644 --- a/src/gui/kernel/qshortcutmap_p.h +++ b/src/gui/kernel/qshortcutmap_p.h @@ -75,7 +75,9 @@ public: int setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &key = QKeySequence()); int setShortcutAutoRepeat(bool on, int id, QObject *owner, const QKeySequence &key = QKeySequence()); - bool tryShortcutEvent(QObject *o, QKeyEvent *e); + QKeySequence::SequenceMatch state(); + + bool tryShortcut(QKeyEvent *e); bool hasShortcutForKeySequence(const QKeySequence &seq) const; #ifdef Dump_QShortcutMap @@ -85,7 +87,6 @@ public: private: void resetState(); QKeySequence::SequenceMatch nextState(QKeyEvent *e); - QKeySequence::SequenceMatch state(); void dispatchEvent(QKeyEvent *e); QKeySequence::SequenceMatch find(QKeyEvent *e, int ignoredModifiers = 0); diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index b850f53014..9f38c9b78a 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -55,6 +55,7 @@ #include <private/qdnd_p.h> #include <private/qshapedpixmapdndwindow_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -87,7 +88,7 @@ static QWindow* topLevelAt(const QPoint &pos) QBasicDrag::QBasicDrag() : m_restoreCursor(false), m_eventLoop(0), m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false), - m_drag(0), m_drag_icon_window(0) + m_drag(0), m_drag_icon_window(0), m_useCompositing(true) { } @@ -106,6 +107,12 @@ void QBasicDrag::disableEventFilter() qApp->removeEventFilter(this); } + +static inline QPoint getNativeMousePos(QEvent *e, QObject *o) +{ + return QHighDpi::toNativePixels(static_cast<QMouseEvent *>(e)->globalPos(), qobject_cast<QWindow*>(o)); +} + bool QBasicDrag::eventFilter(QObject *o, QEvent *e) { Q_UNUSED(o); @@ -139,20 +146,22 @@ bool QBasicDrag::eventFilter(QObject *o, QEvent *e) } case QEvent::MouseMove: - move(static_cast<QMouseEvent *>(e)); - return true; // Eat all mouse events - + { + QPoint nativePosition = getNativeMousePos(e, o); + move(nativePosition); + return true; // Eat all mouse move events + } case QEvent::MouseButtonRelease: disableEventFilter(); if (canDrop()) { - drop(static_cast<QMouseEvent *>(e)); + QPoint nativePosition = getNativeMousePos(e, o); + drop(nativePosition); } else { cancel(); } exitDndEventLoop(); - return true; // Eat all mouse events - - case QEvent::MouseButtonPress: + QCoreApplication::postEvent(o, new QMouseEvent(*static_cast<QMouseEvent *>(e))); + return true; // defer mouse release events until drag event loop has returned case QEvent::MouseButtonDblClick: case QEvent::Wheel: return true; @@ -194,25 +203,15 @@ void QBasicDrag::restoreCursor() void QBasicDrag::startDrag() { - // ### TODO Check if its really necessary to have m_drag_icon_window - // when QDrag is used without a pixmap - QDrag::setPixmap() - if (!m_drag_icon_window) - m_drag_icon_window = new QShapedPixmapWindow(); - - m_drag_icon_window->setPixmap(m_drag->pixmap()); - m_drag_icon_window->setHotspot(m_drag->hotSpot()); - + QPoint pos; #ifndef QT_NO_CURSOR - QPoint pos = QCursor::pos(); + pos = QCursor::pos(); if (pos.x() == int(qInf())) { // ### fixme: no mouse pos registered. Get pos from touch... pos = QPoint(); } - m_drag_icon_window->updateGeometry(pos); #endif - - m_drag_icon_window->setVisible(true); - + recreateShapedPixmapWindow(Q_NULLPTR, pos); enableEventFilter(); } @@ -220,6 +219,20 @@ void QBasicDrag::endDrag() { } +void QBasicDrag::recreateShapedPixmapWindow(QScreen *screen, const QPoint &pos) +{ + delete m_drag_icon_window; + // ### TODO Check if its really necessary to have m_drag_icon_window + // when QDrag is used without a pixmap - QDrag::setPixmap() + m_drag_icon_window = new QShapedPixmapWindow(screen); + + m_drag_icon_window->setUseCompositing(m_useCompositing); + m_drag_icon_window->setPixmap(m_drag->pixmap()); + m_drag_icon_window->setHotspot(m_drag->hotSpot()); + m_drag_icon_window->updateGeometry(pos); + m_drag_icon_window->setVisible(true); +} + void QBasicDrag::cancel() { disableEventFilter(); @@ -227,13 +240,18 @@ void QBasicDrag::cancel() m_drag_icon_window->setVisible(false); } -void QBasicDrag::move(const QMouseEvent *e) +/*! + Move the drag label to \a globalPos, which is + interpreted in device independent coordinates. Typically called from reimplementations of move(). + */ + +void QBasicDrag::moveShapedPixmapWindow(const QPoint &globalPos) { if (m_drag) - m_drag_icon_window->updateGeometry(e->globalPos()); + m_drag_icon_window->updateGeometry(globalPos); } -void QBasicDrag::drop(const QMouseEvent *) +void QBasicDrag::drop(const QPoint &) { disableEventFilter(); restoreCursor(); @@ -330,14 +348,15 @@ void QSimpleDrag::cancel() } } -void QSimpleDrag::move(const QMouseEvent *me) +void QSimpleDrag::move(const QPoint &globalPos) { - QBasicDrag::move(me); - QWindow *window = topLevelAt(me->globalPos()); + //### not high-DPI aware + moveShapedPixmapWindow(globalPos); + QWindow *window = topLevelAt(globalPos); if (!window) return; - const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPoint pos = globalPos - window->geometry().topLeft(); const QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions()); @@ -345,14 +364,16 @@ void QSimpleDrag::move(const QMouseEvent *me) setCanDrop(qt_response.isAccepted()); } -void QSimpleDrag::drop(const QMouseEvent *me) +void QSimpleDrag::drop(const QPoint &globalPos) { - QBasicDrag::drop(me); - QWindow *window = topLevelAt(me->globalPos()); + //### not high-DPI aware + + QBasicDrag::drop(globalPos); + QWindow *window = topLevelAt(globalPos); if (!window) return; - const QPoint pos = me->globalPos() - window->geometry().topLeft(); + const QPoint pos = globalPos - window->geometry().topLeft(); const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions()); if (response.isAccepted()) { diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h index 7812f8b863..055136c436 100644 --- a/src/gui/kernel/qsimpledrag_p.h +++ b/src/gui/kernel/qsimpledrag_p.h @@ -58,6 +58,7 @@ class QWindow; class QEventLoop; class QDropData; class QShapedPixmapWindow; +class QScreen; class Q_GUI_EXPORT QBasicDrag : public QPlatformDrag, public QObject { @@ -73,16 +74,22 @@ protected: virtual void startDrag(); virtual void cancel(); - virtual void move(const QMouseEvent *me); - virtual void drop(const QMouseEvent *me); + virtual void move(const QPoint &globalPos) = 0; + virtual void drop(const QPoint &globalPos) = 0; virtual void endDrag(); + + void moveShapedPixmapWindow(const QPoint &deviceIndependentPosition); QShapedPixmapWindow *shapedPixmapWindow() const { return m_drag_icon_window; } + void recreateShapedPixmapWindow(QScreen *screen, const QPoint &pos); void updateCursor(Qt::DropAction action); bool canDrop() const { return m_can_drop; } void setCanDrop(bool c) { m_can_drop = c; } + bool useCompositing() const { return m_useCompositing; } + void setUseCompositing(bool on) { m_useCompositing = on; } + Qt::DropAction executedDropAction() const { return m_executed_drop_action; } void setExecutedDropAction(Qt::DropAction da) { m_executed_drop_action = da; } @@ -100,6 +107,7 @@ private: bool m_can_drop; QDrag *m_drag; QShapedPixmapWindow *m_drag_icon_window; + bool m_useCompositing; }; class Q_GUI_EXPORT QSimpleDrag : public QBasicDrag @@ -111,8 +119,8 @@ public: protected: virtual void startDrag() Q_DECL_OVERRIDE; virtual void cancel() Q_DECL_OVERRIDE; - virtual void move(const QMouseEvent *me) Q_DECL_OVERRIDE; - virtual void drop(const QMouseEvent *me) Q_DECL_OVERRIDE; + virtual void move(const QPoint &globalPos) Q_DECL_OVERRIDE; + virtual void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; private: QWindow *m_current_window; diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp index 7ff0f9f860..7fc89112e6 100644 --- a/src/gui/kernel/qstylehints.cpp +++ b/src/gui/kernel/qstylehints.cpp @@ -305,7 +305,7 @@ int QStyleHints::cursorFlashTime() const \note The platform may still choose to show certain windows non-fullscreen, such as popups or dialogs. This property only reports the default behavior. - \sa QWindow::show() + \sa QWindow::show(), showIsMaximized() */ bool QStyleHints::showIsFullScreen() const { @@ -313,6 +313,22 @@ bool QStyleHints::showIsFullScreen() const } /*! + \property QStyleHints::showIsMaximized + \brief \c true if the platform defaults to windows being maximized, + otherwise \c false. + + \note The platform may still choose to show certain windows non-maximized, + such as popups or dialogs. This property only reports the default behavior. + + \sa QWindow::show(), showIsFullScreen() + \since 5.6 +*/ +bool QStyleHints::showIsMaximized() const +{ + return hint(QPlatformIntegration::ShowIsMaximized).toBool(); +} + +/*! \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 82eb8a6f7d..c5b8241e07 100644 --- a/src/gui/kernel/qstylehints.h +++ b/src/gui/kernel/qstylehints.h @@ -56,6 +56,7 @@ class Q_GUI_EXPORT QStyleHints : public QObject Q_PROPERTY(int passwordMaskDelay READ passwordMaskDelay STORED false CONSTANT FINAL) Q_PROPERTY(bool setFocusOnTouchRelease READ setFocusOnTouchRelease STORED false CONSTANT FINAL) Q_PROPERTY(bool showIsFullScreen READ showIsFullScreen STORED false CONSTANT FINAL) + Q_PROPERTY(bool showIsMaximized READ showIsMaximized STORED false CONSTANT 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) @@ -78,6 +79,7 @@ public: void setCursorFlashTime(int cursorFlashTime); int cursorFlashTime() const; bool showIsFullScreen() const; + bool showIsMaximized() const; int passwordMaskDelay() const; QChar passwordMaskCharacter() const; qreal fontSmoothingGamma() const; diff --git a/src/gui/kernel/qtouchdevice.cpp b/src/gui/kernel/qtouchdevice.cpp index 1a6e9deba8..266b5308a2 100644 --- a/src/gui/kernel/qtouchdevice.cpp +++ b/src/gui/kernel/qtouchdevice.cpp @@ -195,7 +195,7 @@ void QTouchDevice::setName(const QString &name) d->name = name; } -typedef QList<QTouchDevice *> TouchDevices; +typedef QList<const QTouchDevice *> TouchDevices; Q_GLOBAL_STATIC(TouchDevices, deviceList) static QBasicMutex devicesMutex; @@ -214,26 +214,22 @@ static void cleanupDevicesList() QList<const QTouchDevice *> QTouchDevice::devices() { QMutexLocker lock(&devicesMutex); - QList<QTouchDevice *> *devList = deviceList(); - QList<const QTouchDevice *> constDevList; - for (int i = 0, count = devList->count(); i != count; ++i) - constDevList.append(devList->at(i)); - return constDevList; + return *deviceList(); } /*! \internal */ -bool QTouchDevicePrivate::isRegistered(QTouchDevice *dev) +bool QTouchDevicePrivate::isRegistered(const QTouchDevice *dev) { - QMutexLocker lock(&devicesMutex); + QMutexLocker locker(&devicesMutex); return deviceList()->contains(dev); } /*! \internal */ -void QTouchDevicePrivate::registerDevice(QTouchDevice *dev) +void QTouchDevicePrivate::registerDevice(const QTouchDevice *dev) { QMutexLocker lock(&devicesMutex); if (deviceList()->isEmpty()) @@ -241,6 +237,17 @@ void QTouchDevicePrivate::registerDevice(QTouchDevice *dev) deviceList()->append(dev); } +/*! + \internal + */ +void QTouchDevicePrivate::unregisterDevice(const QTouchDevice *dev) +{ + QMutexLocker lock(&devicesMutex); + bool wasRemoved = deviceList()->removeOne(dev); + if (wasRemoved && deviceList()->isEmpty()) + qRemovePostRoutine(cleanupDevicesList); +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const QTouchDevice *device) { diff --git a/src/gui/kernel/qtouchdevice_p.h b/src/gui/kernel/qtouchdevice_p.h index 9c0bcf3414..63b83d33ec 100644 --- a/src/gui/kernel/qtouchdevice_p.h +++ b/src/gui/kernel/qtouchdevice_p.h @@ -45,7 +45,6 @@ // We mean it. // -#include <QtCore/qobject.h> #include <QtGui/qtouchdevice.h> QT_BEGIN_NAMESPACE @@ -65,8 +64,9 @@ public: QString name; int maxTouchPoints; - static void registerDevice(QTouchDevice *dev); - static bool isRegistered(QTouchDevice *dev); + static void registerDevice(const QTouchDevice *dev); + static void unregisterDevice(const QTouchDevice *dev); + static bool isRegistered(const QTouchDevice *dev); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 871437efb1..21734f1619 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -47,6 +47,7 @@ #ifndef QT_NO_ACCESSIBILITY # include "qaccessible.h" #endif +#include "qhighdpiscaling_p.h" #include <private/qevent_p.h> @@ -368,7 +369,7 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate) { Q_Q(QWindow); if (parentWindow) { - qWarning() << this << Q_FUNC_INFO << '(' << newScreen << "): Attempt to set a screen on a child window."; + qWarning() << this << '(' << newScreen << "): Attempt to set a screen on a child window."; return; } if (newScreen != topLevelScreen) { @@ -388,25 +389,31 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate) void QWindowPrivate::create(bool recursive) { Q_Q(QWindow); + if (platformWindow) + return; + + platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(q); + Q_ASSERT(platformWindow); + if (!platformWindow) { - platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(q); - QObjectList childObjects = q->children(); - for (int i = 0; i < childObjects.size(); i ++) { - QObject *object = childObjects.at(i); - if (object->isWindowType()) { - QWindow *window = static_cast<QWindow *>(object); - if (recursive) - window->d_func()->create(true); - if (window->d_func()->platformWindow) - window->d_func()->platformWindow->setParent(platformWindow); - } - } + qWarning() << "Failed to create platform window for" << q << "with flags" << q->flags(); + return; + } - if (platformWindow) { - QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated); - QGuiApplication::sendEvent(q, &e); + QObjectList childObjects = q->children(); + for (int i = 0; i < childObjects.size(); i ++) { + QObject *object = childObjects.at(i); + if (object->isWindowType()) { + QWindow *window = static_cast<QWindow *>(object); + if (recursive) + window->d_func()->create(true); + if (window->d_func()->platformWindow) + window->d_func()->platformWindow->setParent(platformWindow); } } + + QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated); + QGuiApplication::sendEvent(q, &e); } void QWindowPrivate::clearFocusObject() @@ -587,8 +594,7 @@ QWindow *QWindow::parent() const Setting \a parent to be 0 will make the window become a top level window. If \a parent is a window created by fromWinId(), then the current window - will be embedded inside \a parent, if the platform supports it. Window - embedding is currently supported only by the X11 platform plugin. + will be embedded inside \a parent, if the platform supports it. */ void QWindow::setParent(QWindow *parent) { @@ -598,11 +604,13 @@ void QWindow::setParent(QWindow *parent) QScreen *newScreen = parent ? parent->screen() : screen(); if (d->windowRecreationRequired(newScreen)) { - qWarning() << this << Q_FUNC_INFO << '(' << parent << "): Cannot change screens (" << screen() << newScreen << ')'; + qWarning() << this << '(' << parent << "): Cannot change screens (" << screen() << newScreen << ')'; return; } QObject::setParent(parent); + d->parentWindow = parent; + if (parent) d->disconnectFromScreen(); else @@ -616,8 +624,6 @@ void QWindow::setParent(QWindow *parent) } } - d->parentWindow = parent; - QGuiApplicationPrivate::updateBlockedStatus(this); } @@ -1085,13 +1091,13 @@ qreal QWindow::devicePixelRatio() const { Q_D(const QWindow); - // If there is no platform window, do the second best thing and - // return the app global devicePixelRatio. This is the highest - // devicePixelRatio found on the system screens, and will be - // correct for single-display systems (a very common case). + // If there is no platform window use the app global devicePixelRatio, + // which is the the highest devicePixelRatio found on the system + // screens, and will be correct for single-display systems (a very common case). if (!d->platformWindow) return qApp->devicePixelRatio(); - return d->platformWindow->devicePixelRatio(); + + return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this); } /*! @@ -1154,7 +1160,7 @@ void QWindow::setTransientParent(QWindow *parent) { Q_D(QWindow); if (parent && !parent->isTopLevel()) { - qWarning() << Q_FUNC_INFO << parent << "must be a top level window."; + qWarning() << parent << "must be a top level window."; return; } @@ -1437,7 +1443,13 @@ void QWindow::setGeometry(const QRect &rect) d->positionPolicy = QWindowPrivate::WindowFrameExclusive; if (d->platformWindow) { - d->platformWindow->setGeometry(rect); + QRect nativeRect; + QScreen *newScreen = d->screenForGeometry(rect); + if (newScreen && isTopLevel()) + nativeRect = QHighDpi::toNativePixels(rect, newScreen); + else + nativeRect = QHighDpi::toNativePixels(rect, this); + d->platformWindow->setGeometry(nativeRect); } else { d->geometry = rect; @@ -1452,6 +1464,30 @@ void QWindow::setGeometry(const QRect &rect) } } +/* + This is equivalent to QPlatformWindow::screenForGeometry, but in platform + independent coordinates. The duplication is unfortunate, but there is a + chicken and egg problem here: we cannot convert to native coordinates + before we know which screen we are on. +*/ +QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) +{ + Q_Q(QWindow); + QScreen *currentScreen = q->screen(); + QScreen *fallback = currentScreen; + QPoint center = newGeometry.center(); + if (!q->parent() && currentScreen && !currentScreen->geometry().contains(center)) { + Q_FOREACH (QScreen* screen, currentScreen->virtualSiblings()) { + if (screen->geometry().contains(center)) + return screen; + if (screen->geometry().intersects(newGeometry)) + fallback = screen; + } + } + return fallback; +} + + /*! Returns the geometry of the window, excluding its window frame. @@ -1461,7 +1497,7 @@ QRect QWindow::geometry() const { Q_D(const QWindow); if (d->platformWindow) - return d->platformWindow->geometry(); + return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this); return d->geometry; } @@ -1474,7 +1510,7 @@ QMargins QWindow::frameMargins() const { Q_D(const QWindow); if (d->platformWindow) - return d->platformWindow->frameMargins(); + return QHighDpi::fromNativePixels(d->platformWindow->frameMargins(), this); return QMargins(); } @@ -1488,7 +1524,7 @@ QRect QWindow::frameGeometry() const Q_D(const QWindow); if (d->platformWindow) { QMargins m = frameMargins(); - return d->platformWindow->geometry().adjusted(-m.left(), -m.top(), m.right(), m.bottom()); + return QHighDpi::fromNativePixels(d->platformWindow->geometry(), this).adjusted(-m.left(), -m.top(), m.right(), m.bottom()); } return d->geometry; } @@ -1505,7 +1541,7 @@ QPoint QWindow::framePosition() const Q_D(const QWindow); if (d->platformWindow) { QMargins margins = frameMargins(); - return d->platformWindow->geometry().topLeft() - QPoint(margins.left(), margins.top()); + return QHighDpi::fromNativePixels(d->platformWindow->geometry().topLeft(), this) - QPoint(margins.left(), margins.top()); } return d->geometry.topLeft(); } @@ -1521,7 +1557,7 @@ void QWindow::setFramePosition(const QPoint &point) d->positionPolicy = QWindowPrivate::WindowFrameInclusive; d->positionAutomatic = false; if (d->platformWindow) { - d->platformWindow->setGeometry(QRect(point, size())); + d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(point, size()), this)); } else { d->geometry.moveTopLeft(point); } @@ -1581,7 +1617,7 @@ void QWindow::resize(const QSize &newSize) { Q_D(QWindow); if (d->platformWindow) { - d->platformWindow->setGeometry(QRect(position(), newSize)); + d->platformWindow->setGeometry(QHighDpi::toNativePixels(QRect(position(), newSize), this)); } else { const QSize oldSize = d->geometry.size(); d->geometry.setSize(newSize); @@ -2261,10 +2297,10 @@ QPoint QWindow::mapToGlobal(const QPoint &pos) const Q_D(const QWindow); // QTBUG-43252, prefer platform implementation for foreign windows. if (d->platformWindow - && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded(0))) { + && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded())) { return d->platformWindow->mapToGlobal(pos); } - return pos + d_func()->globalPosition(); + return pos + d->globalPosition(); } @@ -2281,10 +2317,10 @@ QPoint QWindow::mapFromGlobal(const QPoint &pos) const Q_D(const QWindow); // QTBUG-43252, prefer platform implementation for foreign windows. if (d->platformWindow - && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded(0))) { + && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded())) { return d->platformWindow->mapFromGlobal(pos); } - return pos - d_func()->globalPosition(); + return pos - d->globalPosition(); } @@ -2346,9 +2382,16 @@ QWindow *QWindowPrivate::topLevelWindow() const Given the handle \a id to a native window, this method creates a QWindow object which can be used to represent the window when invoking methods like setParent() and setTransientParent(). - This can be used, on platforms which support it, to embed a window inside a - container or to make a window stick on top of a window created by another - process. + + This can be used, on platforms which support it, to embed a QWindow inside a + native window, or to embed a native window inside a QWindow. + + If foreign windows are not supported, this function returns 0. + + \note The resulting QWindow should not be used to manipulate the underlying + native window (besides re-parenting), or to observe state changes of the + native window. Any support for these kind of operations is incidental, highly + platform dependent and untested. \sa setParent() \sa setTransientParent() @@ -2477,6 +2520,45 @@ void QWindowPrivate::applyCursor() } #endif // QT_NO_CURSOR +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QWindow *window) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + if (window) { + debug << window->metaObject()->className() << '(' << (const void *)window; + if (!window->objectName().isEmpty()) + debug << ", name=" << window->objectName(); + if (debug.verbosity() > 2) { + const QRect geometry = window->geometry(); + if (window->isVisible()) + debug << ", visible"; + if (window->isExposed()) + debug << ", exposed"; + debug << ", state=" << window->windowState() + << ", type=" << window->type() << ", flags=" << window->flags() + << ", surface type=" << window->surfaceType(); + if (window->isTopLevel()) + debug << ", toplevel"; + debug << ", " << geometry.width() << 'x' << geometry.height() + << forcesign << geometry.x() << geometry.y() << noforcesign; + const QMargins margins = window->frameMargins(); + if (!margins.isNull()) + debug << ", margins=" << margins; + debug << ", devicePixelRatio=" << window->devicePixelRatio(); + if (const QPlatformWindow *platformWindow = window->handle()) + debug << ", winId=0x" << hex << platformWindow->winId() << dec; + if (const QScreen *screen = window->screen()) + debug << ", on " << screen->name(); + } + debug << ')'; + } else { + debug << "QWindow(0x0)"; + } + return debug; +} +#endif // !QT_NO_DEBUG_STREAM + QT_END_NAMESPACE #include "moc_qwindow.cpp" diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index f9fe37718c..b29e7aaae7 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -78,6 +78,9 @@ class QBackingStore; class QScreen; class QAccessibleInterface; class QWindowContainer; +#ifndef QT_NO_DEBUG_STREAM +class QDebug; +#endif class Q_GUI_EXPORT QWindow : public QObject, public QSurface { @@ -122,7 +125,7 @@ public: }; Q_ENUM(Visibility) - explicit QWindow(QScreen *screen = 0); + explicit QWindow(QScreen *screen = Q_NULLPTR); explicit QWindow(QWindow *parent); virtual ~QWindow(); @@ -357,16 +360,20 @@ private: #ifndef Q_QDOC template <> inline QWindow *qobject_cast<QWindow*>(QObject *o) { - if (!o || !o->isWindowType()) return 0; + if (!o || !o->isWindowType()) return Q_NULLPTR; return static_cast<QWindow*>(o); } template <> inline const QWindow *qobject_cast<const QWindow*>(const QObject *o) { - if (!o || !o->isWindowType()) return 0; + if (!o || !o->isWindowType()) return Q_NULLPTR; return static_cast<const QWindow*>(o); } #endif // !Q_QDOC +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug, const QWindow *); +#endif + QT_END_NAMESPACE #endif // QWINDOW_H diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 4fc63acf28..6880edaada 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -50,6 +50,7 @@ #include <qpa/qplatformwindow.h> #include <QtCore/private/qobject_p.h> +#include <QtCore/qelapsedtimer.h> #include <QtGui/QIcon> QT_BEGIN_NAMESPACE @@ -136,6 +137,7 @@ public: void connectToScreen(QScreen *topLevelScreen); void disconnectFromScreen(); void emitScreenChangedRecursion(QScreen *newScreen); + QScreen *screenForGeometry(const QRect &rect); virtual void clearFocusObject(); virtual QRectF closestAcceptableGeometry(const QRectF &rect) const; @@ -186,6 +188,7 @@ public: #endif bool compositing; + QElapsedTimer lastComposeTime; }; diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 850b69d729..d17a1f1d5b 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -40,14 +40,18 @@ #include <qpa/qplatformdrag.h> #include <qpa/qplatformintegration.h> #include <qdebug.h> +#include "qhighdpiscaling_p.h" +#include <QtCore/qscopedvaluerollback.h> QT_BEGIN_NAMESPACE QElapsedTimer QWindowSystemInterfacePrivate::eventTime; -bool QWindowSystemInterfacePrivate::synchronousWindowsSystemEvents = false; +bool QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = false; QWaitCondition QWindowSystemInterfacePrivate::eventsFlushed; QMutex QWindowSystemInterfacePrivate::flushEventMutex; +QAtomicInt QWindowSystemInterfacePrivate::eventAccepted; +QWindowSystemEventHandler *QWindowSystemInterfacePrivate::eventHandler; //------------------------------------------------------------ // @@ -93,14 +97,14 @@ void QWindowSystemInterface::handleLeaveEvent(QWindow *tlw) */ void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local, const QPointF& global) { - bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowsSystemEvents; + bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; if (wasSynchronous) - setSynchronousWindowsSystemEvents(false); + setSynchronousWindowSystemEvents(false); handleLeaveEvent(leave); handleEnterEvent(enter, local, global); if (wasSynchronous) { flushWindowSystemEvents(); - setSynchronousWindowsSystemEvents(true); + setSynchronousWindowSystemEvents(true); } } @@ -138,7 +142,7 @@ void QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState */ void QWindowSystemInterface::handleGeometryChange(QWindow *tlw, const QRect &newRect, const QRect &oldRect) { - QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw,newRect, oldRect); + QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw, QHighDpi::fromNativePixels(newRect, tlw), QHighDpi::fromNativePixels(oldRect, tlw)); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -167,7 +171,7 @@ void QWindowSystemInterface::handleMouseEvent(QWindow *w, ulong timestamp, const Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { QWindowSystemInterfacePrivate::MouseEvent * e = - new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, local, global, b, mods, source); + new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -184,167 +188,102 @@ void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w, ulong timest QWindowSystemInterfacePrivate::MouseEvent * e = new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp, QWindowSystemInterfacePrivate::FrameStrutMouse, - local, global, b, mods, source); + QHighDpi::fromNativeLocalPosition(local, w), QHighDpi::fromNativePixels(global, w), b, mods, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } -bool QWindowSystemInterface::tryHandleShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods, - const QString & text, bool autorep, ushort count) -{ - unsigned long timestamp = QWindowSystemInterfacePrivate::eventTime.elapsed(); - return tryHandleShortcutEvent(w, timestamp, k, mods, text, autorep, count); -} - -bool QWindowSystemInterface::tryHandleShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, - const QString & text, bool autorep, ushort count) -{ -#ifndef QT_NO_SHORTCUT - QGuiApplicationPrivate::modifier_buttons = mods; - - if (!w) - w = QGuiApplication::focusWindow(); - if (!w) - return false; - - QObject *focus = w->focusObject(); - if (!focus) - focus = w; - - QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, text, autorep, count); - qevent.setTimestamp(timestamp); - return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, &qevent); -#else - Q_UNUSED(w) - Q_UNUSED(timestamp) - Q_UNUSED(k) - Q_UNUSED(mods) - Q_UNUSED(text) - Q_UNUSED(autorep) - Q_UNUSED(count) - return false; -#endif -} - -bool QWindowSystemInterface::tryHandleShortcutOverrideEvent(QWindow *w, QKeyEvent *ev) -{ -#ifndef QT_NO_SHORTCUT - Q_ASSERT(ev->type() == QKeyEvent::ShortcutOverride); - QGuiApplicationPrivate::modifier_buttons = ev->modifiers(); - - QObject *focus = w->focusObject(); - if (!focus) - focus = w; - return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, ev); -#else - Q_UNUSED(w) - Q_UNUSED(ev) - return false; -#endif -} - -// used by QTestLib to directly send shortcuts to objects -bool QWindowSystemInterface::tryHandleShortcutEventToObject(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, - const QString &text, bool autorep, ushort count) +bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestamp, int keyCode, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, + quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text, bool autorepeat, ushort count) { #ifndef QT_NO_SHORTCUT - QGuiApplicationPrivate::modifier_buttons = mods; - - QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, text, autorep, count); - qevent.setTimestamp(timestamp); - return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(o, &qevent); -#else - Q_UNUSED(w) - Q_UNUSED(timestamp) - Q_UNUSED(k) - Q_UNUSED(mods) - Q_UNUSED(text) - Q_UNUSED(autorep) - Q_UNUSED(count) - return false; -#endif -} - -bool QWindowSystemInterface::tryHandleExtendedShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString &text, bool autorep, ushort count) -{ - unsigned long timestamp = QWindowSystemInterfacePrivate::eventTime.elapsed(); - return tryHandleExtendedShortcutEvent(w, timestamp, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); -} - -bool QWindowSystemInterface::tryHandleExtendedShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString &text, bool autorep, ushort count) -{ -#ifndef QT_NO_SHORTCUT - QGuiApplicationPrivate::modifier_buttons = mods; + if (!window) + window = QGuiApplication::focusWindow(); + + QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap; + if (shortcutMap.state() == QKeySequence::NoMatch) { + // Check if the shortcut is overridden by some object in the event delivery path (typically the focus object). + // If so, we should not look up the shortcut in the shortcut map, but instead deliver the event as a regular + // key event, so that the target that accepted the shortcut override event can handle it. Note that we only + // do this if the shortcut map hasn't found a partial shortcut match yet. If it has, the shortcut can not be + // overridden. + QWindowSystemInterfacePrivate::KeyEvent *shortcutOverrideEvent = new QWindowSystemInterfacePrivate::KeyEvent(window, timestamp, + QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorepeat, count); + + { + // FIXME: Template handleWindowSystemEvent to support both sync and async delivery + QScopedValueRollback<bool> syncRollback(QWindowSystemInterfacePrivate::synchronousWindowSystemEvents); + QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = true; + + if (QWindowSystemInterfacePrivate::handleWindowSystemEvent(shortcutOverrideEvent)) + return false; + } + } - QObject *focus = w->focusObject(); - if (!focus) - focus = w; + // The shortcut event is dispatched as a QShortcutEvent, not a QKeyEvent, but we use + // the QKeyEvent as a container for the various properties that the shortcut map needs + // to inspect to determine if a shortcut matched the keys that were pressed. + QKeyEvent keyEvent(QEvent::ShortcutOverride, keyCode, modifiers, nativeScanCode, + nativeVirtualKey, nativeModifiers, text, autorepeat, count); - QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); - qevent.setTimestamp(timestamp); - return QGuiApplicationPrivate::instance()->shortcutMap.tryShortcutEvent(focus, &qevent); + return shortcutMap.tryShortcut(&keyEvent); #else - Q_UNUSED(w) + Q_UNUSED(window) Q_UNUSED(timestamp) - Q_UNUSED(k) - Q_UNUSED(mods) + Q_UNUSED(key) + Q_UNUSED(modifiers) Q_UNUSED(nativeScanCode) Q_UNUSED(nativeVirtualKey) Q_UNUSED(nativeModifiers) Q_UNUSED(text) - Q_UNUSED(autorep) + Q_UNUSED(autorepeat) Q_UNUSED(count) return false; #endif } -void QWindowSystemInterface::handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { +bool QWindowSystemInterface::handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleKeyEvent(w, time, t, k, mods, text, autorep, count); + return handleKeyEvent(w, time, t, k, mods, text, autorep, count); } -void QWindowSystemInterface::handleKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) +bool QWindowSystemInterface::handleKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text, bool autorep, ushort count) { - // This is special handling needed for OS X which eventually will call sendEvent(), on other platforms - // this might not be safe, e.g., on Android. See: QGuiApplicationPrivate::processKeyEvent() for - // shortcut overriding on other platforms. -#if defined(Q_OS_OSX) - if (t == QEvent::KeyPress && QWindowSystemInterface::tryHandleShortcutEvent(tlw, timestamp, k, mods, text)) - return; -#endif // Q_OS_OSX + if (t == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(tlw, timestamp, k, mods, 0, 0, 0, text, autorep, count)) + return true; QWindowSystemInterfacePrivate::KeyEvent * e = new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, t, k, mods, text, autorep, count); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } -void QWindowSystemInterface::handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, +bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text, bool autorep, - ushort count) + ushort count, bool tryShortcutOverride) { unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleExtendedKeyEvent(w, time, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, - text, autorep, count); + return handleExtendedKeyEvent(w, time, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, + text, autorep, count, tryShortcutOverride); } -void QWindowSystemInterface::handleExtendedKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, +bool QWindowSystemInterface::handleExtendedKeyEvent(QWindow *tlw, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text, bool autorep, ushort count, bool tryShortcutOverride) { - Q_UNUSED(tryShortcutOverride) + if (tryShortcutOverride && type == QEvent::KeyPress && QWindowSystemInterface::handleShortcutEvent(tlw, + timestamp, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count)) { + return true; + } + QWindowSystemInterfacePrivate::KeyEvent * e = new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + return QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } void QWindowSystemInterface::handleWheelEvent(QWindow *w, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods) { @@ -382,14 +321,14 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Simple case: vertical deltas only: if (angleDelta.y() != 0 && angleDelta.x() == 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } // Simple case: horizontal deltas only: if (angleDelta.y() == 0 && angleDelta.x() != 0) { - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.x(), Qt::Horizontal, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); return; } @@ -397,12 +336,12 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *tlw, ulong timestamp, con // Both horizontal and vertical deltas: Send two wheel events. // The first event contains the Qt 5 pixel and angle delta as points, // and in addition the Qt 4 compatibility vertical angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), pixelDelta, angleDelta, angleDelta.y(), Qt::Vertical, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); // The second event contains null pixel and angle points and the // Qt 4 compatibility horizontal angle delta. - e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, local, global, QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source); + e = new QWindowSystemInterfacePrivate::WheelEvent(tlw, timestamp, QHighDpi::fromNativeLocalPosition(local, tlw), QHighDpi::fromNativePixels(global, tlw), QPoint(), QPoint(), angleDelta.x(), Qt::Horizontal, mods, phase, source); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -440,23 +379,60 @@ void QWindowSystemInterfacePrivate::removeWindowSystemEvent(WindowSystemEvent *e windowSystemEventQueue.remove(event); } -void QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev) +void QWindowSystemInterfacePrivate::postWindowSystemEvent(WindowSystemEvent *ev) { - if (synchronousWindowsSystemEvents) { - QGuiApplicationPrivate::processWindowSystemEvent(ev); + windowSystemEventQueue.append(ev); + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher(); + if (dispatcher) + dispatcher->wakeUp(); +} + +/*! + Handles a window system event. + + By default this function posts the event on the window system event queue and + wakes the Gui event dispatcher. Qt Gui will then handle the event asynchonously + at a later point. The return value is not used in asynchronous mode and will + always be true. + + In synchronous mode Qt Gui will process the event immediately. The return value + indicates if Qt accepted the event. + + \sa flushWindowSystemEvents(), setSynchronousWindowSystemEvents() +*/ +bool QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *ev) +{ + bool accepted = true; + if (synchronousWindowSystemEvents) { + if (QThread::currentThread() == QGuiApplication::instance()->thread()) { + // Process the event immediately on the current thread and return the accepted state. + QGuiApplicationPrivate::processWindowSystemEvent(ev); + accepted = ev->eventAccepted; + delete ev; + } else { + // Post the event on the Qt main thread queue and flush the queue. + // This will wake up the Gui thread which will process the event. + // Return the accepted state for the last event on the queue, + // which is the event posted by this function. + postWindowSystemEvent(ev); + accepted = QWindowSystemInterface::flushWindowSystemEvents(); + } } else { - windowSystemEventQueue.append(ev); - QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher(); - if (dispatcher) - dispatcher->wakeUp(); + postWindowSystemEvent(ev); } + return accepted; } -void QWindowSystemInterface::registerTouchDevice(QTouchDevice *device) +void QWindowSystemInterface::registerTouchDevice(const QTouchDevice *device) { QTouchDevicePrivate::registerDevice(device); } +void QWindowSystemInterface::unregisterTouchDevice(const QTouchDevice *device) +{ + QTouchDevicePrivate::unregisterDevice(device); +} + void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device, const QList<TouchPoint> &points, Qt::KeyboardModifiers mods) { @@ -464,12 +440,16 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device, handleTouchEvent(w, time, device, points, mods); } -QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type) +QList<QTouchEvent::TouchPoint> + QWindowSystemInterfacePrivate::fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, + const QWindow *window, + QEvent::Type *type) { QList<QTouchEvent::TouchPoint> touchPoints; Qt::TouchPointStates states; QTouchEvent::TouchPoint p; + touchPoints.reserve(points.count()); QList<QWindowSystemInterface::TouchPoint>::const_iterator point = points.constBegin(); QList<QWindowSystemInterface::TouchPoint>::const_iterator end = points.constEnd(); while (point != end) { @@ -479,16 +459,16 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints p.setState(point->state); const QPointF screenPos = point->area.center(); - p.setScreenPos(screenPos); - p.setScreenRect(point->area); + p.setScreenPos(QHighDpi::fromNativePixels(screenPos, window)); + p.setScreenRect(QHighDpi::fromNativePixels(point->area, window)); // The local pos and rect are not set, they will be calculated // when the event gets processed by QGuiApplication. - p.setNormalizedPos(point->normalPosition); - p.setVelocity(point->velocity); + p.setNormalizedPos(QHighDpi::fromNativePixels(point->normalPosition, window)); + p.setVelocity(QHighDpi::fromNativePixels(point->velocity, window)); p.setFlags(point->flags); - p.setRawScreenPositions(point->rawPositions); + p.setRawScreenPositions(QHighDpi::fromNativePixels(point->rawPositions, window)); touchPoints.append(p); ++point; @@ -506,6 +486,27 @@ QList<QTouchEvent::TouchPoint> QWindowSystemInterfacePrivate::convertTouchPoints return touchPoints; } +QList<QWindowSystemInterface::TouchPoint> + QWindowSystemInterfacePrivate::toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, + const QWindow *window) +{ + QList<QWindowSystemInterface::TouchPoint> newList; + newList.reserve(pointList.size()); + foreach (const QTouchEvent::TouchPoint &pt, pointList) { + QWindowSystemInterface::TouchPoint p; + p.id = pt.id(); + p.flags = pt.flags(); + p.normalPosition = QHighDpi::toNativeLocalPosition(pt.normalizedPos(), window); + p.area = QHighDpi::toNativePixels(pt.screenRect(), window); + p.pressure = pt.pressure(); + p.state = pt.state(); + p.velocity = pt.velocity(); + p.rawPositions = pt.rawScreenPositions(); + newList.append(p); + } + return newList; +} + void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTouchDevice *device, const QList<TouchPoint> &points, Qt::KeyboardModifiers mods) { @@ -516,7 +517,7 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo return; QEvent::Type type; - QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::convertTouchPoints(points, &type); + QList<QTouchEvent::TouchPoint> touchPoints = QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, tlw, &type); QWindowSystemInterfacePrivate::TouchEvent *e = new QWindowSystemInterfacePrivate::TouchEvent(tlw, timestamp, type, device, touchPoints, mods); @@ -549,14 +550,14 @@ void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt:: void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const QRect &geometry, const QRect &availableGeometry) { QWindowSystemInterfacePrivate::ScreenGeometryEvent *e = - new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, geometry, availableGeometry); + new QWindowSystemInterfacePrivate::ScreenGeometryEvent(screen, QHighDpi::fromNativeScreenGeometry(geometry, screen), QHighDpi::fromNative(availableGeometry, screen, geometry.topLeft())); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY) { QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e = - new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); + new QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent(screen, dpiX, dpiY); // ### tja QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -575,7 +576,7 @@ void QWindowSystemInterface::handleThemeChange(QWindow *tlw) void QWindowSystemInterface::handleExposeEvent(QWindow *tlw, const QRegion ®ion) { - QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, region); + QWindowSystemInterfacePrivate::ExposeEvent *e = new QWindowSystemInterfacePrivate::ExposeEvent(tlw, QHighDpi::fromNativeLocalRegion(region, tlw)); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -584,30 +585,37 @@ void QWindowSystemInterface::deferredFlushWindowSystemEvents(QEventLoop::Process Q_ASSERT(QThread::currentThread() == QGuiApplication::instance()->thread()); QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex); - flushWindowSystemEvents(flags); + sendWindowSystemEvents(flags); QWindowSystemInterfacePrivate::eventsFlushed.wakeOne(); } -void QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags) +/*! + Make Qt Gui process all events on the event queue immediately. Return the + accepted state for the last event on the queue. +*/ +bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags) { const int count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count(); if (!count) - return; + return false; if (!QGuiApplication::instance()) { qWarning().nospace() << "QWindowSystemInterface::flushWindowSystemEvents() invoked after " "QGuiApplication destruction, discarding " << count << " events."; QWindowSystemInterfacePrivate::windowSystemEventQueue.clear(); - return; + return false; } if (QThread::currentThread() != QGuiApplication::instance()->thread()) { + // Post a FlushEvents event which will trigger a call back to + // deferredFlushWindowSystemEvents from the Gui thread. QMutexLocker locker(&QWindowSystemInterfacePrivate::flushEventMutex); QWindowSystemInterfacePrivate::FlushEventsEvent *e = new QWindowSystemInterfacePrivate::FlushEventsEvent(flags); - QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); + QWindowSystemInterfacePrivate::postWindowSystemEvent(e); QWindowSystemInterfacePrivate::eventsFlushed.wait(&QWindowSystemInterfacePrivate::flushEventMutex); } else { sendWindowSystemEvents(flags); } + return QWindowSystemInterfacePrivate::eventAccepted.load() > 0; } bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags) @@ -621,17 +629,42 @@ bool QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::ProcessEventsFla QWindowSystemInterfacePrivate::getWindowSystemEvent(); if (!event) break; - nevents++; - QGuiApplicationPrivate::processWindowSystemEvent(event); + + if (QWindowSystemInterfacePrivate::eventHandler) { + if (QWindowSystemInterfacePrivate::eventHandler->sendEvent(event)) + nevents++; + } else { + nevents++; + QGuiApplicationPrivate::processWindowSystemEvent(event); + } + + // Record the accepted state for the processed event + // (excluding flush events). This state can then be + // returned by flushWindowSystemEvents(). + if (event->type != QWindowSystemInterfacePrivate::FlushEvents) + QWindowSystemInterfacePrivate::eventAccepted.store(event->eventAccepted); + delete event; } return (nevents > 0); } -void QWindowSystemInterface::setSynchronousWindowsSystemEvents(bool enable) +void QWindowSystemInterfacePrivate::installWindowSystemEventHandler(QWindowSystemEventHandler *handler) +{ + if (!eventHandler) + eventHandler = handler; +} + +void QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(QWindowSystemEventHandler *handler) +{ + if (eventHandler == handler) + eventHandler = 0; +} + +void QWindowSystemInterface::setSynchronousWindowSystemEvents(bool enable) { - QWindowSystemInterfacePrivate::synchronousWindowsSystemEvents = enable; + QWindowSystemInterfacePrivate::synchronousWindowSystemEvents = enable; } int QWindowSystemInterface::windowSystemEventsQueued() @@ -642,12 +675,12 @@ int QWindowSystemInterface::windowSystemEventsQueued() #ifndef QT_NO_DRAGANDDROP QPlatformDragQtResponse QWindowSystemInterface::handleDrag(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrag(w, dropData, p,supportedActions); + return QGuiApplicationPrivate::processDrag(w, dropData, QHighDpi::fromNativeLocalPosition(p, w) ,supportedActions); } QPlatformDropQtResponse QWindowSystemInterface::handleDrop(QWindow *w, const QMimeData *dropData, const QPoint &p, Qt::DropActions supportedActions) { - return QGuiApplicationPrivate::processDrop(w, dropData, p,supportedActions); + return QGuiApplicationPrivate::processDrop(w, dropData, QHighDpi::fromNativeLocalPosition(p, w),supportedActions); } #endif // QT_NO_DRAGANDDROP @@ -681,8 +714,11 @@ void QWindowSystemInterface::handleTabletEvent(QWindow *w, ulong timestamp, cons Qt::KeyboardModifiers modifiers) { QWindowSystemInterfacePrivate::TabletEvent *e = - new QWindowSystemInterfacePrivate::TabletEvent(w, timestamp, local, global, device, pointerType, buttons, pressure, - xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers); + new QWindowSystemInterfacePrivate::TabletEvent(w,timestamp, + QHighDpi::fromNativeLocalPosition(local, w), + QHighDpi::fromNativePixels(global, w), + device, pointerType, buttons, pressure, + xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -807,18 +843,60 @@ Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPo } #endif -Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF & local, const QPointF & global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier) { - QWindowSystemInterface::handleMouseEvent(w, local, global, b, mods); +// The following functions are used by testlib, and need to be synchronous to avoid +// race conditions with plugins delivering native events from secondary threads. + +Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp) +{ + bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; + QWindowSystemInterface::setSynchronousWindowSystemEvents(true); + QWindowSystemInterface::handleMouseEvent(w, timestamp, local, global, b, mods); + QWindowSystemInterface::setSynchronousWindowSystemEvents(wasSynchronous); } Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1) { + bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; + QWindowSystemInterface::setSynchronousWindowSystemEvents(true); QWindowSystemInterface::handleKeyEvent(w, t, k, mods, text, autorep, count); + QWindowSystemInterface::setSynchronousWindowSystemEvents(wasSynchronous); } -Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1) +Q_GUI_EXPORT bool qt_handleShortcutEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1) { - return QWindowSystemInterface::tryHandleShortcutEventToObject(o, timestamp, k, mods, text, autorep, count); +#ifndef QT_NO_SHORTCUT + + // FIXME: This method should not allow targeting a specific object, but should + // instead forward the event to a window, which then takes care of normal event + // propagation. We need to fix a lot of tests before we can refactor this (the + // window needs to be exposed and active and have a focus object), so we leave + // it as is for now. See QTBUG-48577. + + QGuiApplicationPrivate::modifier_buttons = mods; + + QKeyEvent qevent(QEvent::ShortcutOverride, k, mods, text, autorep, count); + qevent.setTimestamp(timestamp); + + QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap; + if (shortcutMap.state() == QKeySequence::NoMatch) { + // Try sending as QKeyEvent::ShortcutOverride first + QCoreApplication::sendEvent(o, &qevent); + if (qevent.isAccepted()) + return false; + } + + // Then as QShortcutEvent + return shortcutMap.tryShortcut(&qevent); +#else + Q_UNUSED(o) + Q_UNUSED(timestamp) + Q_UNUSED(k) + Q_UNUSED(mods) + Q_UNUSED(text) + Q_UNUSED(autorep) + Q_UNUSED(count) + return false; +#endif } static QWindowSystemInterface::TouchPoint touchPoint(const QTouchEvent::TouchPoint& pt) @@ -839,17 +917,31 @@ static QList<struct QWindowSystemInterface::TouchPoint> touchPointList(const QLi QList<struct QWindowSystemInterface::TouchPoint> newList; Q_FOREACH (QTouchEvent::TouchPoint p, pointList) - { newList.append(touchPoint(p)); - } + return newList; } -Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *w, QTouchDevice *device, +Q_GUI_EXPORT void qt_handleTouchEvent(QWindow *w, QTouchDevice *device, const QList<QTouchEvent::TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier) { + bool wasSynchronous = QWindowSystemInterfacePrivate::synchronousWindowSystemEvents; + QWindowSystemInterface::setSynchronousWindowSystemEvents(true); QWindowSystemInterface::handleTouchEvent(w, device, touchPointList(points), mods); + QWindowSystemInterface::setSynchronousWindowSystemEvents(wasSynchronous); } +QWindowSystemEventHandler::~QWindowSystemEventHandler() +{ + QWindowSystemInterfacePrivate::removeWindowSystemEventhandler(this); +} + +bool QWindowSystemEventHandler::sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e) +{ + QGuiApplicationPrivate::processWindowSystemEvent(e); + return true; +} + + QT_END_NAMESPACE diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 448c5d0893..a27c68649e 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -78,32 +78,18 @@ public: Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); - static bool tryHandleShortcutOverrideEvent(QWindow *w, QKeyEvent *ev); + static bool handleShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode, + quint32 nativeVirtualKey, quint32 nativeModifiers, const QString & text = QString(), bool autorep = false, ushort count = 1); - static bool tryHandleShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods, - const QString & text = QString(), bool autorep = false, ushort count = 1); - static bool tryHandleShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, - const QString & text = QString(), bool autorep = false, ushort count = 1); + static bool handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); + static bool handleKeyEvent(QWindow *w, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); - static bool tryHandleShortcutEventToObject(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, - const QString & text = QString(), bool autorep = false, ushort count = 1); - - static bool tryHandleExtendedShortcutEvent(QWindow *w, int k, Qt::KeyboardModifiers mods, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString & text = QString(), bool autorep = false, ushort count = 1); - static bool tryHandleExtendedShortcutEvent(QWindow *w, ulong timestamp, int k, Qt::KeyboardModifiers mods, - quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, - const QString & text = QString(), bool autorep = false, ushort count = 1); - - static void handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); - static void handleKeyEvent(QWindow *w, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); - - static void handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, + static bool handleExtendedKeyEvent(QWindow *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text = QString(), bool autorep = false, - ushort count = 1); - static void handleExtendedKeyEvent(QWindow *w, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, + ushort count = 1, bool tryShortcutOverride = true); + static bool handleExtendedKeyEvent(QWindow *w, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text = QString(), bool autorep = false, @@ -127,7 +113,8 @@ public: QVector<QPointF> rawPositions; // in screen coordinates }; - static void registerTouchDevice(QTouchDevice *device); + static void registerTouchDevice(const QTouchDevice *device); + static void unregisterTouchDevice(const QTouchDevice *device); static void handleTouchEvent(QWindow *w, QTouchDevice *device, const QList<struct TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier); static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device, @@ -212,8 +199,8 @@ public: // For event dispatcher implementations static bool sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags); - static void setSynchronousWindowsSystemEvents(bool enable); - static void flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); + static void setSynchronousWindowSystemEvents(bool enable); + static bool flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents); static void deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags); static int windowSystemEventsQueued(); }; diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 2ec402a1e9..e48d1e965b 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -51,9 +51,12 @@ #include <QMutex> #include <QList> #include <QWaitCondition> +#include <QAtomicInt> QT_BEGIN_NAMESPACE +class QWindowSystemEventHandler; + class Q_GUI_EXPORT QWindowSystemInterfacePrivate { public: enum EventType { @@ -99,7 +102,7 @@ public: }; explicit WindowSystemEvent(EventType t) - : type(t), flags(0) { } + : type(t), flags(0), eventAccepted(true) { } virtual ~WindowSystemEvent() { } bool synthetic() const { return flags & Synthetic; } @@ -107,6 +110,7 @@ public: EventType type; int flags; + bool eventAccepted; }; class CloseEvent : public WindowSystemEvent { @@ -478,15 +482,33 @@ public: static WindowSystemEvent *getNonUserInputWindowSystemEvent(); static WindowSystemEvent *peekWindowSystemEvent(EventType t); static void removeWindowSystemEvent(WindowSystemEvent *event); - static void handleWindowSystemEvent(WindowSystemEvent *ev); + static void postWindowSystemEvent(WindowSystemEvent *ev); + static bool handleWindowSystemEvent(WindowSystemEvent *ev); static QElapsedTimer eventTime; - static bool synchronousWindowsSystemEvents; + static bool synchronousWindowSystemEvents; static QWaitCondition eventsFlushed; static QMutex flushEventMutex; + static QAtomicInt eventAccepted; + + static QList<QTouchEvent::TouchPoint> + fromNativeTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, + const QWindow *window, QEvent::Type *type = Q_NULLPTR); + static QList<QWindowSystemInterface::TouchPoint> + toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, + const QWindow *window); + + static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler); + static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler); + static QWindowSystemEventHandler *eventHandler; +}; - static QList<QTouchEvent::TouchPoint> convertTouchPoints(const QList<QWindowSystemInterface::TouchPoint> &points, QEvent::Type *type); +class Q_GUI_EXPORT QWindowSystemEventHandler +{ +public: + virtual ~QWindowSystemEventHandler(); + virtual bool sendEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *event); }; QT_END_NAMESPACE |