diff options
Diffstat (limited to 'src/plugins/platforms')
49 files changed, 1022 insertions, 95 deletions
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index fd2644717e..1c7800358f 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -900,7 +900,7 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) uenv.venv = nullptr; m_javaVM = nullptr; - if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) { + if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) { __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed"); return -1; } @@ -922,5 +922,5 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) if (threadSetter.thread()) threadSetter.thread()->setObjectName("QtMainLoopThread"); __android_log_print(ANDROID_LOG_INFO, "Qt", "qt started"); - return JNI_VERSION_1_4; + return JNI_VERSION_1_6; } diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 8c4fca0d29..90d5180fed 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -334,7 +334,7 @@ void QCocoaMenu::setEnabled(bool enabled) bool QCocoaMenu::isEnabled() const { - return m_attachedItem ? m_attachedItem.enabled : m_enabled && m_parentEnabled; + return m_enabled && m_parentEnabled; } void QCocoaMenu::setVisible(bool visible) diff --git a/src/plugins/platforms/cocoa/qnsview_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm index a55fd97eb7..b6cd832282 100644 --- a/src/plugins/platforms/cocoa/qnsview_menus.mm +++ b/src/plugins/platforms/cocoa/qnsview_menus.mm @@ -84,7 +84,8 @@ static bool selectorIsCutCopyPaste(SEL selector) menuParent = menuObject->menuParent(); } - if (menubar && menubar->cocoaWindow() != self.platformWindow) + // we have no menubar parent for the application menu items, e.g About and Preferences + if (!menubar || menubar->cocoaWindow() != self.platformWindow) return NO; } diff --git a/src/plugins/platforms/eglfs/api/api.pri b/src/plugins/platforms/eglfs/api/api.pri index a6d81016b6..68965b58d8 100644 --- a/src/plugins/platforms/eglfs/api/api.pri +++ b/src/plugins/platforms/eglfs/api/api.pri @@ -23,4 +23,13 @@ qtConfig(opengl) { $$PWD/qeglfscontext_p.h } +qtConfig(vulkan) { + SOURCES += \ + $$PWD/vulkan/qeglfsvulkaninstance.cpp \ + $$PWD/vulkan/qeglfsvulkanwindow.cpp + HEADERS += \ + $$PWD/vulkan/qeglfsvulkaninstance_p.h \ + $$PWD/vulkan/qeglfsvulkanwindow_p.h +} + INCLUDEPATH += $$PWD diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp index 81bad45cd2..e3145aa0b0 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp @@ -52,6 +52,7 @@ #include <QScreen> #include <QDir> #if QT_CONFIG(regularexpression) +# include <QFileInfo> # include <QRegularExpression> #endif #include <QLoggingCategory> @@ -144,7 +145,12 @@ int QEglFSDeviceIntegration::framebufferIndex() const int fbIndex = 0; #if QT_CONFIG(regularexpression) QRegularExpression fbIndexRx(QLatin1String("fb(\\d+)")); - QRegularExpressionMatch match = fbIndexRx.match(QString::fromLocal8Bit(fbDeviceName())); + QFileInfo fbinfo(QString::fromLocal8Bit(fbDeviceName())); + QRegularExpressionMatch match; + if (fbinfo.isSymLink()) + match = fbIndexRx.match(fbinfo.symLinkTarget()); + else + match = fbIndexRx.match(fbinfo.fileName()); if (match.hasMatch()) fbIndex = match.captured(1).toInt(); #endif @@ -375,6 +381,14 @@ void *QEglFSDeviceIntegration::wlDisplay() const return nullptr; } +#if QT_CONFIG(vulkan) +QPlatformVulkanInstance *QEglFSDeviceIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) +{ + Q_UNUSED(instance); + return nullptr; +} +#endif + EGLConfig QEglFSDeviceIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format) { class Chooser : public QEglConfigChooser { diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h index 71ffb4c69a..08447a40ea 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration_p.h @@ -108,6 +108,10 @@ public: virtual void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen); virtual void *wlDisplay() const; +#if QT_CONFIG(vulkan) + virtual QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance); +#endif + static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format); }; diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index d9a3545a95..e26d984cc1 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -247,6 +247,13 @@ QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOf } #endif // QT_NO_OPENGL +#if QT_CONFIG(vulkan) +QPlatformVulkanInstance *QEglFSIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const +{ + return qt_egl_device_integration()->createPlatformVulkanInstance(instance); +} +#endif + bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const { // We assume that devices will have more and not less capabilities @@ -283,7 +290,8 @@ enum ResourceType { NativeDisplay, XlibDisplay, WaylandDisplay, - EglSurface + EglSurface, + VkSurface }; static int resourceType(const QByteArray &key) @@ -296,7 +304,8 @@ static int resourceType(const QByteArray &key) QByteArrayLiteral("nativedisplay"), QByteArrayLiteral("display"), QByteArrayLiteral("server_wl_display"), - QByteArrayLiteral("eglsurface") + QByteArrayLiteral("eglsurface"), + QByteArrayLiteral("vksurface") }; const QByteArray *end = names + sizeof(names) / sizeof(names[0]); const QByteArray *result = std::find(names, end, key); @@ -364,6 +373,12 @@ void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWi if (window && window->handle()) result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->surface()); break; +#if QT_CONFIG(vulkan) + case VkSurface: + if (window && window->handle() && window->surfaceType() == QSurface::VulkanSurface) + result = static_cast<QEglFSWindow *>(window->handle())->vulkanSurfacePtr(); + break; +#endif default: break; } diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h index 898b322834..b293651ce7 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h @@ -86,6 +86,9 @@ public: QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; #endif +#if QT_CONFIG(vulkan) + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override; +#endif bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformNativeInterface *nativeInterface() const override; diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h index be2a0630d3..7bf74c25ee 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h +++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h @@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE class QOpenGLCompositorBackingStore; class QPlatformTextureList; + #ifndef QT_NO_OPENGL class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow, public QOpenGLCompositorWindow #else @@ -96,6 +97,9 @@ public: EGLNativeWindowType eglWindow() const; EGLSurface surface() const; QEglFSScreen *screen() const override; +#if QT_CONFIG(vulkan) + virtual void *vulkanSurfacePtr() { return nullptr; } +#endif bool hasNativeWindow() const { return m_flags.testFlag(HasNativeWindow); } diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp new file mode 100644 index 0000000000..a75251ca5f --- /dev/null +++ b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance.cpp @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeglfsvulkaninstance_p.h" +#include "qeglfswindow_p.h" +#include "qeglfshooks_p.h" +#include <QLoggingCategory> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(qLcEglDevDebug) + +QEglFSVulkanInstance::QEglFSVulkanInstance(QVulkanInstance *instance) + : m_instance(instance) +{ + loadVulkanLibrary(QStringLiteral("vulkan")); +} + +void QEglFSVulkanInstance::createOrAdoptInstance() +{ + qCDebug(qLcEglDevDebug, "Creating Vulkan instance for VK_KHR_display"); + + const QByteArray extName = QByteArrayLiteral("VK_KHR_display"); + initInstance(m_instance, { extName }); + if (!m_vkInst) + return; + if (!enabledExtensions().contains(extName)) { + qWarning("Failed to enable VK_KHR_display extension"); + return; + } + +#if VK_KHR_display + m_getPhysicalDeviceDisplayPropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR) + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceDisplayPropertiesKHR"); + m_getDisplayModePropertiesKHR = (PFN_vkGetDisplayModePropertiesKHR) + m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayModePropertiesKHR"); + m_getPhysicalDeviceDisplayPlanePropertiesKHR = (PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR) + m_vkGetInstanceProcAddr(m_vkInst, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR"); + + m_getDisplayPlaneSupportedDisplaysKHR = (PFN_vkGetDisplayPlaneSupportedDisplaysKHR) + m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayPlaneSupportedDisplaysKHR"); + m_getDisplayPlaneCapabilitiesKHR = (PFN_vkGetDisplayPlaneCapabilitiesKHR) + m_vkGetInstanceProcAddr(m_vkInst, "vkGetDisplayPlaneCapabilitiesKHR"); + + m_createDisplayPlaneSurfaceKHR = (PFN_vkCreateDisplayPlaneSurfaceKHR) + m_vkGetInstanceProcAddr(m_vkInst, "vkCreateDisplayPlaneSurfaceKHR"); +#endif + + m_enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices) + m_vkGetInstanceProcAddr(m_vkInst, "vkEnumeratePhysicalDevices"); + + // Use for first physical device, unless overridden by QT_VK_PHYSICAL_DEVICE_INDEX. + // This behavior matches what the Vulkan backend of QRhi would do. + + uint32_t physDevCount = 0; + m_enumeratePhysicalDevices(m_vkInst, &physDevCount, nullptr); + if (!physDevCount) { + qWarning("No physical devices"); + return; + } + QVarLengthArray<VkPhysicalDevice, 4> physDevs(physDevCount); + VkResult err = m_enumeratePhysicalDevices(m_vkInst, &physDevCount, physDevs.data()); + if (err != VK_SUCCESS || !physDevCount) { + qWarning("Failed to enumerate physical devices: %d", err); + return; + } + + if (qEnvironmentVariableIsSet("QT_VK_PHYSICAL_DEVICE_INDEX")) { + int requestedPhysDevIndex = qEnvironmentVariableIntValue("QT_VK_PHYSICAL_DEVICE_INDEX"); + if (requestedPhysDevIndex >= 0 && uint32_t(requestedPhysDevIndex) < physDevCount) + m_physDev = physDevs[requestedPhysDevIndex]; + } + + if (m_physDev == VK_NULL_HANDLE) + m_physDev = physDevs[0]; +} + +bool QEglFSVulkanInstance::supportsPresent(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + QWindow *window) +{ + Q_UNUSED(physicalDevice); + Q_UNUSED(queueFamilyIndex); + Q_UNUSED(window); + return true; +} + +VkSurfaceKHR QEglFSVulkanInstance::createSurface(QEglFSWindow *window) +{ +#if VK_KHR_display + qCDebug(qLcEglDevDebug, "Creating VkSurfaceKHR via VK_KHR_display for window %p", (void *) window); + + if (!m_physDev) { + qWarning("No physical device, cannot create surface"); + return VK_NULL_HANDLE; + } + + uint32_t displayCount = 0; + VkResult err = m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, nullptr); + if (err != VK_SUCCESS) { + qWarning("Failed to get display properties: %d", err); + return VK_NULL_HANDLE; + } + + qCDebug(qLcEglDevDebug, "Display count: %u", displayCount); + + QVarLengthArray<VkDisplayPropertiesKHR, 4> displayProps(displayCount); + m_getPhysicalDeviceDisplayPropertiesKHR(m_physDev, &displayCount, displayProps.data()); + + VkDisplayKHR display = VK_NULL_HANDLE; + VkDisplayModeKHR displayMode = VK_NULL_HANDLE; + uint32_t width = 0; + uint32_t height = 0; + + for (uint32_t i = 0; i < displayCount; ++i) { + const VkDisplayPropertiesKHR &disp(displayProps[i]); + qCDebug(qLcEglDevDebug, "Display #%u:\n display: %p\n name: %s\n dimensions: %ux%u\n resolution: %ux%u", + i, (void *) disp.display, disp.displayName, + disp.physicalDimensions.width, disp.physicalDimensions.height, + disp.physicalResolution.width, disp.physicalResolution.height); + + // Just pick the first display and the first mode. + if (i == 0) + display = disp.display; + + uint32_t modeCount = 0; + if (m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, nullptr) != VK_SUCCESS) { + qWarning("Failed to get modes for display"); + continue; + } + QVarLengthArray<VkDisplayModePropertiesKHR, 16> modeProps(modeCount); + m_getDisplayModePropertiesKHR(m_physDev, disp.display, &modeCount, modeProps.data()); + for (uint32_t j = 0; j < modeCount; ++j) { + const VkDisplayModePropertiesKHR &mode(modeProps[j]); + qCDebug(qLcEglDevDebug, " Mode #%u:\n mode: %p\n visibleRegion: %ux%u\n refreshRate: %u", + j, (void *) mode.displayMode, + mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height, + mode.parameters.refreshRate); + if (j == 0) { + displayMode = mode.displayMode; + width = mode.parameters.visibleRegion.width; + height = mode.parameters.visibleRegion.height; + } + } + } + + if (display == VK_NULL_HANDLE || displayMode == VK_NULL_HANDLE) { + qWarning("Failed to choose display and mode"); + return VK_NULL_HANDLE; + } + uint32_t planeCount = 0; + err = m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, nullptr); + if (err != VK_SUCCESS) { + qWarning("Failed to get plane properties: %d", err); + return VK_NULL_HANDLE; + } + + qCDebug(qLcEglDevDebug, "Plane count: %u", planeCount); + + QVarLengthArray<VkDisplayPlanePropertiesKHR, 4> planeProps(planeCount); + m_getPhysicalDeviceDisplayPlanePropertiesKHR(m_physDev, &planeCount, planeProps.data()); + + uint32_t planeIndex = UINT_MAX; + for (uint32_t i = 0; i < planeCount; ++i) { + uint32_t supportedDisplayCount = 0; + err = m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, nullptr); + if (err != VK_SUCCESS) { + qWarning("Failed to query supported displays for plane: %d", err); + return VK_NULL_HANDLE; + } + + QVarLengthArray<VkDisplayKHR, 4> supportedDisplays(supportedDisplayCount); + m_getDisplayPlaneSupportedDisplaysKHR(m_physDev, i, &supportedDisplayCount, supportedDisplays.data()); + qCDebug(qLcEglDevDebug, "Plane #%u supports %u displays, currently bound to display %p", + i, supportedDisplayCount, (void *) planeProps[i].currentDisplay); + + VkDisplayPlaneCapabilitiesKHR caps; + err = m_getDisplayPlaneCapabilitiesKHR(m_physDev, displayMode, i, &caps); + if (err != VK_SUCCESS) { + qWarning("Failed to query plane capabilities: %d", err); + return VK_NULL_HANDLE; + } + + qCDebug(qLcEglDevDebug, " supportedAlpha: %d (1=no, 2=global, 4=per pixel, 8=per pixel premul)\n" + " minSrc=%d, %d %ux%u\n" + " maxSrc=%d, %d %ux%u\n" + " minDst=%d, %d %ux%u\n" + " maxDst=%d, %d %ux%u", + int(caps.supportedAlpha), + caps.minSrcPosition.x, caps.minSrcPosition.y, caps.minSrcExtent.width, caps.minSrcExtent.height, + caps.maxSrcPosition.x, caps.maxSrcPosition.y, caps.maxSrcExtent.width, caps.maxSrcExtent.height, + caps.minDstPosition.x, caps.minDstPosition.y, caps.minDstExtent.width, caps.minDstExtent.height, + caps.maxDstPosition.x, caps.maxDstPosition.y, caps.maxDstExtent.width, caps.maxDstExtent.height); + + // if the plane is not in use and supports our chosen display, use that plane + if (supportedDisplays.contains(display) + && (planeProps[i].currentDisplay == VK_NULL_HANDLE || planeProps[i].currentDisplay == display)) + { + planeIndex = i; + } + } + + if (planeIndex == UINT_MAX) { + qWarning("Failed to find a suitable plane"); + return VK_NULL_HANDLE; + } + + qCDebug(qLcEglDevDebug, "Using plane #%u", planeIndex); + + VkDisplaySurfaceCreateInfoKHR surfaceCreateInfo = {}; + surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR; + surfaceCreateInfo.displayMode = displayMode; + surfaceCreateInfo.planeIndex = planeIndex; + surfaceCreateInfo.planeStackIndex = planeProps[planeIndex].currentStackIndex; + surfaceCreateInfo.transform = VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; + surfaceCreateInfo.globalAlpha = 1.0f; + surfaceCreateInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + surfaceCreateInfo.imageExtent = { width, height }; + + VkSurfaceKHR surface = VK_NULL_HANDLE; + err = m_createDisplayPlaneSurfaceKHR(m_vkInst, &surfaceCreateInfo, nullptr, &surface); + if (err != VK_SUCCESS || surface == VK_NULL_HANDLE) { + qWarning("Failed to create surface: %d", err); + return VK_NULL_HANDLE; + } + + qCDebug(qLcEglDevDebug, "Created surface %p", (void *) surface); + + return surface; + +#else + Q_UNUSED(window); + qWarning("VK_KHR_display support was not compiled in, cannot create surface"); + return VK_NULL_HANDLE; +#endif +} + +void QEglFSVulkanInstance::presentAboutToBeQueued(QWindow *window) +{ + // support QT_QPA_EGLFS_FORCEVSYNC (i.MX8 with eglfs_viv) + qt_egl_device_integration()->waitForVSync(window->handle()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance_p.h b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance_p.h new file mode 100644 index 0000000000..9d6d47f439 --- /dev/null +++ b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkaninstance_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLFSVULKANINSTANCE_H +#define QEGLFSVULKANINSTANCE_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 "qeglfsglobal_p.h" +#include <QtVulkanSupport/private/qbasicvulkanplatforminstance_p.h> + +QT_BEGIN_NAMESPACE + +class QEglFSWindow; + +class Q_EGLFS_EXPORT QEglFSVulkanInstance : public QBasicPlatformVulkanInstance +{ +public: + QEglFSVulkanInstance(QVulkanInstance *instance); + + void createOrAdoptInstance() override; + bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) override; + void presentAboutToBeQueued(QWindow *window) override; + + VkSurfaceKHR createSurface(QEglFSWindow *window); + +private: + QVulkanInstance *m_instance; + VkPhysicalDevice m_physDev = VK_NULL_HANDLE; + PFN_vkEnumeratePhysicalDevices m_enumeratePhysicalDevices = nullptr; +#if VK_KHR_display + PFN_vkGetPhysicalDeviceDisplayPropertiesKHR m_getPhysicalDeviceDisplayPropertiesKHR = nullptr; + PFN_vkGetDisplayModePropertiesKHR m_getDisplayModePropertiesKHR = nullptr; + PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR m_getPhysicalDeviceDisplayPlanePropertiesKHR = nullptr; + PFN_vkGetDisplayPlaneSupportedDisplaysKHR m_getDisplayPlaneSupportedDisplaysKHR = nullptr; + PFN_vkGetDisplayPlaneCapabilitiesKHR m_getDisplayPlaneCapabilitiesKHR = nullptr; + PFN_vkCreateDisplayPlaneSurfaceKHR m_createDisplayPlaneSurfaceKHR = nullptr; +#endif +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow.cpp b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow.cpp new file mode 100644 index 0000000000..ae41ca00b6 --- /dev/null +++ b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeglfsvulkanwindow_p.h" + +QT_BEGIN_NAMESPACE + +QEglFSVulkanWindow::QEglFSVulkanWindow(QWindow *window) + : QEglFSWindow(window), + m_surface(VK_NULL_HANDLE) +{ +} + +QEglFSVulkanWindow::~QEglFSVulkanWindow() +{ + if (m_surface) { + QVulkanInstance *inst = window()->vulkanInstance(); + if (inst) + static_cast<QEglFSVulkanInstance *>(inst->handle())->destroySurface(m_surface); + } +} + +void *QEglFSVulkanWindow::vulkanSurfacePtr() +{ + if (m_surface) + return &m_surface; + + QVulkanInstance *inst = window()->vulkanInstance(); + if (!inst) { + qWarning("Attempted to create Vulkan surface without an instance; was QWindow::setVulkanInstance() called?"); + return nullptr; + } + QEglFSVulkanInstance *eglfsInst = static_cast<QEglFSVulkanInstance *>(inst->handle()); + m_surface = eglfsInst->createSurface(this); + + return &m_surface; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow_p.h b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow_p.h new file mode 100644 index 0000000000..492fb41ca4 --- /dev/null +++ b/src/plugins/platforms/eglfs/api/vulkan/qeglfsvulkanwindow_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLFSVULKANWINDOW_H +#define QEGLFSVULKANWINDOW_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 "qeglfsglobal_p.h" +#include "qeglfswindow_p.h" +#include "qeglfsvulkaninstance_p.h" + +QT_BEGIN_NAMESPACE + +class Q_EGLFS_EXPORT QEglFSVulkanWindow : public QEglFSWindow +{ +public: + QEglFSVulkanWindow(QWindow *window); + ~QEglFSVulkanWindow(); + + void *vulkanSurfacePtr() override; + +private: + VkSurfaceKHR m_surface; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp index 2fc076ad0c..5e1d28a353 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.cpp @@ -41,6 +41,11 @@ #include <EGL/eglvivante.h> #include <QDebug> +#if QT_CONFIG(vulkan) +#include "private/qeglfsvulkaninstance_p.h" +#include "private/qeglfsvulkanwindow_p.h" +#endif + #ifdef Q_OS_INTEGRITY extern "C" void VivanteInit(void); #endif @@ -97,4 +102,20 @@ void QEglFSVivIntegration::destroyNativeWindow(EGLNativeWindowType window) fbDestroyWindow(window); } +#if QT_CONFIG(vulkan) + +QEglFSWindow *QEglFSVivIntegration::createWindow(QWindow *window) const +{ + if (window->surfaceType() == QSurface::VulkanSurface) + return new QEglFSVulkanWindow(window); + return QEglFSDeviceIntegration::createWindow(window); +} + +QPlatformVulkanInstance *QEglFSVivIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) +{ + return new QEglFSVulkanInstance(instance); +} + +#endif // vulkan + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h index 4d1718afcf..02b59c16b5 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_viv/qeglfsvivintegration.h @@ -53,6 +53,12 @@ public: void destroyNativeWindow(EGLNativeWindowType window) override; EGLNativeDisplayType platformDisplay() const override; + // Vulkan support with VK_KHR_display +#if QT_CONFIG(vulkan) + QEglFSWindow *createWindow(QWindow *window) const override; + QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) override; +#endif + private: QSize mScreenSize; EGLNativeDisplayType mNativeDisplay; diff --git a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro index 8bb7b614f1..bd02aea4d3 100644 --- a/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro +++ b/src/plugins/platforms/eglfs/eglfsdeviceintegration.pro @@ -20,6 +20,9 @@ qtHaveModule(input_support-private): \ qtHaveModule(platformcompositor_support-private): \ QT += platformcompositor_support-private +qtConfig(vulkan): \ + QT += vulkan_support-private + # Avoid X11 header collision, use generic EGL native types DEFINES += QT_EGL_NO_X11 diff --git a/src/plugins/platforms/minimalegl/minimalegl.pro b/src/plugins/platforms/minimalegl/minimalegl.pro index b7dde9069f..3f6ae4e248 100644 --- a/src/plugins/platforms/minimalegl/minimalegl.pro +++ b/src/plugins/platforms/minimalegl/minimalegl.pro @@ -21,6 +21,7 @@ HEADERS = qminimaleglintegration.h \ qminimaleglscreen.h qtConfig(opengl) { + QT += opengl SOURCES += qminimaleglbackingstore.cpp HEADERS += qminimaleglbackingstore.h } diff --git a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp index dc8dd74312..2319762f31 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp @@ -40,7 +40,7 @@ #include "qminimaleglbackingstore.h" #include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLPaintDevice> +#include <QtOpenGL/QOpenGLPaintDevice> QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp index 7e8a382512..a7423e9c47 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.cpp +++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp @@ -31,7 +31,7 @@ #include "qwasmwindow.h" #include "qwasmcompositor.h" -#include <QtGui/qopengltexture.h> +#include <QtOpenGL/qopengltexture.h> #include <QtGui/qmatrix4x4.h> #include <QtGui/qpainter.h> #include <private/qguiapplication_p.h> diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp index fb46f1534f..f02c2c6ccb 100644 --- a/src/plugins/platforms/wasm/qwasmclipboard.cpp +++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp @@ -29,6 +29,7 @@ #include "qwasmclipboard.h" #include "qwasmwindow.h" +#include "qwasmstring.h" #include <emscripten.h> #include <emscripten/html5.h> @@ -40,22 +41,22 @@ using namespace emscripten; // there has got to be a better way... -static QByteArray g_clipboardArray; -static QByteArray g_clipboardFormat; +static QString g_clipboardText; +static QString g_clipboardFormat; static val getClipboardData() { - return val(g_clipboardArray.constData()); + return QWasmString::fromQString(g_clipboardText); } static val getClipboardFormat() { - return val(g_clipboardFormat.constData()); + return QWasmString::fromQString(g_clipboardFormat); } static void pasteClipboardData(emscripten::val format, emscripten::val dataPtr) { - QString formatString = QString::fromStdString(format.as<std::string>()); + QString formatString = QWasmString::toQString(format); QByteArray dataArray = QByteArray::fromStdString(dataPtr.as<std::string>()); QMimeData *mMimeData = new QMimeData; mMimeData->setData(formatString, dataArray); @@ -102,11 +103,10 @@ static void qClipboardPasteTo(val event) bool hasClipboardApi = QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi; val clipdata = hasClipboardApi ? val::global("Module").call<val>("qtGetClipboardData") : - event["clipboardData"].call<val>("getData", std::string("text")); + event["clipboardData"].call<val>("getData", val("text")); - const std::string data = clipdata.as<std::string>(); - if (data.length() > 0) { - QString qstr = QString::fromStdString(data); + const QString qstr = QWasmString::toQString(clipdata); + if (qstr.length() > 0) { QMimeData *mMimeData = new QMimeData; mMimeData->setText(qstr); QWasmClipboard::qWasmClipboardPaste(mMimeData); @@ -133,7 +133,7 @@ QWasmClipboard::QWasmClipboard() QWasmClipboard::~QWasmClipboard() { - g_clipboardArray.clear(); + g_clipboardText.clear(); g_clipboardFormat.clear(); } @@ -148,11 +148,11 @@ QMimeData* QWasmClipboard::mimeData(QClipboard::Mode mode) void QWasmClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) { if (mimeData->hasText()) { - g_clipboardFormat = mimeData->formats().at(0).toUtf8(); - g_clipboardArray = mimeData->text().toUtf8(); + g_clipboardFormat = mimeData->formats().at(0); + g_clipboardText = mimeData->text(); } else if (mimeData->hasHtml()) { - g_clipboardFormat =mimeData->formats().at(0).toUtf8(); - g_clipboardArray = mimeData->html().toUtf8(); + g_clipboardFormat = mimeData->formats().at(0); + g_clipboardText = mimeData->html(); } QPlatformClipboard::setMimeData(mimeData, mode); @@ -199,13 +199,13 @@ void QWasmClipboard::installEventHandlers(const QString &canvasId) // Fallback path for browsers which do not support direct clipboard access val document = val::global("document"); - val canvas = document.call<val>("getElementById", val(canvasId.toUtf8().constData())); + val canvas = document.call<val>("getElementById", QWasmString::fromQString(canvasId)); - canvas.call<void>("addEventListener", std::string("cut"), + canvas.call<void>("addEventListener", val("cut"), val::module_property("qtClipboardCutTo")); - canvas.call<void>("addEventListener", std::string("copy"), + canvas.call<void>("addEventListener", val("copy"), val::module_property("qtClipboardCopyTo")); - canvas.call<void>("addEventListener", std::string("paste"), + canvas.call<void>("addEventListener", val("paste"), val::module_property("qtClipboardPasteTo")); } @@ -226,6 +226,6 @@ void QWasmClipboard::writeTextToClipboard() val txt = module.call<val>("qtGetClipboardData"); val format = module.call<val>("qtGetClipboardFormat"); val navigator = val::global("navigator"); - navigator["clipboard"].call<void>("writeText", txt.as<std::string>()); + navigator["clipboard"].call<void>("writeText", txt); } } diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index e9c4559971..6bf0d69770 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -31,7 +31,7 @@ #include "qwasmwindow.h" #include "qwasmstylepixmaps_p.h" -#include <QtGui/qopengltexture.h> +#include <QtOpenGL/qopengltexture.h> #include <QtGui/private/qwindow_p.h> #include <QtGui/qopenglcontext.h> diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 98f4a79b27..6b59d87a0a 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -34,7 +34,6 @@ #include <qpa/qplatformwindow.h> #include <QtGui/qopengltextureblitter.h> -#include <QtGui/qopengltexture.h> #include <QtGui/qpalette.h> #include <QtGui/qpainter.h> @@ -43,6 +42,7 @@ QT_BEGIN_NAMESPACE class QWasmWindow; class QWasmScreen; class QOpenGLContext; +class QOpenGLTexture; class QOpenGLTextureBlitter; class QWasmCompositedWindow diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp index c04fa6441a..616456b2fa 100644 --- a/src/plugins/platforms/wasm/qwasmcursor.cpp +++ b/src/plugins/platforms/wasm/qwasmcursor.cpp @@ -29,6 +29,7 @@ #include "qwasmcursor.h" #include "qwasmscreen.h" +#include "qwasmstring.h" #include <QtCore/qdebug.h> #include <QtGui/qwindow.h> @@ -56,11 +57,11 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window) htmlCursorName = "auto"; // Set cursor on the canvas - QByteArray canvasId = QWasmScreen::get(screen)->canvasId().toUtf8(); + val jsCanvasId = QWasmString::fromQString(QWasmScreen::get(screen)->canvasId()); val document = val::global("document"); - val canvas = document.call<val>("getElementById", val(canvasId.constData())); + val canvas = document.call<val>("getElementById", jsCanvasId); val canvasStyle = canvas["style"]; - canvasStyle.set("cursor", emscripten::val(htmlCursorName.constData())); + canvasStyle.set("cursor", val(htmlCursorName.constData())); } QByteArray QWasmCursor::cursorShapeToHtml(Qt::CursorShape shape) diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp index d89cd78b28..ca8db9b215 100644 --- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp +++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp @@ -33,9 +33,11 @@ #include <emscripten.h> +#if QT_CONFIG(thread) #if (__EMSCRIPTEN_major__ > 1 || __EMSCRIPTEN_minor__ > 38 || __EMSCRIPTEN_minor__ == 38 && __EMSCRIPTEN_tiny__ >= 22) # define EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD #endif +#endif #ifdef EMSCRIPTEN_HAS_ASYNC_RUN_IN_MAIN_RUNTIME_THREAD #include <emscripten/threading.h> diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index d6ea147ccf..d99c202c48 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -32,6 +32,7 @@ #include "qwasmcompositor.h" #include "qwasmintegration.h" #include "qwasmclipboard.h" +#include "qwasmstring.h" #include <QtGui/qevent.h> #include <qpa/qwindowsysteminterface.h> @@ -355,9 +356,10 @@ void QWasmEventTranslator::initEventHandlers() if (emscripten::val::global("window")["safari"].isUndefined()) { val document = val::global("document"); - val canvas = document.call<val>("getElementById", val(canvasId)); + val jsCanvasId = QWasmString::fromQString(screen()->canvasId()); + val canvas = document.call<val>("getElementById", jsCanvasId); canvas.call<void>("addEventListener", - std::string("wheel"), + val("wheel"), val::module_property("qtMouseWheelEvent")); } } diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 1e9f68027c..fd53cd0bae 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -36,6 +36,7 @@ #include "qwasmclipboard.h" #include "qwasmservices.h" #include "qwasmoffscreensurface.h" +#include "qwasmstring.h" #include "qwasmwindow.h" #ifndef QT_NO_OPENGL @@ -67,19 +68,19 @@ static void browserBeforeUnload(emscripten::val) static void addCanvasElement(emscripten::val canvas) { - QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QString canvasId = QWasmString::toQString(canvas["id"]); QWasmIntegration::get()->addScreen(canvasId); } static void removeCanvasElement(emscripten::val canvas) { - QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QString canvasId = QWasmString::toQString(canvas["id"]); QWasmIntegration::get()->removeScreen(canvasId); } static void resizeCanvasElement(emscripten::val canvas) { - QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QString canvasId = QWasmString::toQString(canvas["id"]); QWasmIntegration::get()->resizeScreen(canvasId); } @@ -115,11 +116,11 @@ QWasmIntegration::QWasmIntegration() int screenCount = qtCanvaseElements["length"].as<int>(); for (int i = 0; i < screenCount; ++i) { emscripten::val canvas = qtCanvaseElements[i].as<emscripten::val>(); - QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QString canvasId = QWasmString::toQString(canvas["id"]); addScreen(canvasId); } } else if (!canvas.isUndefined()){ - QString canvasId = QString::fromStdString(canvas["id"].as<std::string>()); + QString canvasId = QWasmString::toQString(canvas["id"]); addScreen(canvasId); } diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index d50765e3fb..5e6f94b9ed 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -32,6 +32,8 @@ #include "qwasmeventtranslator.h" #include "qwasmcompositor.h" #include "qwasmintegration.h" +#include "qwasmstring.h" + #include <emscripten/bind.h> #include <emscripten/val.h> @@ -186,7 +188,7 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize() QSizeF canvasSize = cssSize * devicePixelRatio(); val document = val::global("document"); - val canvas = document.call<val>("getElementById", val(canvasId.constData())); + val canvas = document.call<val>("getElementById", QWasmString::fromQString(m_canvasId)); canvas.set("width", canvasSize.width()); canvas.set("height", canvasSize.height()); diff --git a/src/plugins/platforms/wasm/qwasmservices.cpp b/src/plugins/platforms/wasm/qwasmservices.cpp index 9328b8c065..4eee3fe972 100644 --- a/src/plugins/platforms/wasm/qwasmservices.cpp +++ b/src/plugins/platforms/wasm/qwasmservices.cpp @@ -28,6 +28,8 @@ ****************************************************************************/ #include "qwasmservices.h" +#include "qwasmstring.h" + #include <QtCore/QUrl> #include <QtCore/QDebug> @@ -37,8 +39,8 @@ QT_BEGIN_NAMESPACE bool QWasmServices::openUrl(const QUrl &url) { - QByteArray utf8Url = url.toString().toUtf8(); - emscripten::val::global("window").call<void>("open", emscripten::val(utf8Url.constData()), emscripten::val("_blank")); + emscripten::val jsUrl = QWasmString::fromQString(url.toString()); + emscripten::val::global("window").call<void>("open", jsUrl, emscripten::val("_blank")); return true; } diff --git a/src/plugins/platforms/wasm/qwasmstring.cpp b/src/plugins/platforms/wasm/qwasmstring.cpp new file mode 100644 index 0000000000..05b571c459 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmstring.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwasmstring.h" + +QT_BEGIN_NAMESPACE + +using namespace emscripten; + +val QWasmString::fromQString(const QString &str) +{ + static const val UTF16ToString( + val::global("Module")["UTF16ToString"]); + + auto ptr = quintptr(str.utf16()); + return UTF16ToString(val(ptr)); +} + +QString QWasmString::toQString(const val &v) +{ + QString result; + if (!v.isString()) + return result; + + static const val stringToUTF16( + val::global("Module")["stringToUTF16"]); + static const val length("length"); + + result.resize(v[length].as<int>()); + auto ptr = quintptr(result.utf16()); + stringToUTF16(v, val(ptr)); + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmstring.h b/src/plugins/platforms/wasm/qwasmstring.h new file mode 100644 index 0000000000..de5da92830 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmstring.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include <qstring.h> + +#include <emscripten/val.h> + +QT_BEGIN_NAMESPACE + +class QWasmString +{ +public: + static emscripten::val fromQString(const QString &str); + static QString toQString(const emscripten::val &v); +}; +QT_END_NAMESPACE + diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro index f8c8175525..c8b28fb37d 100644 --- a/src/plugins/platforms/wasm/wasm.pro +++ b/src/plugins/platforms/wasm/wasm.pro @@ -23,7 +23,8 @@ SOURCES = \ qwasmtheme.cpp \ qwasmclipboard.cpp \ qwasmservices.cpp \ - qwasmoffscreensurface.cpp + qwasmoffscreensurface.cpp \ + qwasmstring.cpp HEADERS = \ qwasmintegration.h \ @@ -39,7 +40,8 @@ HEADERS = \ qwasmtheme.h \ qwasmclipboard.h \ qwasmservices.h \ - qwasmoffscreensurface.h + qwasmoffscreensurface.h \ + qwasmstring.h wasmfonts.files = \ ../../../3rdparty/wasm/Vera.ttf \ @@ -50,6 +52,7 @@ wasmfonts.base = ../../../3rdparty/wasm RESOURCES += wasmfonts qtConfig(opengl) { + QT += opengl SOURCES += qwasmbackingstore.cpp HEADERS += qwasmbackingstore.h } diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index ccd4e50a8b..efcb0b6e6e 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -190,7 +190,7 @@ void QWindowsClipboard::releaseIData() void QWindowsClipboard::registerViewer() { m_clipboardViewer = QWindowsContext::instance()-> - createDummyWindow(QStringLiteral("Qt5ClipboardView"), L"Qt5ClipboardView", + createDummyWindow(QStringLiteral("ClipboardView"), L"QtClipboardView", qClipboardViewerWndProc, WS_OVERLAPPED); // Try format listener API (Vista onwards) first. diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 88d3131de2..438a0fbaa4 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -42,6 +42,7 @@ #include "qwindowsintegration.h" #include "qwindowswindow.h" #include "qwindowskeymapper.h" +#include "qwindowsnativeinterface.h" #include "qwindowsmousehandler.h" #include "qwindowspointerhandler.h" #include "qtwindowsglobal.h" @@ -72,6 +73,7 @@ #include <QtCore/qset.h> #include <QtCore/qhash.h> +#include <QtCore/qlibraryinfo.h> #include <QtCore/qstringlist.h> #include <QtCore/qdebug.h> #include <QtCore/qoperatingsystemversion.h> @@ -276,8 +278,11 @@ struct QWindowsContextPrivate { bool m_asyncExpose = false; HPOWERNOTIFY m_powerNotification = nullptr; HWND m_powerDummyWindow = nullptr; + static bool m_darkMode; }; +bool QWindowsContextPrivate::m_darkMode = false; + QWindowsContextPrivate::QWindowsContextPrivate() : m_oleInitializeResult(OleInitialize(nullptr)) { @@ -292,6 +297,7 @@ QWindowsContextPrivate::QWindowsContextPrivate() m_systemInfo |= QWindowsContext::SI_RTL_Extensions; m_keyMapper.setUseRTLExtensions(true); } + m_darkMode = QWindowsTheme::queryDarkMode(); if (FAILED(m_oleInitializeResult)) { qWarning() << "QWindowsContext: OleInitialize() failed: " << QWindowsContext::comErrorString(m_oleInitializeResult); @@ -426,7 +432,7 @@ bool QWindowsContext::initPowerNotificationHandler() if (d->m_powerNotification) return false; - d->m_powerDummyWindow = createDummyWindow(QStringLiteral("QtPowerDummyWindow"), L"QtPowerDummyWindow", qWindowsPowerWindowProc); + d->m_powerDummyWindow = createDummyWindow(QStringLiteral("PowerDummyWindow"), L"QtPowerDummyWindow", qWindowsPowerWindowProc); if (!d->m_powerDummyWindow) return false; @@ -484,6 +490,11 @@ void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiA } } +bool QWindowsContext::isDarkMode() +{ + return QWindowsContextPrivate::m_darkMode; +} + QWindowsContext *QWindowsContext::instance() { return m_instance; @@ -536,6 +547,23 @@ void QWindowsContext::setKeyGrabber(QWindow *w) d->m_keyMapper.setKeyGrabber(w); } +QString QWindowsContext::classNamePrefix() +{ + static QString result; + if (result.isEmpty()) { + QTextStream str(&result); + str << "Qt" << QT_VERSION_MAJOR << QT_VERSION_MINOR << QT_VERSION_PATCH; + if (QLibraryInfo::isDebugBuild()) + str << 'd'; +#ifdef QT_NAMESPACE +# define xstr(s) str(s) +# define str(s) #s + str << xstr(QT_NAMESPACE); +#endif + } + return result; +} + // Window class registering code (from qapplication_win.cpp) QString QWindowsContext::registerWindowClass(const QWindow *w) @@ -567,8 +595,8 @@ QString QWindowsContext::registerWindowClass(const QWindow *w) break; } // Create a unique name for the flag combination - QString cname; - cname += QLatin1String("Qt5QWindow"); + QString cname = classNamePrefix(); + cname += QLatin1String("QWindow"); switch (type) { case Qt::Tool: cname += QLatin1String("Tool"); @@ -878,7 +906,7 @@ HWND QWindowsContext::createDummyWindow(const QString &classNameIn, { if (!wndProc) wndProc = DefWindowProc; - QString className = registerWindowClass(classNameIn, wndProc); + QString className = registerWindowClass(classNamePrefix() + classNameIn, wndProc); return CreateWindowEx(0, reinterpret_cast<LPCWSTR>(className.utf16()), windowName, style, CW_USEDEFAULT, CW_USEDEFAULT, @@ -1185,9 +1213,27 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, t->displayChanged(); QWindowsWindow::displayChanged(); return d->m_screenManager.handleDisplayChange(wParam, lParam); - case QtWindows::SettingChangedEvent: + case QtWindows::SettingChangedEvent: { QWindowsWindow::settingsChanged(); + const bool darkMode = QWindowsTheme::queryDarkMode(); + if (darkMode != QWindowsContextPrivate::m_darkMode) { + QWindowsContextPrivate::m_darkMode = darkMode; + auto nativeInterface = + static_cast<QWindowsNativeInterface *>(QWindowsIntegration::instance()->nativeInterface()); + emit nativeInterface->darkModeChanged(darkMode); + const auto options = QWindowsIntegration::instance()->options(); + if ((options & QWindowsIntegration::DarkModeWindowFrames) != 0) { + for (QWindowsWindow *w : d->m_windows) + w->setDarkBorder(QWindowsContextPrivate::m_darkMode); + } + if ((options & QWindowsIntegration::DarkModeStyle) != 0) { + QWindowsTheme::instance()->refresh(); + for (QWindowsWindow *w : d->m_windows) + QWindowSystemInterface::handleThemeChange(w->window()); + } + } return d->m_screenManager.handleScreenChanges(); + } default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 8027f09389..1831ac6ec0 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -180,6 +180,7 @@ public: int defaultDPI() const; + static QString classNamePrefix(); QString registerWindowClass(const QWindow *w); QString registerWindowClass(QString cname, WNDPROC proc, unsigned style = 0, HBRUSH brush = nullptr, @@ -225,6 +226,8 @@ public: void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); static int processDpiAwareness(); + static bool isDarkMode(); + void setDetectAltGrModifier(bool a); // Returns a combination of SystemInfoFlags diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 59457f1720..19de3d5939 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -80,10 +80,10 @@ QWindowsPixmapCursorCacheKey::QWindowsPixmapCursorCacheKey(const QCursor &c) : bitmapCacheKey(c.pixmap().cacheKey()), maskCacheKey(0) { if (!bitmapCacheKey) { - Q_ASSERT(c.bitmap()); - Q_ASSERT(c.mask()); - bitmapCacheKey = c.bitmap()->cacheKey(); - maskCacheKey = c.mask()->cacheKey(); + Q_ASSERT(!c.bitmap(Qt::ReturnByValue).isNull()); + Q_ASSERT(!c.mask(Qt::ReturnByValue).isNull()); + bitmapCacheKey = c.bitmap(Qt::ReturnByValue).cacheKey(); + maskCacheKey = c.mask(Qt::ReturnByValue).cacheKey(); } } @@ -169,9 +169,9 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits, // Create a cursor from image and mask of the format QImage::Format_Mono. static HCURSOR createBitmapCursor(const QCursor &cursor, qreal scaleFactor = 1) { - Q_ASSERT(cursor.shape() == Qt::BitmapCursor && cursor.bitmap()); - QImage bbits = cursor.bitmap()->toImage(); - QImage mbits = cursor.mask()->toImage(); + Q_ASSERT(cursor.shape() == Qt::BitmapCursor && !cursor.bitmap(Qt::ReturnByValue).isNull()); + QImage bbits = cursor.bitmap(Qt::ReturnByValue).toImage(); + QImage mbits = cursor.mask(Qt::ReturnByValue).toImage(); scaleFactor /= bbits.devicePixelRatioF(); if (!qFuzzyCompare(scaleFactor, 1)) { const QSize scaledSize = (QSizeF(bbits.size()) * scaleFactor).toSize(); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index d9521e7e08..7431f52e8a 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -802,7 +802,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, static inline HWND createDummyGLWindow() { return QWindowsContext::instance()-> - createDummyWindow(QStringLiteral("QtOpenGLDummyWindow"), + createDummyWindow(QStringLiteral("OpenGLDummyWindow"), L"OpenGLDummyWindow", nullptr, WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); } diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 32bd29a842..4b4047ac0c 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -219,6 +219,10 @@ static inline unsigned parseOptions(const QStringList ¶mList, options |= QWindowsIntegration::DontUseWMPointer; } else if (param == u"reverse") { options |= QWindowsIntegration::RtlEnabled; + } else if (param == u"darkmode=1") { + options |= QWindowsIntegration::DarkModeWindowFrames; + } else if (param == u"darkmode=2") { + options |= QWindowsIntegration::DarkModeWindowFrames | QWindowsIntegration::DarkModeStyle; } else { qWarning() << "Unknown option" << param; } diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index b49d21022b..1f16d13769 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -70,7 +70,9 @@ public: NoNativeMenus = 0x200, DontUseWMPointer = 0x400, DetectAltGrModifier = 0x800, - RtlEnabled = 0x1000 + RtlEnabled = 0x1000, + DarkModeWindowFrames = 0x2000, + DarkModeStyle = 0x4000 }; explicit QWindowsIntegration(const QStringList ¶mList); diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index d1d181d66e..1195f15a59 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -47,6 +47,7 @@ #include "qwindowsopengltester.h" #include "qwindowsintegration.h" #include "qwindowsmime.h" +#include "qwindowstheme.h" #include "qwin10helpers.h" #include <QtGui/qwindow.h> @@ -316,4 +317,15 @@ QVariant QWindowsNativeInterface::gpuList() const return result; } +bool QWindowsNativeInterface::isDarkMode() const +{ + return QWindowsContext::isDarkMode(); +} + +// Dark mode support level 2 (style) +bool QWindowsNativeInterface::isDarkModeStyle() const +{ + return (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) != 0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h index ce395dc5a4..90ba7a44c9 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.h +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h @@ -65,6 +65,8 @@ class QWindowsNativeInterface : public QPlatformNativeInterface { Q_OBJECT Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) + Q_PROPERTY(bool darkMode READ isDarkMode STORED false NOTIFY darkModeChanged) + Q_PROPERTY(bool darkModeStyle READ isDarkModeStyle STORED false) Q_PROPERTY(QVariant gpu READ gpu STORED false) Q_PROPERTY(QVariant gpuList READ gpuList STORED false) @@ -92,6 +94,9 @@ public: bool asyncExpose() const; void setAsyncExpose(bool value); + bool isDarkMode() const; + bool isDarkModeStyle() const; + QVariant gpu() const; QVariant gpuList() const; @@ -109,6 +114,9 @@ public: QFunctionPointer platformFunction(const QByteArray &function) const override; +Q_SIGNALS: + void darkModeChanged(bool); + private: static QWindowsWindowFunctions::WindowActivationBehavior m_windowActivationBehavior; }; diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp index 66c558df1e..53562c87dd 100644 --- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp +++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp @@ -168,7 +168,7 @@ static inline HWND createTrayIconMessageWindow() return nullptr; // Register window class in the platform plugin. const QString className = - ctx->registerWindowClass(QStringLiteral("QTrayIconMessageWindowClass"), + ctx->registerWindowClass(QWindowsContext::classNamePrefix() + QStringLiteral("TrayIconMessageWindowClass"), qWindowsTrayIconWndProc); const wchar_t windowName[] = L"QTrayIconMessageWindow"; return CreateWindowEx(0, reinterpret_cast<const wchar_t *>(className.utf16()), diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 010aea2068..325956b7ba 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -63,6 +63,7 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qdebug.h> #include <QtCore/qtextstream.h> +#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qsysinfo.h> #include <QtCore/qcache.h> #include <QtCore/qthread.h> @@ -78,6 +79,7 @@ #include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h> #include <private/qhighdpiscaling_p.h> #include <private/qsystemlibrary_p.h> +#include <private/qwinregistry_p.h> #include <algorithm> @@ -241,6 +243,15 @@ static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes, return result; } +// Dark Mode constants +enum DarkModeColors : QRgb { + darkModeBtnHighlightRgb = 0xc0c0c0, + darkModeBtnShadowRgb = 0x808080, + darkModeHighlightRgb = 0x0055ff, // deviating from 0x800080 + darkModeMenuHighlightRgb = darkModeHighlightRgb, + darkModeGrayTextRgb = 0x00ff00 +}; + // from QStyle::standardPalette static inline QPalette standardPalette() { @@ -258,23 +269,55 @@ static inline QPalette standardPalette() return palette; } -static inline QPalette systemPalette() +static void populateLightSystemBasePalette(QPalette &result) { - QPalette result = standardPalette(); result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT)); - result.setColor(QPalette::Button, getSysColor(COLOR_BTNFACE)); - result.setColor(QPalette::Light, getSysColor(COLOR_BTNHIGHLIGHT)); + const QColor btnFace = getSysColor(COLOR_BTNFACE); + result.setColor(QPalette::Button, btnFace); + const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT); + result.setColor(QPalette::Light, btnHighlight); result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW)); result.setColor(QPalette::Mid, result.button().color().darker(150)); result.setColor(QPalette::Text, getSysColor(COLOR_WINDOWTEXT)); - result.setColor(QPalette::BrightText, getSysColor(COLOR_BTNHIGHLIGHT)); + result.setColor(QPalette::BrightText, btnHighlight); result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW)); - result.setColor(QPalette::Window, getSysColor(COLOR_BTNFACE)); + result.setColor(QPalette::Window, btnFace); result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT)); result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT)); result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW)); result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT)); result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); +} + +static void populateDarkSystemBasePalette(QPalette &result) +{ + const QColor darkModeWindowText = Qt::white; + result.setColor(QPalette::WindowText, darkModeWindowText); + const QColor darkModebtnFace = Qt::black; + result.setColor(QPalette::Button, darkModebtnFace); + const QColor btnHighlight = QColor(darkModeBtnHighlightRgb); + result.setColor(QPalette::Light, btnHighlight); + result.setColor(QPalette::Dark, QColor(darkModeBtnShadowRgb)); + result.setColor(QPalette::Mid, result.button().color().darker(150)); + result.setColor(QPalette::Text, darkModeWindowText); + result.setColor(QPalette::BrightText, btnHighlight); + result.setColor(QPalette::Base, darkModebtnFace); + result.setColor(QPalette::Window, darkModebtnFace); + result.setColor(QPalette::ButtonText, darkModeWindowText); + result.setColor(QPalette::Midlight, darkModeWindowText); + result.setColor(QPalette::Shadow, darkModeWindowText); + result.setColor(QPalette::Highlight, QColor(darkModeHighlightRgb)); + result.setColor(QPalette::HighlightedText, darkModeWindowText); +} + +static QPalette systemPalette(bool light) +{ + QPalette result = standardPalette(); + if (light) + populateLightSystemBasePalette(result); + else + populateDarkSystemBasePalette(result); + result.setColor(QPalette::Link, Qt::blue); result.setColor(QPalette::LinkVisited, Qt::magenta); result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); @@ -300,19 +343,19 @@ static inline QPalette systemPalette() result.setColor(QPalette::Disabled, QPalette::Text, disabled); result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled); result.setColor(QPalette::Disabled, QPalette::Highlight, - getSysColor(COLOR_HIGHLIGHT)); + light ? getSysColor(COLOR_HIGHLIGHT) : QColor(darkModeHighlightRgb)); result.setColor(QPalette::Disabled, QPalette::HighlightedText, - getSysColor(COLOR_HIGHLIGHTTEXT)); + light ? getSysColor(COLOR_HIGHLIGHTTEXT) : QColor(Qt::white)); result.setColor(QPalette::Disabled, QPalette::Base, result.window().color()); return result; } -static inline QPalette toolTipPalette(const QPalette &systemPalette) +static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light) { QPalette result(systemPalette); - const QColor tipBgColor(getSysColor(COLOR_INFOBK)); - const QColor tipTextColor(getSysColor(COLOR_INFOTEXT)); + const QColor tipBgColor = light ? getSysColor(COLOR_INFOBK) : QColor(Qt::black); + const QColor tipTextColor = light ? getSysColor(COLOR_INFOTEXT) : QColor(Qt::white); result.setColor(QPalette::All, QPalette::Button, tipBgColor); result.setColor(QPalette::All, QPalette::Window, tipBgColor); @@ -337,12 +380,13 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette) return result; } -static inline QPalette menuPalette(const QPalette &systemPalette) +static inline QPalette menuPalette(const QPalette &systemPalette, bool light) { QPalette result(systemPalette); - const QColor menuColor(getSysColor(COLOR_MENU)); - const QColor menuTextColor(getSysColor(COLOR_MENUTEXT)); - const QColor disabled(getSysColor(COLOR_GRAYTEXT)); + const QColor menuColor = light ? getSysColor(COLOR_MENU) : QColor(Qt::black); + const QColor menuTextColor = light ? getSysColor(COLOR_MENUTEXT) : QColor(Qt::white); + const QColor disabled = light + ? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeGrayTextRgb); // we might need a special color group for the result. result.setColor(QPalette::Active, QPalette::Button, menuColor); result.setColor(QPalette::Active, QPalette::Text, menuTextColor); @@ -351,8 +395,10 @@ static inline QPalette menuPalette(const QPalette &systemPalette) result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false); - result.setColor(QPalette::Disabled, QPalette::Highlight, - getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)); + const QColor highlightColor = light + ? (getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)) + : QColor(darkModeMenuHighlightRgb); + result.setColor(QPalette::Disabled, QPalette::Highlight, highlightColor); result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled); result.setColor(QPalette::Disabled, QPalette::Button, result.color(QPalette::Active, QPalette::Button)); @@ -373,12 +419,12 @@ static inline QPalette menuPalette(const QPalette &systemPalette) return result; } -static inline QPalette *menuBarPalette(const QPalette &menuPalette) +static inline QPalette *menuBarPalette(const QPalette &menuPalette, bool light) { QPalette *result = nullptr; if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) { result = new QPalette(menuPalette); - const QColor menubar(getSysColor(COLOR_MENUBAR)); + const QColor menubar(light ? getSysColor(COLOR_MENUBAR) : QColor(Qt::black)); result->setColor(QPalette::Active, QPalette::Button, menubar); result->setColor(QPalette::Disabled, QPalette::Button, menubar); result->setColor(QPalette::Inactive, QPalette::Button, menubar); @@ -485,10 +531,26 @@ void QWindowsTheme::refreshPalettes() if (!QGuiApplication::desktopSettingsAware()) return; - m_palettes[SystemPalette] = new QPalette(systemPalette()); - m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette])); - m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette])); - m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette]); + const bool light = + !QWindowsContext::isDarkMode() + || (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) == 0; + m_palettes[SystemPalette] = new QPalette(systemPalette(light)); + m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette], light)); + m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light)); + m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light); + if (!light) { + m_palettes[ButtonPalette] = new QPalette(*m_palettes[SystemPalette]); + m_palettes[ButtonPalette]->setColor(QPalette::Button, QColor(0x666666u)); + const QColor checkBoxBlue(0x0078d7u); + const QColor white(Qt::white); + m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]); + m_palettes[CheckBoxPalette]->setColor(QPalette::Window, checkBoxBlue); + m_palettes[CheckBoxPalette]->setColor(QPalette::Base, checkBoxBlue); + m_palettes[CheckBoxPalette]->setColor(QPalette::Button, checkBoxBlue); + m_palettes[CheckBoxPalette]->setColor(QPalette::ButtonText, white); + m_palettes[RadioButtonPalette] = new QPalette(*m_palettes[CheckBoxPalette]); + + } } void QWindowsTheme::clearFonts() @@ -497,6 +559,12 @@ void QWindowsTheme::clearFonts() std::fill(m_fonts, m_fonts + NFonts, nullptr); } +void QWindowsTheme::refresh() +{ + refreshPalettes(); + refreshFonts(); +} + void QWindowsTheme::refreshFonts() { clearFonts(); @@ -946,6 +1014,23 @@ bool QWindowsTheme::useNativeMenus() return result; } +bool QWindowsTheme::queryDarkMode() +{ + if (QOperatingSystemVersion::current() + < QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17763) + || queryHighContrast()) { + return false; + } + const auto setting = QWinRegistryKey(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)") + .dwordValue(L"AppsUseLightTheme"); + return setting.second && setting.first == 0; +} + +bool QWindowsTheme::queryHighContrast() +{ + return booleanSystemParametersInfo(SPI_GETHIGHCONTRAST, false); +} + QPlatformMenuItem *QWindowsTheme::createPlatformMenuItem() const { qCDebug(lcQpaMenus) << __FUNCTION__; diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 7a8c321da4..af28f2878c 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -84,13 +84,15 @@ public: void showPlatformMenuBar() override; static bool useNativeMenus(); + static bool queryDarkMode(); + static bool queryHighContrast(); void refreshFonts(); + void refresh(); static const char *name; private: - void refresh() { refreshPalettes(); refreshFonts(); } void clearPalettes(); void refreshPalettes(); void clearFonts(); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 04596b2d4d..d22cc75647 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -749,6 +749,11 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } } +static inline bool shouldApplyDarkFrame(const QWindow *w) +{ + return w->isTopLevel() && !w->flags().testFlag(Qt::FramelessWindowHint); +} + QWindowsWindowData WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const { @@ -816,6 +821,12 @@ QWindowsWindowData return result; } + if (QWindowsContext::isDarkMode() + && (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeWindowFrames) != 0 + && shouldApplyDarkFrame(w)) { + QWindowsWindow::setDarkBorderToWindow(result.hwnd, true); + } + if (mirrorParentWidth != 0) { context->obtainedPos.setX(mirrorParentWidth - context->obtainedSize.width() - context->obtainedPos.x()); @@ -2892,6 +2903,39 @@ bool QWindowsWindow::isTopLevel() const return window()->isTopLevel() && !m_data.embedded; } +enum : WORD { + DwmwaUseImmersiveDarkMode = 20, + DwmwaUseImmersiveDarkModeBefore20h1 = 19 +}; + +static bool queryDarkBorder(HWND hwnd) +{ + BOOL result = FALSE; + const bool ok = + SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &result, sizeof(result))) + || SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &result, sizeof(result))); + if (!ok) + qWarning("%s: Unable to retrieve dark window border setting.", __FUNCTION__); + return result == TRUE; +} + +bool QWindowsWindow::setDarkBorderToWindow(HWND hwnd, bool d) +{ + const BOOL darkBorder = d ? TRUE : FALSE; + const bool ok = + SUCCEEDED(DwmSetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &darkBorder, sizeof(darkBorder))) + || SUCCEEDED(DwmSetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &darkBorder, sizeof(darkBorder))); + if (!ok) + qWarning("%s: Unable to set dark window border.", __FUNCTION__); + return ok; +} + +void QWindowsWindow::setDarkBorder(bool d) +{ + if (shouldApplyDarkFrame(window()) && queryDarkBorder(m_data.hwnd) != d) + setDarkBorderToWindow(m_data.hwnd, d); +} + QWindowsMenuBar *QWindowsWindow::menuBar() const { return m_menuBar.data(); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 1f8800272b..7c37c6b115 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -287,6 +287,9 @@ public: HWND handle() const override { return m_data.hwnd; } bool isTopLevel() const override; + static bool setDarkBorderToWindow(HWND hwnd, bool d); + void setDarkBorder(bool d); + QWindowsMenuBar *menuBar() const; void setMenuBar(QWindowsMenuBar *mb); diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp index c2d9d060fb..fe9ddfece7 100644 --- a/src/plugins/platforms/xcb/qxcbclipboard.cpp +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -123,8 +123,9 @@ protected: return list.contains(format); } - QVariant retrieveData_sys(const QString &fmt, QVariant::Type requestedType) const override + QVariant retrieveData_sys(const QString &fmt, QVariant::Type type) const override { + auto requestedType = QMetaType::Type(type); if (fmt.isEmpty() || isEmpty()) return QByteArray(); diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 47d58fa880..e76fc8bd40 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -114,7 +114,7 @@ protected: QStringList formats_sys() const override; QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const override; - QVariant xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const; + QVariant xdndObtainData(const QByteArray &format, QMetaType::Type requestedType) const; QXcbDrag *drag; }; @@ -1248,11 +1248,11 @@ QXcbDropData::~QXcbDropData() QVariant QXcbDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const { QByteArray mime = mimetype.toLatin1(); - QVariant data = xdndObtainData(mime, requestedType); + QVariant data = xdndObtainData(mime, QMetaType::Type(requestedType)); return data; } -QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const +QVariant QXcbDropData::xdndObtainData(const QByteArray &format, QMetaType::Type requestedType) const { QByteArray result; diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp index d611f86a9c..0b3219f792 100644 --- a/src/plugins/platforms/xcb/qxcbmime.cpp +++ b/src/plugins/platforms/xcb/qxcbmime.cpp @@ -159,7 +159,7 @@ QVector<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, con } QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &d, const QString &format, - QVariant::Type requestedType, const QByteArray &encoding) + QMetaType::Type requestedType, const QByteArray &encoding) { QByteArray data = d; QString atomName = mimeAtomToString(connection, a); @@ -169,7 +169,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, && atomName == format + QLatin1String(";charset=") + QLatin1String(encoding)) { #if QT_CONFIG(textcodec) - if (requestedType == QVariant::String) { + if (requestedType == QMetaType::QString) { QTextCodec *codec = QTextCodec::codecForName(encoding); if (codec) return codec->toUnicode(data); @@ -264,7 +264,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, return QVariant(); } -xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, +xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType::Type requestedType, const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding) { requestedEncoding->clear(); @@ -297,7 +297,7 @@ xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString // for string/text requests try to use a format with a well-defined charset // first to avoid encoding problems - if (requestedType == QVariant::String + if (requestedType == QMetaType::QString && format.startsWith(QLatin1String("text/")) && !format.contains(QLatin1String("charset="))) { diff --git a/src/plugins/platforms/xcb/qxcbmime.h b/src/plugins/platforms/xcb/qxcbmime.h index f2136ec9f4..dcb4f6b6c6 100644 --- a/src/plugins/platforms/xcb/qxcbmime.h +++ b/src/plugins/platforms/xcb/qxcbmime.h @@ -60,8 +60,8 @@ public: static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, xcb_atom_t *atomFormat, int *dataFormat); static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, - QVariant::Type requestedType, const QByteArray &encoding); - static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, + QMetaType::Type requestedType, const QByteArray &encoding); + static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QMetaType::Type requestedType, const QVector<xcb_atom_t> &atoms, QByteArray *requestedEncoding); }; |