diff options
Diffstat (limited to 'src/plugins')
32 files changed, 355 insertions, 332 deletions
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index fcc08ea00d..ca16efe34f 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -110,6 +110,8 @@ public: static AssetItem::Type fileType(const QString &filePath) { + if (filePath.isEmpty()) + return AssetItem::Type::Folder; const QStringList paths = filePath.split(QLatin1Char('/')); QString fullPath; AssetItem::Type res = AssetItem::Type::Invalid; @@ -146,7 +148,7 @@ public: jobjectArray jFiles = static_cast<jobjectArray>(files.object()); const jint nFiles = env->GetArrayLength(jFiles); for (int i = 0; i < nFiles; ++i) { - AssetItem item{QJNIObjectPrivate(env->GetObjectArrayElement(jFiles, i)).toString()}; + AssetItem item{QJNIObjectPrivate::fromLocalRef(env->GetObjectArrayElement(jFiles, i)).toString()}; insert(std::upper_bound(begin(), end(), item, [](const auto &a, const auto &b){ return a.name < b.name; }), item); @@ -399,7 +401,8 @@ public: private: AAsset *m_assetFile = nullptr; AAssetManager *m_assetManager = nullptr; - QString m_fileName; + // initialize with a name that can't be used as a file name + QString m_fileName = QLatin1String("."); bool m_isFolder = false; }; diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp index 4fb271a75c..fb979ab6cc 100644 --- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp @@ -100,10 +100,14 @@ bool QAndroidPlatformFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::Win void QAndroidPlatformFileDialogHelper::exec() { + m_eventLoop.exec(QEventLoop::DialogExec); } void QAndroidPlatformFileDialogHelper::hide() { + if (m_eventLoop.isRunning()) + m_eventLoop.exit(); + QtAndroidPrivate::unregisterActivityResultListener(this); } QString QAndroidPlatformFileDialogHelper::selectedNameFilter() const diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h index e445aa2fef..5cd26af7c9 100644 --- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h +++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.h @@ -41,6 +41,7 @@ #define QANDROIDPLATFORMFILEDIALOGHELPER_H #include <jni.h> +#include <QEventLoop> #include <qpa/qplatformdialoghelper.h> #include <QtCore/private/qjnihelpers_p.h> @@ -72,6 +73,7 @@ public: bool handleActivityResult(jint requestCode, jint resultCode, jobject data) override; private: + QEventLoop m_eventLoop; QUrl m_selectedFile; }; diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index ae584965e6..592b78d936 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -77,6 +77,8 @@ #include "qandroidplatformvulkaninstance.h" #endif +#include <QtGui/qpa/qplatforminputcontextfactory_p.h> + QT_BEGIN_NAMESPACE int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320; @@ -258,6 +260,15 @@ static bool needsBasicRenderloopWorkaround() return needsWorkaround; } +void QAndroidPlatformIntegration::initialize() +{ + const QString icStr = QPlatformInputContextFactory::requested(); + if (icStr.isNull()) + m_inputContext.reset(new QAndroidInputContext); + else + m_inputContext.reset(QPlatformInputContextFactory::create(icStr)); +} + bool QAndroidPlatformIntegration::hasCapability(Capability cap) const { switch (cap) { @@ -374,7 +385,7 @@ QPlatformClipboard *QAndroidPlatformIntegration::clipboard() const QPlatformInputContext *QAndroidPlatformIntegration::inputContext() const { - return &m_platformInputContext; + return m_inputContext.data(); } QPlatformNativeInterface *QAndroidPlatformIntegration::nativeInterface() const diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index c795c499bc..ecbde4f951 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -81,6 +81,8 @@ public: QAndroidPlatformIntegration(const QStringList ¶mList); ~QAndroidPlatformIntegration(); + void initialize() override; + bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; @@ -167,7 +169,7 @@ private: mutable QPlatformAccessibility *m_accessibility; #endif - mutable QAndroidInputContext m_platformInputContext; + QScopedPointer<QPlatformInputContext> m_inputContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 1e46cd2dde..4bff1de515 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -219,6 +219,8 @@ protected: void toggleFullScreen(); bool isTransitioningToFullScreen() const; + bool startSystemMove() override; + // private: public: // for QNSView friend class QCocoaBackingStore; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index ad232d6d80..28da4fcf5d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -291,6 +291,22 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) // will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm) } +bool QCocoaWindow::startSystemMove() +{ + switch (NSApp.currentEvent.type) { + case NSEventTypeLeftMouseDown: + case NSEventTypeRightMouseDown: + case NSEventTypeOtherMouseDown: + case NSEventTypeMouseMoved: + // The documentation only describes starting a system move + // based on mouse down events, but move events also work. + [m_view.window performWindowDragWithEvent:NSApp.currentEvent]; + return true; + default: + return false; + } +} + void QCocoaWindow::setVisible(bool visible) { qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible; diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm index 0561a826c6..3da4ba5480 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -511,7 +511,7 @@ static void executeBlockWithoutAnimation(Block block) - (void)createLoupe { - // We magnify the the desktop view. But the loupe itself will be added as a child + // We magnify the desktop view. But the loupe itself will be added as a child // of the desktop view's parent, so it doesn't become a part of what we magnify. _loupeLayer = [[self createLoupeLayer] retain]; _loupeLayer.targetView = _desktopView; diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index ce2aa96ca5..cd4af46ef7 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -452,7 +452,7 @@ if (!focusWindow->screen() || focusWindow->screen()->handle() != self.platformScreen) return; - // All decisions are based on the the top level window + // All decisions are based on the top level window focusWindow = qt_window_private(focusWindow)->topLevelWindow(); #ifndef Q_OS_TVOS diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp index 3bd6a86b59..25f7b09a60 100644 --- a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp +++ b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp @@ -94,6 +94,11 @@ void *QQnxNativeInterface::nativeResourceForIntegration(const QByteArray &resour if (resource == "screenContext") return m_integration->screenContext(); +#if QT_CONFIG(opengl) + if (resource.toLower() == "egldisplay") + return m_integration->eglDisplay(); +#endif + return 0; } diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp index f02c2c6ccb..890b01fa3c 100644 --- a/src/plugins/platforms/wasm/qwasmclipboard.cpp +++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp @@ -192,15 +192,12 @@ void QWasmClipboard::initClipboardEvents() permissions.call<val>("query", writePermissionsMap); } -void QWasmClipboard::installEventHandlers(const QString &canvasId) +void QWasmClipboard::installEventHandlers(const emscripten::val &canvas) { if (hasClipboardApi) return; // Fallback path for browsers which do not support direct clipboard access - val document = val::global("document"); - val canvas = document.call<val>("getElementById", QWasmString::fromQString(canvasId)); - canvas.call<void>("addEventListener", val("cut"), val::module_property("qtClipboardCutTo")); canvas.call<void>("addEventListener", val("copy"), diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h index 00aae8fead..3b28e2c381 100644 --- a/src/plugins/platforms/wasm/qwasmclipboard.h +++ b/src/plugins/platforms/wasm/qwasmclipboard.h @@ -36,6 +36,7 @@ #include <QMimeData> #include <emscripten/bind.h> +#include <emscripten/val.h> class QWasmClipboard : public QObject, public QPlatformClipboard { @@ -51,7 +52,7 @@ public: static void qWasmClipboardPaste(QMimeData *mData); void initClipboardEvents(); - void installEventHandlers(const QString &canvasId); + void installEventHandlers(const emscripten::val &canvas); bool hasClipboardApi; void readTextFromClipboard(); void writeTextToClipboard(); diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp index 616456b2fa..61204517ce 100644 --- a/src/plugins/platforms/wasm/qwasmcursor.cpp +++ b/src/plugins/platforms/wasm/qwasmcursor.cpp @@ -57,9 +57,7 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window) htmlCursorName = "auto"; // Set cursor on the canvas - val jsCanvasId = QWasmString::fromQString(QWasmScreen::get(screen)->canvasId()); - val document = val::global("document"); - val canvas = document.call<val>("getElementById", jsCanvasId); + val canvas = QWasmScreen::get(screen)->canvas(); val canvasStyle = canvas["style"]; canvasStyle.set("cursor", val(htmlCursorName.constData())); } diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index d99c202c48..3e6043b083 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -339,8 +339,7 @@ QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen) void QWasmEventTranslator::initEventHandlers() { - QByteArray _canvasId = screen()->canvasId().toUtf8(); - const char *canvasId = _canvasId.constData(); + QByteArray canvasSelector = "#" + screen()->canvasId().toUtf8(); // The Platform Detect: expand coverage and move as needed enum Platform { @@ -355,30 +354,28 @@ void QWasmEventTranslator::initEventHandlers() g_useNaturalScrolling = false; // make this !default on macOS if (emscripten::val::global("window")["safari"].isUndefined()) { - val document = val::global("document"); - val jsCanvasId = QWasmString::fromQString(screen()->canvasId()); - val canvas = document.call<val>("getElementById", jsCanvasId); + val canvas = screen()->canvas(); canvas.call<void>("addEventListener", val("wheel"), val::module_property("qtMouseWheelEvent")); } } - emscripten_set_keydown_callback(canvasId, (void *)this, 1, &keyboard_cb); - emscripten_set_keyup_callback(canvasId, (void *)this, 1, &keyboard_cb); + emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); + emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); - emscripten_set_mousedown_callback(canvasId, (void *)this, 1, &mouse_cb); - emscripten_set_mouseup_callback(canvasId, (void *)this, 1, &mouse_cb); - emscripten_set_mousemove_callback(canvasId, (void *)this, 1, &mouse_cb); + emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); + emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); + emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); - emscripten_set_focus_callback(canvasId, (void *)this, 1, &focus_cb); + emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, 1, &focus_cb); - emscripten_set_wheel_callback(canvasId, (void *)this, 1, &wheel_cb); + emscripten_set_wheel_callback(canvasSelector.constData(), (void *)this, 1, &wheel_cb); - emscripten_set_touchstart_callback(canvasId, (void *)this, 1, &touchCallback); - emscripten_set_touchend_callback(canvasId, (void *)this, 1, &touchCallback); - emscripten_set_touchmove_callback(canvasId, (void *)this, 1, &touchCallback); - emscripten_set_touchcancel_callback(canvasId, (void *)this, 1, &touchCallback); + emscripten_set_touchstart_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchend_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); + emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); } template <typename Event> diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index ce83ad4e2f..d1901d840e 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -69,20 +69,17 @@ static void browserBeforeUnload(emscripten::val) static void addCanvasElement(emscripten::val canvas) { - QString canvasId = QWasmString::toQString(canvas["id"]); - QWasmIntegration::get()->addScreen(canvasId); + QWasmIntegration::get()->addScreen(canvas); } static void removeCanvasElement(emscripten::val canvas) { - QString canvasId = QWasmString::toQString(canvas["id"]); - QWasmIntegration::get()->removeScreen(canvasId); + QWasmIntegration::get()->removeScreen(canvas); } static void resizeCanvasElement(emscripten::val canvas) { - QString canvasId = QWasmString::toQString(canvas["id"]); - QWasmIntegration::get()->resizeScreen(canvasId); + QWasmIntegration::get()->resizeScreen(canvas); } static void qtUpdateDpi() @@ -109,20 +106,18 @@ QWasmIntegration::QWasmIntegration() s_instance = this; // We expect that qtloader.js has populated Module.qtCanvasElements with one or more canvases. - // Also check Module.canvas, which may be set if the emscripen or a custom loader is used. emscripten::val qtCanvaseElements = val::module_property("qtCanvasElements"); - emscripten::val canvas = val::module_property("canvas"); + emscripten::val canvas = val::module_property("canvas"); // TODO: remove for Qt 6.0 if (!qtCanvaseElements.isUndefined()) { int screenCount = qtCanvaseElements["length"].as<int>(); for (int i = 0; i < screenCount; ++i) { - emscripten::val canvas = qtCanvaseElements[i].as<emscripten::val>(); - QString canvasId = QWasmString::toQString(canvas["id"]); - addScreen(canvasId); + addScreen(qtCanvaseElements[i].as<emscripten::val>()); } - } else if (!canvas.isUndefined()){ - QString canvasId = QWasmString::toQString(canvas["id"]); - addScreen(canvasId); + } else if (!canvas.isUndefined()) { + qWarning() << "Module.canvas is deprecated. A future version of Qt will stop reading this property. " + << "Instead, set Module.qtCanvasElements to be an array of canvas elements, or use qtloader.js."; + addScreen(canvas); } emscripten::val::global("window").set("onbeforeunload", val::module_property("qtBrowserBeforeUnload")); @@ -134,13 +129,13 @@ QWasmIntegration::QWasmIntegration() Q_UNUSED(userData); // This resize event is called when the HTML window is resized. Depending - // on the page layout the the canvas(es) might also have been resized, so we + // on the page layout the canvas(es) might also have been resized, so we // update the Qt screen sizes (and canvas render sizes). if (QWasmIntegration *integration = QWasmIntegration::get()) integration->resizeAllScreens(); return 0; }; - emscripten_set_resize_callback(nullptr, nullptr, 1, onWindowResize); + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, 1, onWindowResize); } QWasmIntegration::~QWasmIntegration() @@ -148,8 +143,8 @@ QWasmIntegration::~QWasmIntegration() delete m_fontDb; delete m_desktopServices; - for (auto it = m_screens.constBegin(); it != m_screens.constEnd(); ++it) - QWindowSystemInterface::handleScreenRemoved(*it); + for (const auto &canvasAndScreen : m_screens) + QWindowSystemInterface::handleScreenRemoved(canvasAndScreen.second); m_screens.clear(); s_instance = nullptr; @@ -272,24 +267,37 @@ QPlatformClipboard* QWasmIntegration::clipboard() const return m_clipboard; } -void QWasmIntegration::addScreen(const QString &canvasId) +void QWasmIntegration::addScreen(const emscripten::val &canvas) { - QWasmScreen *screen = new QWasmScreen(canvasId); - m_clipboard->installEventHandlers(canvasId); - m_screens.insert(canvasId, screen); + QWasmScreen *screen = new QWasmScreen(canvas); + m_screens.append(qMakePair(canvas, screen)); + m_clipboard->installEventHandlers(canvas); QWindowSystemInterface::handleScreenAdded(screen); } -void QWasmIntegration::removeScreen(const QString &canvasId) +void QWasmIntegration::removeScreen(const emscripten::val &canvas) { - QWasmScreen *exScreen = m_screens.take(canvasId); + auto it = std::find_if(m_screens.begin(), m_screens.end(), + [&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(canvas); }); + if (it == m_screens.end()) { + qWarning() << "Attempting to remove non-existing screen for canvas" << QWasmString::toQString(canvas["id"]);; + return; + } + QWasmScreen *exScreen = it->second; + m_screens.erase(it); exScreen->destroy(); // clean up before deleting the screen QWindowSystemInterface::handleScreenRemoved(exScreen); } -void QWasmIntegration::resizeScreen(const QString &canvasId) +void QWasmIntegration::resizeScreen(const emscripten::val &canvas) { - m_screens.value(canvasId)->updateQScreenAndCanvasRenderSize(); + auto it = std::find_if(m_screens.begin(), m_screens.end(), + [&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(canvas); }); + if (it == m_screens.end()) { + qWarning() << "Attempting to resize non-existing screen for canvas" << QWasmString::toQString(canvas["id"]);; + return; + } + it->second->updateQScreenAndCanvasRenderSize(); } void QWasmIntegration::updateDpi() @@ -298,15 +306,14 @@ void QWasmIntegration::updateDpi() if (dpi.isUndefined()) return; qreal dpiValue = dpi.as<qreal>(); - for (QWasmScreen *screen : m_screens) - QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->screen(), dpiValue, dpiValue); + for (const auto &canvasAndScreen : m_screens) + QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(canvasAndScreen.second->screen(), dpiValue, dpiValue); } void QWasmIntegration::resizeAllScreens() { - qDebug() << "resizeAllScreens"; - for (QWasmScreen *screen : m_screens) - screen->updateQScreenAndCanvasRenderSize(); + for (const auto &canvasAndScreen : m_screens) + canvasAndScreen.second->updateQScreenAndCanvasRenderSize(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index 2102f5c226..08b68cb5f7 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -40,6 +40,7 @@ #include <emscripten.h> #include <emscripten/html5.h> +#include <emscripten/val.h> QT_BEGIN_NAMESPACE @@ -83,9 +84,9 @@ public: static QWasmIntegration *get() { return s_instance; } static void QWasmBrowserExit(); - void addScreen(const QString &canvasId); - void removeScreen(const QString &canvasId); - void resizeScreen(const QString &canvasId); + void addScreen(const emscripten::val &canvas); + void removeScreen(const emscripten::val &canvas); + void resizeScreen(const emscripten::val &canvas); void resizeAllScreens(); void updateDpi(); @@ -93,8 +94,7 @@ private: mutable QWasmFontDatabase *m_fontDb; mutable QWasmServices *m_desktopServices; mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores; - - QHash<QString, QWasmScreen *> m_screens; + QVector<QPair<emscripten::val, QWasmScreen *>> m_screens; mutable QWasmClipboard *m_clipboard; qreal m_fontDpi = -1; mutable QScopedPointer<QPlatformInputContext> m_inputContext; diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp index 501ab99116..4ddd56fd8c 100644 --- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp +++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp @@ -106,7 +106,8 @@ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(cons attributes.depth = useDepthStencil; attributes.stencil = useDepthStencil; - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId.toUtf8().constData(), &attributes); + QByteArray convasSelector = "#" + canvasId.toUtf8(); + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(convasSelector.constData(), &attributes); return context; } diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index 5e6f94b9ed..a2bcd4fcb4 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -50,15 +50,13 @@ using namespace emscripten; QT_BEGIN_NAMESPACE -QWasmScreen::QWasmScreen(const QString &canvasId) - : m_canvasId(canvasId) - +QWasmScreen::QWasmScreen(const emscripten::val &canvas) + : m_canvas(canvas) { m_compositor = new QWasmCompositor(this); m_eventTranslator = new QWasmEventTranslator(this); updateQScreenAndCanvasRenderSize(); - emscripten::val canvas = emscripten::val::global(m_canvasId.toUtf8().constData()); - canvas.call<void>("focus"); + m_canvas.call<void>("focus"); } QWasmScreen::~QWasmScreen() @@ -91,9 +89,14 @@ QWasmEventTranslator *QWasmScreen::eventTranslator() return m_eventTranslator; } +emscripten::val QWasmScreen::canvas() const +{ + return m_canvas; +} + QString QWasmScreen::canvasId() const { - return m_canvasId; + return QWasmString::toQString(m_canvas["id"]); } QRect QWasmScreen::geometry() const @@ -134,7 +137,7 @@ qreal QWasmScreen::devicePixelRatio() const QString QWasmScreen::name() const { - return m_canvasId; + return canvasId(); } QPlatformCursor *QWasmScreen::cursor() const @@ -180,24 +183,22 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize() // Setting the render size to a value larger than the CSS size enables high-dpi // rendering. - QByteArray canvasId = m_canvasId.toUtf8(); + QByteArray canvasSelector = "#" + canvasId().toUtf8(); double css_width; double css_height; - emscripten_get_element_css_size(canvasId.constData(), &css_width, &css_height); + emscripten_get_element_css_size(canvasSelector.constData(), &css_width, &css_height); QSizeF cssSize(css_width, css_height); QSizeF canvasSize = cssSize * devicePixelRatio(); - val document = val::global("document"); - val canvas = document.call<val>("getElementById", QWasmString::fromQString(m_canvasId)); - canvas.set("width", canvasSize.width()); - canvas.set("height", canvasSize.height()); + m_canvas.set("width", canvasSize.width()); + m_canvas.set("height", canvasSize.height()); QPoint offset; - offset.setX(canvas["offsetTop"].as<int>()); - offset.setY(canvas["offsetLeft"].as<int>()); + offset.setX(m_canvas["offsetTop"].as<int>()); + offset.setY(m_canvas["offsetLeft"].as<int>()); - emscripten::val rect = canvas.call<emscripten::val>("getBoundingClientRect"); + emscripten::val rect = m_canvas.call<emscripten::val>("getBoundingClientRect"); QPoint position(rect["left"].as<int>() - offset.x(), rect["top"].as<int>() - offset.y()); setGeometry(QRect(position, cssSize.toSize())); diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h index fcf693681c..ea7ffc4193 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.h +++ b/src/plugins/platforms/wasm/qwasmscreen.h @@ -37,6 +37,8 @@ #include <QtCore/qscopedpointer.h> #include <QtCore/qtextstream.h> +#include <emscripten/val.h> + QT_BEGIN_NAMESPACE class QPlatformOpenGLContext; @@ -50,12 +52,13 @@ class QWasmScreen : public QObject, public QPlatformScreen { Q_OBJECT public: - QWasmScreen(const QString &canvasId); + QWasmScreen(const emscripten::val &canvas); ~QWasmScreen(); void destroy(); static QWasmScreen *get(QPlatformScreen *screen); static QWasmScreen *get(QScreen *screen); + emscripten::val canvas() const; QString canvasId() const; QWasmCompositor *compositor(); @@ -80,7 +83,7 @@ public slots: void setGeometry(const QRect &rect); private: - QString m_canvasId; + emscripten::val m_canvas; QWasmCompositor *m_compositor = nullptr; QWasmEventTranslator *m_eventTranslator = nullptr; QRect m_geometry = QRect(0, 0, 100, 100); diff --git a/src/plugins/platforms/wasm/qwasmstring.cpp b/src/plugins/platforms/wasm/qwasmstring.cpp index 05b571c459..b1be405eeb 100644 --- a/src/plugins/platforms/wasm/qwasmstring.cpp +++ b/src/plugins/platforms/wasm/qwasmstring.cpp @@ -52,9 +52,10 @@ QString QWasmString::toQString(const val &v) val::global("Module")["stringToUTF16"]); static const val length("length"); - result.resize(v[length].as<int>()); + int len = v[length].as<int>(); + result.resize(len); auto ptr = quintptr(result.utf16()); - stringToUTF16(v, val(ptr)); + stringToUTF16(v, val(ptr), val((len + 1) * 2)); return result; } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index d22cc75647..ee65b393d4 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1946,12 +1946,13 @@ void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode) if (newScreen == nullptr || newScreen == currentScreen) return; // For screens with different DPI: postpone until WM_DPICHANGE - if (mode == FromGeometryChange + // Check on currentScreen as it can be 0 when resuming a session (QTBUG-80436). + if (mode == FromGeometryChange && currentScreen != nullptr && !equalDpi(currentScreen->logicalDpi(), newScreen->logicalDpi())) { return; } qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ - << ' ' << window() << " \"" << currentScreen->name() + << ' ' << window() << " \"" << (currentScreen ? currentScreen->name() : QString()) << "\"->\"" << newScreen->name() << '"'; if (mode == FromGeometryChange) setFlag(SynchronousGeometryChangeEvent); @@ -2604,37 +2605,41 @@ bool QWindowsWindow::setMouseGrabEnabled(bool grab) return grab; } -static inline DWORD cornerToWinOrientation(Qt::Corner corner) +static inline DWORD edgesToWinOrientation(Qt::Edges edges) { - switch (corner) { - case Qt::TopLeftCorner: - return 0xf004; // SZ_SIZETOPLEFT; - case Qt::TopRightCorner: - return 0xf005; // SZ_SIZETOPRIGHT - case Qt::BottomLeftCorner: - return 0xf007; // SZ_SIZEBOTTOMLEFT - case Qt::BottomRightCorner: - return 0xf008; // SZ_SIZEBOTTOMRIGHT - } - return 0; + if (edges == Qt::LeftEdge) + return 0xf001; // SC_SIZELEFT; + else if (edges == (Qt::RightEdge)) + return 0xf002; // SC_SIZERIGHT + else if (edges == (Qt::TopEdge)) + return 0xf003; // SC_SIZETOP + else if (edges == (Qt::TopEdge | Qt::LeftEdge)) + return 0xf004; // SC_SIZETOPLEFT + else if (edges == (Qt::TopEdge | Qt::RightEdge)) + return 0xf005; // SC_SIZETOPRIGHT + else if (edges == (Qt::BottomEdge)) + return 0xf006; // SC_SIZEBOTTOM + else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) + return 0xf007; // SC_SIZEBOTTOMLEFT + else if (edges == (Qt::BottomEdge | Qt::RightEdge)) + return 0xf008; // SC_SIZEBOTTOMRIGHT + + return 0xf000; // SC_SIZE } -bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner) +bool QWindowsWindow::startSystemResize(Qt::Edges edges) { - if (!GetSystemMenu(m_data.hwnd, FALSE)) + if (Q_UNLIKELY(!(window()->flags() & Qt::MSWindowsFixedSizeDialogHint))) return false; ReleaseCapture(); - PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0); + PostMessage(m_data.hwnd, WM_SYSCOMMAND, edgesToWinOrientation(edges), 0); setFlag(SizeGripOperation); return true; } -bool QWindowsWindow::startSystemMove(const QPoint &) +bool QWindowsWindow::startSystemMove() { - if (!GetSystemMenu(m_data.hwnd, FALSE)) - return false; - ReleaseCapture(); PostMessage(m_data.hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0); return true; diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 7c37c6b115..e1f7908687 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -277,8 +277,8 @@ public: bool setMouseGrabEnabled(bool grab) override; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - bool startSystemResize(const QPoint &pos, Qt::Corner corner) override; - bool startSystemMove(const QPoint &pos) override; + bool startSystemResize(Qt::Edges edges) override; + bool startSystemMove() override; void setFrameStrutEventsEnabled(bool enabled) override; bool frameStrutEventsEnabled() const override { return testFlag(FrameStrutEventsEnabled); } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 2d89b971dc..8a4b577d2e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -230,7 +230,7 @@ public: bool xi2MouseEventsDisabled() const; Qt::MouseButton xiToQtMouseButton(uint32_t b); void xi2UpdateScrollingDevices(); - bool startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner); + bool startSystemMoveResizeForTouch(xcb_window_t window, int edges); void abortSystemMoveResizeForTouch(); bool isTouchScreen(int id); @@ -334,7 +334,7 @@ private: xcb_window_t window = XCB_NONE; uint16_t deviceid; uint32_t pointid; - int corner; + int edges; } m_startSystemMoveResizeInfo; const bool m_canGrabServer; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 2d114c51b3..4620f0fd1d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -753,7 +753,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo xcb_input_xi_allow_events(xcb_connection(), XCB_CURRENT_TIME, xiDeviceEvent->deviceid, XCB_INPUT_EVENT_MODE_REJECT_TOUCH, xiDeviceEvent->detail, xiDeviceEvent->event); - window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.corner); + window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.edges); m_startSystemMoveResizeInfo.window = XCB_NONE; } } @@ -787,19 +787,20 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo touchPoint.state = Qt::TouchPointStationary; } -bool QXcbConnection::startSystemMoveResizeForTouchBegin(xcb_window_t window, const QPoint &point, int corner) +bool QXcbConnection::startSystemMoveResizeForTouch(xcb_window_t window, int edges) { QHash<int, TouchDeviceData>::const_iterator devIt = m_touchDevices.constBegin(); for (; devIt != m_touchDevices.constEnd(); ++devIt) { TouchDeviceData deviceData = devIt.value(); if (deviceData.qtTouchDevice->type() == QTouchDevice::TouchScreen) { - QHash<int, QPointF>::const_iterator pointIt = deviceData.pointPressedPosition.constBegin(); - for (; pointIt != deviceData.pointPressedPosition.constEnd(); ++pointIt) { - if (pointIt.value().toPoint() == point) { + auto pointIt = deviceData.touchPoints.constBegin(); + for (; pointIt != deviceData.touchPoints.constEnd(); ++pointIt) { + Qt::TouchPointState state = pointIt.value().state; + if (state == Qt::TouchPointMoved || state == Qt::TouchPointPressed || state == Qt::TouchPointStationary) { m_startSystemMoveResizeInfo.window = window; m_startSystemMoveResizeInfo.deviceid = devIt.key(); m_startSystemMoveResizeInfo.pointid = pointIt.key(); - m_startSystemMoveResizeInfo.corner = corner; + m_startSystemMoveResizeInfo.edges = edges; return true; } } diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 2426b5243a..698be45aa8 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -41,7 +41,6 @@ #include "qxcbwindow.h" #include "qxcbcursor.h" #include "qxcbimage.h" -#include "qxcbintegration.h" #include "qnamespace.h" #include "qxcbxsettings.h" @@ -50,7 +49,6 @@ #include <QDebug> #include <QtAlgorithms> -#include <qpa/qplatformservices.h> #include <qpa/qwindowsysteminterface.h> #include <private/qmath_p.h> #include <QtGui/private/qhighdpiscaling_p.h> @@ -368,15 +366,6 @@ static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray& stri void QXcbVirtualDesktop::readXResources() { - const QPlatformServices *services = QXcbIntegration::instance()->services(); - bool useXftConf = false; - if (services) { - const QList<QByteArray> desktopEnv = services->desktopEnvironment().split(':'); - useXftConf = desktopEnv.contains("GNOME") || desktopEnv.contains("UNITY") || desktopEnv.contains("XFCE"); - } - if (!useXftConf) - return; - int offset = 0; QByteArray resources; while (true) { diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index adca902c69..71ec47b053 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2161,6 +2161,7 @@ QXcbWindow *QXcbWindow::toWindow() { return this; } void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source) { + m_lastPointerPosition = local; connection()->setTime(time); Qt::MouseButton button = type == QEvent::MouseMove ? Qt::NoButton : connection()->button(); QWindowSystemInterface::handleMouseEvent(window(), time, local, global, @@ -2345,45 +2346,65 @@ bool QXcbWindow::windowEvent(QEvent *event) return QPlatformWindow::windowEvent(event); } -bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) +bool QXcbWindow::startSystemResize(Qt::Edges edges) { - return startSystemMoveResize(pos, corner); + return startSystemMoveResize(m_lastPointerPosition, edges); } -bool QXcbWindow::startSystemMove(const QPoint &pos) +bool QXcbWindow::startSystemMove() { - return startSystemMoveResize(pos, 4); + return startSystemMoveResize(m_lastPointerPosition, 16); } -bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int corner) +bool QXcbWindow::startSystemMoveResize(const QPoint &pos, int edges) { - return false; // ### FIXME QTBUG-69716 const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); if (!connection()->wmSupport()->isSupportedByWM(moveResize)) return false; - const QPoint globalPos = QHighDpi::toNativePixels(window()->mapToGlobal(pos), window()->screen()); - // ### FIXME QTBUG-53389 - bool startedByTouch = connection()->startSystemMoveResizeForTouchBegin(m_window, globalPos, corner); + bool startedByTouch = connection()->startSystemMoveResizeForTouch(m_window, edges); if (startedByTouch) { - if (connection()->isUnity() || connection()->isGnome()) { - // These desktops fail to move/resize via _NET_WM_MOVERESIZE (WM bug?). + if (connection()->isUnity()) { + // Unity fails to move/resize via _NET_WM_MOVERESIZE (WM bug?). connection()->abortSystemMoveResizeForTouch(); return false; } - // KWin, Openbox, AwesomeWM have been tested to work with _NET_WM_MOVERESIZE. + // KWin, Openbox, AwesomeWM and Gnome have been tested to work with _NET_WM_MOVERESIZE. } else { // Started by mouse press. if (connection()->isUnity()) return false; // _NET_WM_MOVERESIZE on this WM is bouncy (WM bug?). - doStartSystemMoveResize(globalPos, corner); + doStartSystemMoveResize(mapToGlobal(pos), edges); } return true; } -void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner) +static uint qtEdgesToXcbMoveResizeDirection(Qt::Edges edges) +{ + if (edges == (Qt::TopEdge | Qt::LeftEdge)) + return 0; + if (edges == Qt::TopEdge) + return 1; + if (edges == (Qt::TopEdge | Qt::RightEdge)) + return 2; + if (edges == Qt::RightEdge) + return 3; + if (edges == (Qt::RightEdge | Qt::BottomEdge)) + return 4; + if (edges == Qt::BottomEdge) + return 5; + if (edges == (Qt::BottomEdge | Qt::LeftEdge)) + return 6; + if (edges == Qt::LeftEdge) + return 7; + + qWarning() << "Cannot convert " << edges << "to _NET_WM_MOVERESIZE direction."; + return 0; +} + +void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int edges) { const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); xcb_client_message_event_t xev; @@ -2394,16 +2415,10 @@ void QXcbWindow::doStartSystemMoveResize(const QPoint &globalPos, int corner) xev.format = 32; xev.data.data32[0] = globalPos.x(); xev.data.data32[1] = globalPos.y(); - if (corner == 4) { + if (edges == 16) xev.data.data32[2] = 8; // move - } else { - const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner; - const bool left = corner == Qt::BottomLeftCorner || corner == Qt::TopLeftCorner; - if (bottom) - xev.data.data32[2] = left ? 6 : 4; // bottomleft/bottomright - else - xev.data.data32[2] = left ? 0 : 2; // topleft/topright - } + else + xev.data.data32[2] = qtEdgesToXcbMoveResizeDirection(Qt::Edges(edges)); xev.data.data32[3] = XCB_BUTTON_INDEX_1; xev.data.data32[4] = 0; xcb_ungrab_pointer(connection()->xcb_connection(), XCB_CURRENT_TIME); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 976a442b11..d6f370eebe 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -107,8 +107,8 @@ public: bool windowEvent(QEvent *event) override; - bool startSystemResize(const QPoint &pos, Qt::Corner corner) override; - bool startSystemMove(const QPoint &pos) override; + bool startSystemResize(Qt::Edges edges) override; + bool startSystemMove() override; void setOpacity(qreal level) override; void setMask(const QRegion ®ion) override; @@ -168,8 +168,8 @@ public: QXcbScreen *xcbScreen() const; - bool startSystemMoveResize(const QPoint &pos, int corner); - void doStartSystemMoveResize(const QPoint &globalPos, int corner); + bool startSystemMoveResize(const QPoint &pos, int edges); + void doStartSystemMoveResize(const QPoint &globalPos, int edges); static bool isTrayIconWindow(QWindow *window) { @@ -264,6 +264,7 @@ protected: QRegion m_exposeRegion; QSize m_oldWindowSize; + QPoint m_lastPointerPosition; xcb_visualid_t m_visualId = 0; // Last sent state. Initialized to an invalid state, on purpose. diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp index ae213365b7..09c0655f3d 100644 --- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp +++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp @@ -250,7 +250,7 @@ static QDateTime fromTimeStamp(char *buffer) return QDateTime(d, t); } -static ISC_TIME toTime(const QTime &t) +static ISC_TIME toTime(QTime t) { static const QTime midnight(0, 0, 0, 0); return (ISC_TIME)midnight.msecsTo(t) * 10; @@ -266,7 +266,7 @@ static QTime fromTime(char *buffer) return t; } -static ISC_DATE toDate(const QDate &t) +static ISC_DATE toDate(QDate t) { static const QDate basedate(1858, 11, 17); ISC_DATE date; diff --git a/src/plugins/sqldrivers/mysql/mysql.json b/src/plugins/sqldrivers/mysql/mysql.json index 0caaadb7ce..89f5e65fb9 100644 --- a/src/plugins/sqldrivers/mysql/mysql.json +++ b/src/plugins/sqldrivers/mysql/mysql.json @@ -1,3 +1,3 @@ { - "Keys": [ "QMYSQL3", "QMYSQL" ] + "Keys": [ "QMYSQL3", "QMYSQL", "QMARIADB" ] } diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 24efb641f2..e2599e8c6b 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -3096,13 +3096,18 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai bool needTranslation = false; if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave && !qt_mac_applicationIsInDarkMode()) { - // Another surprise from AppKit (SDK 10.14) - -displayRectIgnoringOpacity: - // is different from drawRect: for some Apple-known reason box is smaller - // in height than we need, resulting in tab buttons sitting too high/not - // centered. Attempts to play with insets etc did not work - the same wrong - // height. Simple translation is not working (too much space "at bottom"), - // so we make it bigger and translate (otherwise it's clipped at bottom btw). - adjustedRect.adjust(0, 0, 0, 3); + // In Aqua theme we have to use the 'default' NSBox (as opposite + // to the 'custom' QDarkNSBox we use in dark theme). Since -drawRect: + // does nothing in default NSBox, we call -displayRectIgnoringOpaticty:. + // Unfortunately, the resulting box is smaller then the actual rect we + // wanted. This can be seen, e.g. because tabs (buttons) are misaligned + // vertically and even worse, if QTabWidget has autoFillBackground + // set, this background overpaints NSBox making it to disappear. + // We trick our NSBox to render in a larger rectangle, so that + // the actuall result (which is again smaller than requested), + // more or less is what we really want. We'll have to adjust CTM + // and translate accordingly. + adjustedRect.adjust(0, 0, 6, 6); needTranslation = true; } d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx, const CGRect &rect) { @@ -3117,7 +3122,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai [box drawRect:rect]; } else { if (needTranslation) - CGContextTranslateCTM(ctx, 0.0, 4.0); + CGContextTranslateCTM(ctx, -3.0, 5.0); [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext]; } }); @@ -4613,6 +4618,7 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, case SE_ToolBoxTabContents: rect = QCommonStyle::subElementRect(sr, opt, widget); break; + case SE_PushButtonBevel: case SE_PushButtonContents: if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) { // Comment from the old HITheme days: @@ -4626,9 +4632,20 @@ QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt, const auto ct = cocoaControlType(btn, widget); const auto cs = d->effectiveAquaSizeConstrain(btn, widget); const auto cw = QMacStylePrivate::CocoaControl(ct, cs); - const auto frameRect = cw.adjustedControlFrame(btn->rect); - const auto titleMargins = cw.titleMargins(); - rect = (frameRect - titleMargins).toRect(); + auto frameRect = cw.adjustedControlFrame(btn->rect); + if (sr == SE_PushButtonContents) { + frameRect -= cw.titleMargins(); + } else { + auto *pb = static_cast<NSButton *>(d->cocoaControl(cw)); + if (cw.type != QMacStylePrivate::Button_SquareButton) { + frameRect = QRectF::fromCGRect([pb alignmentRectForFrame:pb.frame]); + if (cw.type == QMacStylePrivate::Button_PushButton) + frameRect -= pushButtonShadowMargins[cw.size]; + else if (cw.type == QMacStylePrivate::Button_PullDown) + frameRect -= pullDownButtonShadowMargins[cw.size]; + } + } + rect = frameRect.toRect(); } break; case SE_HeaderLabel: { diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 9ae8bd6c90..9d143da169 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -665,7 +665,7 @@ static inline bool isFullyOpaque(const XPThemeData &themeData) \note drawBackgroundThruNativeBuffer() can return false for large sizes due to buffer()/CreateDIBSection() failing. */ -bool QWindowsXPStylePrivate::drawBackground(XPThemeData &themeData) +bool QWindowsXPStylePrivate::drawBackground(XPThemeData &themeData, qreal correctionFactor) { if (themeData.rect.isEmpty()) return true; @@ -710,9 +710,9 @@ bool QWindowsXPStylePrivate::drawBackground(XPThemeData &themeData) } const HDC dc = canDrawDirectly ? hdcForWidgetBackingStore(themeData.widget) : nullptr; - const bool result = dc + const bool result = dc && qFuzzyCompare(correctionFactor, qreal(1)) ? drawBackgroundDirectly(dc, themeData, aditionalDevicePixelRatio) - : drawBackgroundThruNativeBuffer(themeData, aditionalDevicePixelRatio); + : drawBackgroundThruNativeBuffer(themeData, aditionalDevicePixelRatio, correctionFactor); painter->restore(); return result; } @@ -786,9 +786,14 @@ bool QWindowsXPStylePrivate::drawBackgroundDirectly(HDC dc, XPThemeData &themeDa other pixmaps etc), or when special transformations are needed (e.g. flips (horizonal mirroring only, vertical are handled by the theme engine). + + \a correctionFactor is an additional factor used to scale up controls + that are too small on High DPI screens, as has been observed for + WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON (QTBUG-75927). */ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeData, - qreal additionalDevicePixelRatio) + qreal additionalDevicePixelRatio, + qreal correctionFactor) { QPainter *painter = themeData.painter; QRectF rectF = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio); @@ -797,7 +802,11 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa rectF = QRectF(0, 0, rectF.height(), rectF.width()); } rectF.moveTo(0, 0); + + const bool hasCorrectionFactor = !qFuzzyCompare(correctionFactor, qreal(1)); QRect rect = rectF.toRect(); + QRect drawRect = hasCorrectionFactor + ? QRectF(rectF.topLeft() / correctionFactor, rectF.size() / correctionFactor).toRect() : rect; int partId = themeData.partId; int stateId = themeData.stateId; int w = rect.width(); @@ -826,6 +835,10 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa pixmapCacheKey.append(QLatin1Char('h')); pixmapCacheKey.append(QString::number(additionalDevicePixelRatio)); pixmapCacheKey.append(QLatin1Char('d')); + if (hasCorrectionFactor) { + pixmapCacheKey.append(QLatin1Char('c')); + pixmapCacheKey.append(QString::number(correctionFactor)); + } QPixmap cachedPixmap; ThemeMapKey key(themeData); @@ -884,7 +897,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa // and DTGB_OMITCONTENT bool addBorderContentClipping = false; QRegion extraClip; - QRect area = rect; + QRect area = drawRect; if (themeData.noBorder || themeData.noContent) { extraClip = area; // We are running on a system where the uxtheme.dll does not have @@ -915,19 +928,19 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa QImage img; if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! ------------------------- - if (!buffer(w, h)) // Ensure a buffer of at least (w, h) in size + if (!buffer(drawRect.width(), drawRect.height())) // Ensure a buffer of at least (w, h) in size return false; HDC dc = bufferHDC(); // Clear the buffer if (alphaType != NoAlpha) { // Consider have separate "memset" function for small chunks for more speedup - memset(bufferPixels, 0x00, bufferW * h * 4); + memset(bufferPixels, 0x00, bufferW * drawRect.height() * 4); } // Difference between area and rect - int dx = area.x() - rect.x(); - int dy = area.y() - rect.y(); + int dx = area.x() - drawRect.x(); + int dy = area.y() - drawRect.y(); // Adjust so painting rect starts from Origo rect.moveTo(0,0); @@ -957,7 +970,7 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa if (!hasAlpha && partIsTransparent) potentialInvalidAlpha = true; #if defined(DEBUG_XP_STYLE) && 1 - dumpNativeDIB(w, h); + dumpNativeDIB(drawRect.width(), drawRect.height()); #endif } @@ -985,6 +998,8 @@ bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeDa printf("Image format is: %s\n", alphaType == RealAlpha ? "Real Alpha" : alphaType == MaskAlpha ? "Masked Alpha" : "No Alpha"); #endif img = QImage(bufferPixels, bufferW, bufferH, format); + if (hasCorrectionFactor) + img = img.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation); img.setDevicePixelRatio(additionalDevicePixelRatio); } @@ -2463,6 +2478,61 @@ QRect QWindowsXPStylePrivate::scrollBarGripperBounds(QStyle::State flags, const return sufficientSpace ? QRect(theme->rect.topLeft() + QPoint(hSpace, vSpace) / 2, size) : QRect(); } +#if QT_CONFIG(mdiarea) +// Helper for drawing MDI buttons into the corner widget of QMenuBar in case a +// QMdiSubWindow is maximized. +static void populateMdiButtonTheme(const QStyle *proxy, const QWidget *widget, + const QStyleOptionComplex *option, + QStyle::SubControl subControl, int part, + XPThemeData *theme) +{ + theme->partId = part; + theme->rect = proxy->subControlRect(QStyle::CC_MdiControls, option, subControl, widget); + if (!option->state.testFlag(QStyle::State_Enabled)) + theme->stateId = CBS_INACTIVE; + else if (option->state.testFlag(QStyle::State_Sunken) && option->activeSubControls.testFlag(subControl)) + theme->stateId = CBS_PUSHED; + else if (option->state.testFlag(QStyle::State_MouseOver) && option->activeSubControls.testFlag(subControl)) + theme->stateId = CBS_HOT; + else + theme->stateId = CBS_NORMAL; +} + +// Calculate an small (max 2), empirical correction factor for scaling up +// WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON, which are too +// small on High DPI screens (QTBUG-75927). +qreal mdiButtonCorrectionFactor(XPThemeData &theme, const QPaintDevice *pd = nullptr) +{ + const auto dpr = pd ? pd->devicePixelRatioF() : qApp->devicePixelRatio(); + const QSizeF nativeSize = QSizeF(theme.size()) / dpr; + const QSizeF requestedSize(theme.rect.size()); + const auto rawFactor = qMin(requestedSize.width() / nativeSize.width(), + requestedSize.height() / nativeSize.height()); + const auto factor = rawFactor >= qreal(2) ? qreal(2) : qreal(1); + return factor; +} +#endif // QT_CONFIG(mdiarea) + +static void populateTitleBarButtonTheme(const QStyle *proxy, const QWidget *widget, + const QStyleOptionComplex *option, + QStyle::SubControl subControl, + bool isTitleBarActive, int part, + XPThemeData *theme) +{ + theme->rect = proxy->subControlRect(QStyle::CC_TitleBar, option, subControl, widget); + theme->partId = part; + if (widget && !widget->isEnabled()) + theme->stateId = RBS_DISABLED; + else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_Sunken)) + theme->stateId = RBS_PUSHED; + else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_MouseOver)) + theme->stateId = RBS_HOT; + else if (!isTitleBarActive) + theme->stateId = RBS_INACTIVE; + else + theme->stateId = RBS_NORMAL; +} + /*! \reimp */ @@ -3024,56 +3094,17 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo if (sub & SC_TitleBarMinButton && tb->titleBarFlags & Qt::WindowMinimizeButtonHint && !(tb->titleBarState & Qt::WindowMinimized)) { - theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarMinButton, widget); - partId = WP_MINBUTTON; - if (widget && !widget->isEnabled()) - stateId = MINBS_DISABLED; - else if (option->activeSubControls == SC_TitleBarMinButton && (option->state & State_Sunken)) - stateId = MINBS_PUSHED; - else if (option->activeSubControls == SC_TitleBarMinButton && (option->state & State_MouseOver)) - stateId = MINBS_HOT; - else if (!isActive) - stateId = MINBS_INACTIVE; - else - stateId = MINBS_NORMAL; - theme.partId = partId; - theme.stateId = stateId; + populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMinButton, isActive, WP_MINBUTTON, &theme); d->drawBackground(theme); } if (sub & SC_TitleBarMaxButton && tb->titleBarFlags & Qt::WindowMaximizeButtonHint && !(tb->titleBarState & Qt::WindowMaximized)) { - theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarMaxButton, widget); - partId = WP_MAXBUTTON; - if (widget && !widget->isEnabled()) - stateId = MAXBS_DISABLED; - else if (option->activeSubControls == SC_TitleBarMaxButton && (option->state & State_Sunken)) - stateId = MAXBS_PUSHED; - else if (option->activeSubControls == SC_TitleBarMaxButton && (option->state & State_MouseOver)) - stateId = MAXBS_HOT; - else if (!isActive) - stateId = MAXBS_INACTIVE; - else - stateId = MAXBS_NORMAL; - theme.partId = partId; - theme.stateId = stateId; + populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarMaxButton, isActive, WP_MAXBUTTON, &theme); d->drawBackground(theme); } if (sub & SC_TitleBarContextHelpButton && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) { - theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarContextHelpButton, widget); - partId = WP_HELPBUTTON; - if (widget && !widget->isEnabled()) - stateId = MINBS_DISABLED; - else if (option->activeSubControls == SC_TitleBarContextHelpButton && (option->state & State_Sunken)) - stateId = MINBS_PUSHED; - else if (option->activeSubControls == SC_TitleBarContextHelpButton && (option->state & State_MouseOver)) - stateId = MINBS_HOT; - else if (!isActive) - stateId = MINBS_INACTIVE; - else - stateId = MINBS_NORMAL; - theme.partId = partId; - theme.stateId = stateId; + populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarContextHelpButton, isActive, WP_HELPBUTTON, &theme); d->drawBackground(theme); } bool drawNormalButton = (sub & SC_TitleBarNormalButton) @@ -3082,74 +3113,21 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint) && (tb->titleBarState & Qt::WindowMaximized))); if (drawNormalButton) { - theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarNormalButton, widget); - partId = WP_RESTOREBUTTON; - if (widget && !widget->isEnabled()) - stateId = RBS_DISABLED; - else if (option->activeSubControls == SC_TitleBarNormalButton && (option->state & State_Sunken)) - stateId = RBS_PUSHED; - else if (option->activeSubControls == SC_TitleBarNormalButton && (option->state & State_MouseOver)) - stateId = RBS_HOT; - else if (!isActive) - stateId = RBS_INACTIVE; - else - stateId = RBS_NORMAL; - theme.partId = partId; - theme.stateId = stateId; + populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarNormalButton, isActive, WP_RESTOREBUTTON, &theme); d->drawBackground(theme); } if (sub & SC_TitleBarShadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint && !(tb->titleBarState & Qt::WindowMinimized)) { - theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarShadeButton, widget); - partId = WP_MINBUTTON; - if (widget && !widget->isEnabled()) - stateId = MINBS_DISABLED; - else if (option->activeSubControls == SC_TitleBarShadeButton && (option->state & State_Sunken)) - stateId = MINBS_PUSHED; - else if (option->activeSubControls == SC_TitleBarShadeButton && (option->state & State_MouseOver)) - stateId = MINBS_HOT; - else if (!isActive) - stateId = MINBS_INACTIVE; - else - stateId = MINBS_NORMAL; - theme.partId = partId; - theme.stateId = stateId; + populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarShadeButton, isActive, WP_MINBUTTON, &theme); d->drawBackground(theme); } if (sub & SC_TitleBarUnshadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint && tb->titleBarState & Qt::WindowMinimized) { - theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarUnshadeButton, widget); - partId = WP_RESTOREBUTTON; - if (widget && !widget->isEnabled()) - stateId = RBS_DISABLED; - else if (option->activeSubControls == SC_TitleBarUnshadeButton && (option->state & State_Sunken)) - stateId = RBS_PUSHED; - else if (option->activeSubControls == SC_TitleBarUnshadeButton && (option->state & State_MouseOver)) - stateId = RBS_HOT; - else if (!isActive) - stateId = RBS_INACTIVE; - else - stateId = RBS_NORMAL; - theme.partId = partId; - theme.stateId = stateId; + populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarUnshadeButton, isActive, WP_RESTOREBUTTON, &theme); d->drawBackground(theme); } if (sub & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) { - theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarCloseButton, widget); - //partId = titlebar->testWFlags(Qt::WA_WState_Tool) ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON; - partId = WP_CLOSEBUTTON; - if (widget && !widget->isEnabled()) - stateId = CBS_DISABLED; - else if (option->activeSubControls == SC_TitleBarCloseButton && (option->state & State_Sunken)) - stateId = CBS_PUSHED; - else if (option->activeSubControls == SC_TitleBarCloseButton && (option->state & State_MouseOver)) - stateId = CBS_HOT; - else if (!isActive) - stateId = CBS_INACTIVE; - else - stateId = CBS_NORMAL; - theme.partId = partId; - theme.stateId = stateId; + populateTitleBarButtonTheme(proxy(), widget, option, SC_TitleBarCloseButton, isActive, WP_CLOSEBUTTON, &theme); d->drawBackground(theme); } } @@ -3159,56 +3137,21 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo #if QT_CONFIG(mdiarea) case CC_MdiControls: { - QRect buttonRect; XPThemeData theme(widget, p, QWindowsXPStylePrivate::WindowTheme, WP_MDICLOSEBUTTON, CBS_NORMAL); + if (Q_UNLIKELY(!theme.isValid())) + return; - if (option->subControls & SC_MdiCloseButton) { - buttonRect = proxy()->subControlRect(CC_MdiControls, option, SC_MdiCloseButton, widget); - if (theme.isValid()) { - theme.partId = WP_MDICLOSEBUTTON; - theme.rect = buttonRect; - if (!(flags & State_Enabled)) - theme.stateId = CBS_INACTIVE; - else if (flags & State_Sunken && (option->activeSubControls & SC_MdiCloseButton)) - theme.stateId = CBS_PUSHED; - else if (flags & State_MouseOver && (option->activeSubControls & SC_MdiCloseButton)) - theme.stateId = CBS_HOT; - else - theme.stateId = CBS_NORMAL; - d->drawBackground(theme); - } + if (option->subControls.testFlag(SC_MdiCloseButton)) { + populateMdiButtonTheme(proxy(), widget, option, SC_MdiCloseButton, WP_MDICLOSEBUTTON, &theme); + d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget)); } - if (option->subControls & SC_MdiNormalButton) { - buttonRect = proxy()->subControlRect(CC_MdiControls, option, SC_MdiNormalButton, widget); - if (theme.isValid()) { - theme.partId = WP_MDIRESTOREBUTTON; - theme.rect = buttonRect; - if (!(flags & State_Enabled)) - theme.stateId = CBS_INACTIVE; - else if (flags & State_Sunken && (option->activeSubControls & SC_MdiNormalButton)) - theme.stateId = CBS_PUSHED; - else if (flags & State_MouseOver && (option->activeSubControls & SC_MdiNormalButton)) - theme.stateId = CBS_HOT; - else - theme.stateId = CBS_NORMAL; - d->drawBackground(theme); - } + if (option->subControls.testFlag(SC_MdiNormalButton)) { + populateMdiButtonTheme(proxy(), widget, option, SC_MdiNormalButton, WP_MDIRESTOREBUTTON, &theme); + d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget)); } - if (option->subControls & QStyle::SC_MdiMinButton) { - buttonRect = proxy()->subControlRect(CC_MdiControls, option, SC_MdiMinButton, widget); - if (theme.isValid()) { - theme.partId = WP_MDIMINBUTTON; - theme.rect = buttonRect; - if (!(flags & State_Enabled)) - theme.stateId = CBS_INACTIVE; - else if (flags & State_Sunken && (option->activeSubControls & SC_MdiMinButton)) - theme.stateId = CBS_PUSHED; - else if (flags & State_MouseOver && (option->activeSubControls & SC_MdiMinButton)) - theme.stateId = CBS_HOT; - else - theme.stateId = CBS_NORMAL; - d->drawBackground(theme); - } + if (option->subControls.testFlag(QStyle::SC_MdiMinButton)) { + populateMdiButtonTheme(proxy(), widget, option, SC_MdiMinButton, WP_MDIMINBUTTON, &theme); + d->drawBackground(theme, mdiButtonCorrectionFactor(theme, widget)); } } break; @@ -3670,19 +3613,20 @@ QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt sz = QWindowsStyle::sizeFromContents(ct, option, sz, widget); break; - case CT_MdiControls: + case CT_MdiControls: { + sz.setHeight(int(QStyleHelper::dpiScaled(19, option))); + int width = 54; if (const QStyleOptionComplex *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(option)) { - int width = 0; + width = 0; if (styleOpt->subControls & SC_MdiMinButton) width += 17 + 1; if (styleOpt->subControls & SC_MdiNormalButton) width += 17 + 1; if (styleOpt->subControls & SC_MdiCloseButton) width += 17 + 1; - sz = QSize(width, 19); - } else { - sz = QSize(54, 19); } + sz.setWidth(int(QStyleHelper::dpiScaled(width, option))); + } break; default: diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h b/src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h index ad7754e3d4..06b37a6e5c 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle_p_p.h @@ -241,8 +241,8 @@ public: bool isTransparent(XPThemeData &themeData); QRegion region(XPThemeData &themeData); - bool drawBackground(XPThemeData &themeData); - bool drawBackgroundThruNativeBuffer(XPThemeData &themeData, qreal aditionalDevicePixelRatio); + bool drawBackground(XPThemeData &themeData, qreal correctionFactor = 1); + bool drawBackgroundThruNativeBuffer(XPThemeData &themeData, qreal aditionalDevicePixelRatio, qreal correctionFactor); bool drawBackgroundDirectly(HDC dc, XPThemeData &themeData, qreal aditionalDevicePixelRatio); bool hasAlphaChannel(const QRect &rect); |