diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-09-01 11:35:12 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-09-01 11:35:53 +0200 |
commit | 2dfc786c26663a2d555a8c8152c5ff95a3b0672e (patch) | |
tree | fbf4d41dc1836ffa607e70e2348102066a83855c /src/plugins/platforms | |
parent | d444bbf110e83c72d0657203896ad3c8a4cb5107 (diff) | |
parent | 1812bb968c49d50745ab2b10787320205c54f946 (diff) |
Merge remote-tracking branch 'origin/5.4' into dev
Change-Id: I2811ff0b9d4097f0be60ff16e9664a5060cff23e
Diffstat (limited to 'src/plugins/platforms')
68 files changed, 1099 insertions, 727 deletions
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index 0209379afb..ffbad08c10 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -47,7 +47,6 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroidplatformscreen.cpp \ $$PWD/qandroidplatformwindow.cpp \ $$PWD/qandroidplatformopenglwindow.cpp \ - $$PWD/qandroidplatformrasterwindow.cpp \ $$PWD/qandroidplatformbackingstore.cpp \ $$PWD/qandroidplatformopenglcontext.cpp \ $$PWD/qandroidplatformforeignwindow.cpp \ @@ -76,7 +75,6 @@ HEADERS += $$PWD/qandroidplatformintegration.h \ $$PWD/qandroidplatformscreen.h \ $$PWD/qandroidplatformwindow.h \ $$PWD/qandroidplatformopenglwindow.h \ - $$PWD/qandroidplatformrasterwindow.h \ $$PWD/qandroidplatformbackingstore.h \ $$PWD/qandroidplatformopenglcontext.h \ $$PWD/qandroidplatformforeignwindow.h \ diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index f776e43efa..de30fa825a 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -401,10 +401,8 @@ namespace QtAndroid { QMutexLocker lock(&m_surfacesMutex); const auto &it = m_surfaces.find(surfaceId); - if (it == m_surfaces.end()) - return; - - m_surfaces.remove(surfaceId); + if (it != m_surfaces.end()) + m_surfaces.remove(surfaceId); if (m_surfaces.isEmpty()) m_surfaceId = 1; diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp index ff49f59076..2ee556de5c 100644 --- a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp +++ b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp @@ -42,7 +42,7 @@ #include "qandroidplatformbackingstore.h" #include "qandroidplatformscreen.h" -#include "qandroidplatformrasterwindow.h" +#include "qandroidplatformwindow.h" #include <qpa/qplatformscreen.h> QT_BEGIN_NAMESPACE @@ -66,7 +66,7 @@ void QAndroidPlatformBackingStore::flush(QWindow *window, const QRegion ®ion, if (!m_backingStoreSet) setBackingStore(window); - (static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->repaint(region); + (static_cast<QAndroidPlatformWindow *>(window->handle()))->repaint(region); } void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents) @@ -79,11 +79,11 @@ void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &stat void QAndroidPlatformBackingStore::setBackingStore(QWindow *window) { - if (window->surfaceType() == QSurface::RasterSurface) { - (static_cast<QAndroidPlatformRasterWindow *>(window->handle()))->setBackingStore(this); + if (window->surfaceType() == QSurface::RasterSurface || window->surfaceType() == QSurface::RasterGLSurface) { + (static_cast<QAndroidPlatformWindow *>(window->handle()))->setBackingStore(this); m_backingStoreSet = true; } else { - qWarning("QAndroidPlatformBackingStore does not support GL windows."); + qWarning("QAndroidPlatformBackingStore does not support OpenGL-only windows."); } } diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 829227f81c..53cb3588f6 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -62,7 +62,6 @@ #include "qandroidplatformfontdatabase.h" #include "qandroidplatformopenglcontext.h" #include "qandroidplatformopenglwindow.h" -#include "qandroidplatformrasterwindow.h" #include "qandroidplatformscreen.h" #include "qandroidplatformservices.h" #include "qandroidplatformtheme.h" @@ -192,6 +191,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const return false; else return true; + case RasterGLSurface: return true; default: return QPlatformIntegration::hasCapability(cap); } @@ -227,8 +227,6 @@ QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *wind { if (window->type() == Qt::ForeignWindow) return new QAndroidPlatformForeignWindow(window); - else if (window->surfaceType() == QSurface::RasterSurface) - return new QAndroidPlatformRasterWindow(window); else return new QAndroidPlatformOpenGLWindow(window, m_eglDisplay); } diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index d821145973..73c0a76dd7 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -42,9 +42,11 @@ #include "qandroidplatformopenglwindow.h" +#include "qandroidplatformscreen.h" #include "androidjnimain.h" #include <QSurfaceFormat> +#include <QtGui/private/qwindow_p.h> #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformscreen.h> @@ -69,25 +71,52 @@ QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow() unlockSurface(); } +void QAndroidPlatformOpenGLWindow::repaint(const QRegion ®ion) +{ + // This is only for real raster top-level windows. Stop in all other cases. + if ((window()->surfaceType() == QSurface::RasterGLSurface && qt_window_private(window())->compositing) + || window()->surfaceType() == QSurface::OpenGLSurface + || QAndroidPlatformWindow::parent()) + return; + + QRect currentGeometry = geometry(); + + QRect dirtyClient = region.boundingRect(); + QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), + currentGeometry.top() + dirtyClient.top(), + dirtyClient.width(), + dirtyClient.height()); + QRect mOldGeometryLocal = m_oldGeometry; + m_oldGeometry = currentGeometry; + // If this is a move, redraw the previous location + if (mOldGeometryLocal != currentGeometry) + platformScreen()->setDirty(mOldGeometryLocal); + platformScreen()->setDirty(dirtyRegion); +} + void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) { if (rect == geometry()) return; - QRect oldGeometry = geometry(); + m_oldGeometry = geometry(); QAndroidPlatformWindow::setGeometry(rect); - QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); + if (m_nativeSurfaceId != -1) + QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); QRect availableGeometry = screen()->availableGeometry(); - if (oldGeometry.width() == 0 - && oldGeometry.height() == 0 + if (m_oldGeometry.width() == 0 + && m_oldGeometry.height() == 0 && rect.width() > 0 && rect.height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) { QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size())); } + + if (rect.topLeft() != m_oldGeometry.topLeft()) + repaint(QRegion(rect)); } EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) @@ -162,8 +191,8 @@ QSurfaceFormat QAndroidPlatformOpenGLWindow::format() const void QAndroidPlatformOpenGLWindow::clearEgl() { - eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (m_eglSurface != EGL_NO_SURFACE) { + eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(m_eglDisplay, m_eglSurface); m_eglSurface = EGL_NO_SURFACE; } diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h index 713f943bc5..5f7089d5a4 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h @@ -66,6 +66,8 @@ public: void applicationStateChanged(Qt::ApplicationState); + void repaint(const QRegion ®ion) Q_DECL_OVERRIDE; + protected: virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h); void createEgl(EGLConfig config); @@ -80,6 +82,7 @@ private: QJNIObjectPrivate m_androidSurfaceObject; QWaitCondition m_surfaceWaitCondition; QSurfaceFormat m_format; + QRect m_oldGeometry; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp deleted file mode 100644 index 3fb236793b..0000000000 --- a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** 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 Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qandroidplatformrasterwindow.h" - -#include "qandroidplatformscreen.h" - -QT_BEGIN_NAMESPACE - -QAndroidPlatformRasterWindow::QAndroidPlatformRasterWindow(QWindow *window) - :QAndroidPlatformWindow(window) -{ - -} - -void QAndroidPlatformRasterWindow::repaint(const QRegion ®ion) -{ - if (QAndroidPlatformWindow::parent()) - return; - - QRect currentGeometry = geometry(); - - QRect dirtyClient = region.boundingRect(); - QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), - currentGeometry.top() + dirtyClient.top(), - dirtyClient.width(), - dirtyClient.height()); - QRect mOldGeometryLocal = m_oldGeometry; - m_oldGeometry = currentGeometry; - // If this is a move, redraw the previous location - if (mOldGeometryLocal != currentGeometry) - platformScreen()->setDirty(mOldGeometryLocal); - platformScreen()->setDirty(dirtyRegion); -} - -void QAndroidPlatformRasterWindow::setGeometry(const QRect &rect) -{ - m_oldGeometry = geometry(); - QAndroidPlatformWindow::setGeometry(rect); - if (rect.topLeft() != m_oldGeometry.topLeft()) - repaint(QRegion(rect)); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 433461f628..870d81688c 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -48,9 +48,9 @@ #include "qandroidplatformscreen.h" #include "qandroidplatformbackingstore.h" #include "qandroidplatformintegration.h" +#include "qandroidplatformwindow.h" #include "androidjnimain.h" #include "androidjnimenu.h" -#include "qandroidplatformrasterwindow.h" #include <android/bitmap.h> #include <android/native_window_jni.h> @@ -58,6 +58,7 @@ #include <QtGui/QGuiApplication> #include <QtGui/QWindow> +#include <QtGui/private/qwindow_p.h> QT_BEGIN_NAMESPACE @@ -291,6 +292,19 @@ void QAndroidPlatformScreen::doRedraw() if (m_dirtyRect.isEmpty()) return; + // Stop if there no visible raster windows. This is important because if we only have + // RasterGLSurface windows that have renderToTexture children (i.e. they need the + // OpenGL path) then we must bail out right now. + bool hasVisibleRasterWindows = false; + foreach (QAndroidPlatformWindow *window, m_windowStack) { + if (window->window()->isVisible() && window->isRaster() && !qt_window_private(window->window())->compositing) { + hasVisibleRasterWindows = true; + break; + } + } + if (!hasVisibleRasterWindows) + return; + QMutexLocker lock(&m_surfaceMutex); if (m_id == -1 && m_rasterSurfaces) { m_id = QtAndroid::createSurface(this, m_availableGeometry, true, m_depth); @@ -343,7 +357,7 @@ void QAndroidPlatformScreen::doRedraw() visibleRegion -= targetRect; QRect windowRect = targetRect.translated(-window->geometry().topLeft()); - QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformRasterWindow *>(window)->backingStore(); + QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformWindow *>(window)->backingStore(); if (backingStore) compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect); } diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp index 9c21abe39b..1f2f58f838 100644 --- a/src/plugins/platforms/android/qandroidplatformservices.cpp +++ b/src/plugins/platforms/android/qandroidplatformservices.cpp @@ -54,11 +54,10 @@ QAndroidPlatformServices::QAndroidPlatformServices() bool QAndroidPlatformServices::openUrl(const QUrl &url) { QJNIObjectPrivate urlString = QJNIObjectPrivate::fromString(url.toString()); - QJNIObjectPrivate::callStaticMethod<void>(QtAndroid::applicationClass(), - "openURL", - "(Ljava/lang/String;)V", - urlString.object()); - return true; + return QJNIObjectPrivate::callStaticMethod<jboolean>(QtAndroid::applicationClass(), + "openURL", + "(Ljava/lang/String;)Z", + urlString.object()); } bool QAndroidPlatformServices::openDocument(const QUrl &url) diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 91e32fa2ac..1899499d01 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE class QAndroidPlatformScreen; +class QAndroidPlatformBackingStore; class QAndroidPlatformWindow: public QPlatformWindow { @@ -71,10 +72,19 @@ public: void propagateSizeHints(); void requestActivateWindow(); void updateStatusBarVisibility(); - inline bool isRaster() const { return window()->surfaceType() == QSurface::RasterSurface; } + inline bool isRaster() const { + return window()->surfaceType() == QSurface::RasterSurface + || window()->surfaceType() == QSurface::RasterGLSurface; + } bool isExposed() const; virtual void applicationStateChanged(Qt::ApplicationState); + + void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; } + QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; } + + virtual void repaint(const QRegion &) { } + protected: void setGeometry(const QRect &rect); @@ -83,6 +93,8 @@ protected: Qt::WindowState m_windowState; WId m_windowId; + + QAndroidPlatformBackingStore *m_backingStore = nullptr; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm index 5a7cdec83e..8158c244ab 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm @@ -81,6 +81,7 @@ static NSButton *macCreateButton(const char *text, NSView *superview) NSInteger mResultCode; BOOL mDialogIsExecuting; BOOL mResultSet; + BOOL mClosingDueToKnownButton; }; - (void)restoreOriginalContentView; - (void)relayout; @@ -103,6 +104,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); mResultCode = NSCancelButton; mDialogIsExecuting = false; mResultSet = false; + mClosingDueToKnownButton = false; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) @@ -114,6 +116,11 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); name:NSColorPanelColorDidChangeNotification object:mColorPanel]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowWillClose:) + name:NSWindowWillCloseNotification + object:mColorPanel]; + [mColorPanel retain]; return self; } @@ -179,6 +186,15 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); emit mHelper->colorSelected(mQtColor); } +- (void)windowWillClose:(NSNotification *)notification +{ + Q_UNUSED(notification); + if (mCancelButton && mHelper && !mClosingDueToKnownButton) { + mClosingDueToKnownButton = true; // prevent repeating emit + emit mHelper->reject(); + } +} + - (void)restoreOriginalContentView { if (mStolenContentView) { @@ -246,6 +262,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); - (void)onOkClicked { + mClosingDueToKnownButton = true; [mColorPanel close]; [self updateQtColor]; [self finishOffWithCode:NSOKButton]; @@ -254,6 +271,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); - (void)onCancelClicked { if (mOkButton) { + mClosingDueToKnownButton = true; [mColorPanel close]; mQtColor = QColor(); [self finishOffWithCode:NSCancelButton]; @@ -298,6 +316,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSColorPanelDelegate); { mDialogIsExecuting = false; mResultSet = false; + mClosingDueToKnownButton = false; [mColorPanel makeKeyAndOrderFront:mColorPanel]; } diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.h b/src/plugins/platforms/cocoa/qcocoasystemsettings.h index 9ce301f7e7..3861da6230 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.h +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.h @@ -50,7 +50,6 @@ QT_BEGIN_NAMESPACE QPalette * qt_mac_createSystemPalette(); QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes(); -QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts(); QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index 26aa871998..3ce2f06763 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -213,48 +213,4 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes() return palettes; } -QFont *qt_mac_qfontForThemeFont(ThemeFontID themeID) -{ - CTFontUIFontType ctID = HIThemeGetUIFontType(themeID); - QCFType<CTFontRef> ctfont = CTFontCreateUIFontForLanguage(ctID, 0, 0); - QString familyName = QCFString(CTFontCopyFamilyName(ctfont)); - QCFType<CFDictionaryRef> dict = CTFontCopyTraits(ctfont); - CFNumberRef num = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kCTFontWeightTrait)); - float fW; - CFNumberGetValue(num, kCFNumberFloat32Type, &fW); - QFont::Weight wght = fW > 0. ? QFont::Bold : QFont::Normal; - num = static_cast<CFNumberRef>(CFDictionaryGetValue(dict, kCTFontSlantTrait)); - CFNumberGetValue(num, kCFNumberFloatType, &fW); - bool italic = (fW != 0.0); - return new QFont(familyName, CTFontGetSize(ctfont), wght, italic); -} - -QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts() -{ - QHash<QPlatformTheme::Font, QFont *> fonts; - - fonts.insert(QPlatformTheme::SystemFont, qt_mac_qfontForThemeFont(kThemeApplicationFont)); - fonts.insert(QPlatformTheme::PushButtonFont, qt_mac_qfontForThemeFont(kThemePushButtonFont)); - fonts.insert(QPlatformTheme::ListViewFont, qt_mac_qfontForThemeFont(kThemeViewsFont)); - fonts.insert(QPlatformTheme::ListBoxFont, qt_mac_qfontForThemeFont(kThemeViewsFont)); - fonts.insert(QPlatformTheme::TitleBarFont, qt_mac_qfontForThemeFont(kThemeWindowTitleFont)); - fonts.insert(QPlatformTheme::MenuFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont)); - fonts.insert(QPlatformTheme::MenuBarFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont)); - fonts.insert(QPlatformTheme::ComboMenuItemFont, qt_mac_qfontForThemeFont(kThemeSystemFont)); - fonts.insert(QPlatformTheme::HeaderViewFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); - fonts.insert(QPlatformTheme::TipLabelFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); - fonts.insert(QPlatformTheme::LabelFont, qt_mac_qfontForThemeFont(kThemeSystemFont)); - fonts.insert(QPlatformTheme::ToolButtonFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); - fonts.insert(QPlatformTheme::MenuItemFont, qt_mac_qfontForThemeFont(kThemeMenuItemFont)); - fonts.insert(QPlatformTheme::ComboLineEditFont, qt_mac_qfontForThemeFont(kThemeViewsFont)); - fonts.insert(QPlatformTheme::SmallFont, qt_mac_qfontForThemeFont(kThemeSmallSystemFont)); - fonts.insert(QPlatformTheme::MiniFont, qt_mac_qfontForThemeFont(kThemeMiniSystemFont)); - - QFont* fixedFont = new QFont(QStringLiteral("Monaco"), fonts[QPlatformTheme::SystemFont]->pointSize()); - fixedFont->setStyleHint(QFont::TypeWriter); - fonts.insert(QPlatformTheme::FixedFont, fixedFont); - - return fonts; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index dce1671800..ae42fee82c 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -60,6 +60,7 @@ #include <QtCore/qfileinfo.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/qpainter.h> +#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> #include <qpa/qplatformintegration.h> #include <qpa/qplatformnativeinterface.h> @@ -134,6 +135,12 @@ const QPalette *QCocoaTheme::palette(Palette type) const return 0; } +QHash<QPlatformTheme::Font, QFont *> qt_mac_createRoleFonts() +{ + QCoreTextFontDatabase *ctfd = static_cast<QCoreTextFontDatabase *>(QGuiApplicationPrivate::platformIntegration()->fontDatabase()); + return ctfd->themeFonts(); +} + const QFont *QCocoaTheme::font(Font type) const { if (m_fonts.isEmpty()) { diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 011a9ba71a..cfcbb8053c 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -66,7 +66,11 @@ #include <accessibilityinspector.h> #endif -Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.tabletsupport") +Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch") +#ifndef QT_NO_GESTURES +Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures") +#endif +Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") static QTouchDevice *touchDevice = 0; @@ -1120,41 +1124,49 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) } } +- (bool) shouldSendSingleTouch +{ + // QtWidgets expects single-point touch events, QtDeclarative does not. + // Until there is an API we solve this by looking at the window class type. + return m_window->inherits("QWidgetWindow"); +} + - (void)touchesBeganWithEvent:(NSEvent *)event { const NSTimeInterval timestamp = [event timestamp]; - const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false); + const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); + qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points; QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points); } - (void)touchesMovedWithEvent:(NSEvent *)event { const NSTimeInterval timestamp = [event timestamp]; - const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false); + const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); + qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points; QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points); } - (void)touchesEndedWithEvent:(NSEvent *)event { const NSTimeInterval timestamp = [event timestamp]; - const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false); + const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); + qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points; QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points); } - (void)touchesCancelledWithEvent:(NSEvent *)event { const NSTimeInterval timestamp = [event timestamp]; - const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, /*acceptSingleTouch= ### true or false?*/false); + const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]); + qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points; QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points); } #ifndef QT_NO_GESTURES -//#define QT_COCOA_ENABLE_GESTURE_DEBUG - (void)magnifyWithEvent:(NSEvent *)event { -#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG - qDebug() << "magnifyWithEvent" << [event magnification]; -#endif + qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -1167,9 +1179,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)smartMagnifyWithEvent:(NSEvent *)event { static bool zoomIn = true; -#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG - qDebug() << "smartMagnifyWithEvent" << zoomIn; -#endif + qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -1182,9 +1192,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)rotateWithEvent:(NSEvent *)event { -#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG - qDebug() << "rotateWithEvent" << [event rotation]; -#endif + qCDebug(lcQpaGestures) << "rotateWithEvent" << [event rotation]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -1195,9 +1203,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)swipeWithEvent:(NSEvent *)event { -#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG - qDebug() << "swipeWithEvent" << [event deltaX] << [event deltaY]; -#endif + qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY]; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; @@ -1219,22 +1225,18 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) - (void)beginGestureWithEvent:(NSEvent *)event { -#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG - qDebug() << "beginGestureWithEvent"; -#endif const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint; QWindowSystemInterface::handleGestureEvent(m_window, timestamp, Qt::BeginNativeGesture, windowPoint, screenPoint); } - (void)endGestureWithEvent:(NSEvent *)event { -#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG - qDebug() << "endGestureWithEvent"; -#endif + qCDebug(lcQpaGestures) << "endGestureWithEvent"; const NSTimeInterval timestamp = [event timestamp]; QPointF windowPoint; QPointF screenPoint; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index 4c39560cbe..f131419140 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -48,11 +48,11 @@ #include "qwindowsdirect2ddevicecontext.h" #include "qwindowsfontengine.h" -#include "qwindowsfontenginedirectwrite.h" #include "qwindowsfontdatabase.h" #include "qwindowsintegration.h" #include <QtCore/QStack> +#include <QtCore/QSettings> #include <QtGui/private/qpaintengine_p.h> #include <QtGui/private/qtextengine_p.h> #include <QtGui/private/qfontengine_p.h> @@ -109,6 +109,13 @@ static inline ID2D1Factory1 *factory() return QWindowsDirect2DContext::instance()->d2dFactory(); } +inline static FLOAT pixelSizeToDIP(int pixelSize) +{ + FLOAT dpiX, dpiY; + QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY); + return FLOAT(pixelSize) * 96.0f / dpiY; +} + class Direct2DPathGeometryWriter { public: @@ -243,7 +250,7 @@ public: QPointF currentBrushOrigin; - QHash< QFont, ComPtr<IDWriteFontFace> > fontCache; + QHash< QFontDef, ComPtr<IDWriteFontFace> > fontCache; struct { bool emulate; @@ -836,6 +843,74 @@ public: { dc()->SetAntialiasMode(antialiasMode()); } + + void drawGlyphRun(const D2D1_POINT_2F &pos, + IDWriteFontFace *fontFace, + const QFontDef &fontDef, + int numGlyphs, + const UINT16 *glyphIndices, + const FLOAT *glyphAdvances, + const DWRITE_GLYPH_OFFSET *glyphOffsets, + bool rtl) + { + Q_Q(QWindowsDirect2DPaintEngine); + + DWRITE_GLYPH_RUN glyphRun = { + fontFace, // IDWriteFontFace *fontFace; + pixelSizeToDIP(fontDef.pixelSize), // FLOAT fontEmSize; + numGlyphs, // UINT32 glyphCount; + glyphIndices, // const UINT16 *glyphIndices; + glyphAdvances, // const FLOAT *glyphAdvances; + glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets; + FALSE, // BOOL isSideways; + rtl ? 1 : 0 // UINT32 bidiLevel; + }; + + const bool antiAlias = bool((q->state()->renderHints & QPainter::TextAntialiasing) + && !(fontDef.styleStrategy & QFont::NoAntialias)); + dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE + : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); + + dc()->DrawGlyphRun(pos, + &glyphRun, + NULL, + pen.brush.Get(), + DWRITE_MEASURING_MODE_GDI_CLASSIC); + } + + ComPtr<IDWriteFontFace> fontFaceFromFontEngine(QFontEngine *fe) + { + const QFontDef fontDef = fe->fontDef; + ComPtr<IDWriteFontFace> fontFace = fontCache.value(fontDef); + if (fontFace) + return fontFace; + + LOGFONT lf = QWindowsFontDatabase::fontDefToLOGFONT(fontDef); + + // Get substitute name + static const char keyC[] = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"; + const QString familyName = QString::fromWCharArray(lf.lfFaceName); + const QString nameSubstitute = QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString(); + memcpy(lf.lfFaceName, nameSubstitute.utf16(), sizeof(wchar_t) * qMin(nameSubstitute.length() + 1, LF_FACESIZE)); + + ComPtr<IDWriteFont> dwriteFont; + HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFromLOGFONT(&lf, &dwriteFont); + if (FAILED(hr)) { + qDebug("%s: CreateFontFromLOGFONT failed: %#x", __FUNCTION__, hr); + return fontFace; + } + + hr = dwriteFont->CreateFontFace(&fontFace); + if (FAILED(hr)) { + qDebug("%s: CreateFontFace failed: %#x", __FUNCTION__, hr); + return fontFace; + } + + if (fontFace) + fontCache.insert(fontDef, fontFace); + + return fontFace; + } }; QWindowsDirect2DPaintEngine::QWindowsDirect2DPaintEngine(QWindowsDirect2DBitmap *bitmap) @@ -1411,7 +1486,7 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText return; } - ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(staticTextItem->font, staticTextItem->fontEngine()); + ComPtr<IDWriteFontFace> fontFace = d->fontFaceFromFontEngine(staticTextItem->fontEngine()); if (!fontFace) { qWarning("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__); QPaintEngineEx::drawStaticTextItem(staticTextItem); @@ -1432,14 +1507,14 @@ void QWindowsDirect2DPaintEngine::drawStaticTextItem(QStaticTextItem *staticText glyphOffsets[i].ascenderOffset = staticTextItem->glyphPositions[i].y.toReal() * -1; } - drawGlyphRun(D2D1::Point2F(0, 0), - fontFace.Get(), - staticTextItem->font, - staticTextItem->numGlyphs, - glyphIndices.constData(), - glyphAdvances.constData(), - glyphOffsets.constData(), - false); + d->drawGlyphRun(D2D1::Point2F(0, 0), + fontFace.Get(), + staticTextItem->fontEngine()->fontDef, + staticTextItem->numGlyphs, + glyphIndices.constData(), + glyphAdvances.constData(), + glyphOffsets.constData(), + false); } void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) @@ -1459,7 +1534,7 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem return; } - ComPtr<IDWriteFontFace> fontFace = fontFaceFromFontEngine(*ti.f, ti.fontEngine); + ComPtr<IDWriteFontFace> fontFace = d->fontFaceFromFontEngine(ti.fontEngine); if (!fontFace) { qWarning("%s: Could not find font - falling back to slow text rendering path.", __FUNCTION__); QPaintEngine::drawTextItem(p, textItem); @@ -1482,72 +1557,14 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem const bool rtl = (ti.flags & QTextItem::RightToLeft); const QPointF offset(rtl ? ti.width.toReal() : 0, 0); - drawGlyphRun(to_d2d_point_2f(p + offset), - fontFace.Get(), - ti.font(), - ti.glyphs.numGlyphs, - glyphIndices.constData(), - glyphAdvances.constData(), - glyphOffsets.constData(), - rtl); -} - -inline static FLOAT pointSizeToDIP(qreal pointSize, FLOAT dpiY) -{ - return (pointSize + (pointSize / qreal(3.0))) * (dpiY / 96.0f); -} - -inline static FLOAT pixelSizeToDIP(int pixelSize, FLOAT dpiY) -{ - return FLOAT(pixelSize) * 96.0f / dpiY; -} - -inline static FLOAT fontSizeInDIP(const QFont &font) -{ - FLOAT dpiX, dpiY; - QWindowsDirect2DContext::instance()->d2dFactory()->GetDesktopDpi(&dpiX, &dpiY); - - if (font.pixelSize() == -1) { - // font size was set as points - return pointSizeToDIP(font.pointSizeF(), dpiY); - } else { - // font size was set as pixels - return pixelSizeToDIP(font.pixelSize(), dpiY); - } -} - -void QWindowsDirect2DPaintEngine::drawGlyphRun(const D2D1_POINT_2F &pos, - IDWriteFontFace *fontFace, - const QFont &font, - int numGlyphs, - const UINT16 *glyphIndices, - const FLOAT *glyphAdvances, - const DWRITE_GLYPH_OFFSET *glyphOffsets, - bool rtl) -{ - Q_D(QWindowsDirect2DPaintEngine); - - DWRITE_GLYPH_RUN glyphRun = { - fontFace, // IDWriteFontFace *fontFace; - fontSizeInDIP(font), // FLOAT fontEmSize; - numGlyphs, // UINT32 glyphCount; - glyphIndices, // const UINT16 *glyphIndices; - glyphAdvances, // const FLOAT *glyphAdvances; - glyphOffsets, // const DWRITE_GLYPH_OFFSET *glyphOffsets; - FALSE, // BOOL isSideways; - rtl ? 1 : 0 // UINT32 bidiLevel; - }; - - const bool antiAlias = bool((state()->renderHints & QPainter::TextAntialiasing) - && !(font.styleStrategy() & QFont::NoAntialias)); - d->dc()->SetTextAntialiasMode(antiAlias ? D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE - : D2D1_TEXT_ANTIALIAS_MODE_ALIASED); - - d->dc()->DrawGlyphRun(pos, - &glyphRun, - NULL, - d->pen.brush.Get(), - DWRITE_MEASURING_MODE_GDI_CLASSIC); + d->drawGlyphRun(to_d2d_point_2f(p + offset), + fontFace.Get(), + ti.fontEngine->fontDef, + ti.glyphs.numGlyphs, + glyphIndices.constData(), + glyphAdvances.constData(), + glyphOffsets.constData(), + rtl); } void QWindowsDirect2DPaintEngine::ensureBrush() @@ -1678,49 +1695,4 @@ void QWindowsDirect2DPaintEngine::adjustForAliasing(QPointF *point) (*point) += adjustment; } -Microsoft::WRL::ComPtr<IDWriteFontFace> QWindowsDirect2DPaintEngine::fontFaceFromFontEngine(const QFont &font, QFontEngine *fe) -{ - Q_D(QWindowsDirect2DPaintEngine); - - ComPtr<IDWriteFontFace> fontFace = d->fontCache.value(font); - if (fontFace) - return fontFace; - - switch (fe->type()) { - case QFontEngine::Win: - { - QWindowsFontEngine *wfe = static_cast<QWindowsFontEngine *>(fe); - QSharedPointer<QWindowsFontEngineData> wfed = wfe->fontEngineData(); - - HGDIOBJ oldfont = wfe->selectDesignFont(); - HRESULT hr = QWindowsDirect2DContext::instance()->dwriteGdiInterop()->CreateFontFaceFromHdc(wfed->hdc, &fontFace); - DeleteObject(SelectObject(wfed->hdc, oldfont)); - if (FAILED(hr)) - qWarning("%s: Could not create DirectWrite fontface from HDC: %#x", __FUNCTION__, hr); - - } - break; - -#ifndef QT_NO_DIRECTWRITE - - case QFontEngine::DirectWrite: - { - QWindowsFontEngineDirectWrite *wfedw = static_cast<QWindowsFontEngineDirectWrite *>(fe); - fontFace = wfedw->directWriteFontFace(); - } - break; - -#endif // QT_NO_DIRECTWRITE - - default: - qWarning("%s: Unknown font engine!", __FUNCTION__); - break; - } - - if (fontFace) - d->fontCache.insert(font, fontFace); - - return fontFace; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index c91a951ebe..1469d32876 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -105,10 +105,6 @@ public: void drawTextItem(const QPointF &p, const QTextItem &textItem) Q_DECL_OVERRIDE; private: - void drawGlyphRun(const D2D1_POINT_2F &pos, IDWriteFontFace *fontFace, const QFont &font, - int numGlyphs, const UINT16 *glyphIndices, const FLOAT *glyphAdvances, - const DWRITE_GLYPH_OFFSET *glyphOffsets, bool rtl); - void ensureBrush(); void ensureBrush(const QBrush &brush); void ensurePen(); @@ -122,8 +118,6 @@ private: bool antiAliasingEnabled() const; void adjustForAliasing(QRectF *rect); void adjustForAliasing(QPointF *point); - - Microsoft::WRL::ComPtr<IDWriteFontFace> fontFaceFromFontEngine(const QFont &font, QFontEngine *fe); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbinput.cpp b/src/plugins/platforms/directfb/qdirectfbinput.cpp index 49dc45f04a..fd558b9974 100644 --- a/src/plugins/platforms/directfb/qdirectfbinput.cpp +++ b/src/plugins/platforms/directfb/qdirectfbinput.cpp @@ -154,7 +154,7 @@ void QDirectFbInput::handleEvents() void QDirectFbInput::handleMouseEvents(const DFBEvent &event) { QPoint p(event.window.x, event.window.y); - QPoint globalPos = globalPoint(event); + QPoint globalPos(event.window.cx, event.window.cy); Qt::MouseButtons buttons = QDirectFbConvenience::mouseButtons(event.window.buttons); QDirectFBPointer<IDirectFBDisplayLayer> layer(QDirectFbConvenience::dfbDisplayLayer()); @@ -169,8 +169,8 @@ void QDirectFbInput::handleMouseEvents(const DFBEvent &event) void QDirectFbInput::handleWheelEvent(const DFBEvent &event) { - QPoint p(event.window.cx, event.window.cy); - QPoint globalPos = globalPoint(event); + QPoint p(event.window.x, event.window.y); + QPoint globalPos(event.window.cx, event.window.cy); long timestamp = (event.window.timestamp.tv_sec*1000) + (event.window.timestamp.tv_usec/1000); QWindow *tlw = m_tlwMap.value(event.window.window_id); QWindowSystemInterface::handleWheelEvent(tlw, timestamp, p, globalPos, @@ -227,13 +227,4 @@ void QDirectFbInput::handleGeometryEvent(const DFBEvent &event) QWindowSystemInterface::handleGeometryChange(tlw, rect); } -inline QPoint QDirectFbInput::globalPoint(const DFBEvent &event) const -{ - QDirectFBPointer<IDirectFBWindow> window; - m_dfbDisplayLayer->GetWindow(m_dfbDisplayLayer, event.window.window_id, window.outPtr()); - int x,y; - window->GetPosition(window.data(), &x, &y); - return QPoint(event.window.cx +x, event.window.cy + y); -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbinput.h b/src/plugins/platforms/directfb/qdirectfbinput.h index 0ce45823e1..0d775cdc79 100644 --- a/src/plugins/platforms/directfb/qdirectfbinput.h +++ b/src/plugins/platforms/directfb/qdirectfbinput.h @@ -75,7 +75,6 @@ private: void handleGotFocusEvent(const DFBEvent &event); void handleCloseEvent(const DFBEvent& event); void handleGeometryEvent(const DFBEvent& event); - inline QPoint globalPoint(const DFBEvent &event) const; IDirectFB *m_dfbInterface; diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.cpp b/src/plugins/platforms/directfb/qdirectfbintegration.cpp index 27d070b75d..fe11cbebc4 100644 --- a/src/plugins/platforms/directfb/qdirectfbintegration.cpp +++ b/src/plugins/platforms/directfb/qdirectfbintegration.cpp @@ -48,6 +48,7 @@ #include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> #include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixservices_p.h> #include <QtGui/private/qpixmap_blitter_p.h> #include <QtGui/private/qpixmap_raster_p.h> @@ -56,11 +57,13 @@ #include <QtCore/QCoreApplication> #include <QtCore/QThread> #include <QtCore/QAbstractEventDispatcher> +#include <qpa/qplatforminputcontextfactory_p.h> QT_BEGIN_NAMESPACE QDirectFbIntegration::QDirectFbIntegration() : m_fontDb(new QGenericUnixFontDatabase()) + , m_services(new QGenericUnixServices) { } @@ -69,6 +72,8 @@ void QDirectFbIntegration::connectToDirectFb() initializeDirectFB(); initializeScreen(); initializeInput(); + + m_inputContext = QPlatformInputContextFactory::create(); } bool QDirectFbIntegration::hasCapability(Capability cap) const @@ -155,4 +160,14 @@ QPlatformFontDatabase *QDirectFbIntegration::fontDatabase() const return m_fontDb.data(); } +QPlatformServices *QDirectFbIntegration::services() const +{ + return m_services.data(); +} + +QPlatformNativeInterface *QDirectFbIntegration::nativeInterface() const +{ + return const_cast<QDirectFbIntegration *>(this); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbintegration.h b/src/plugins/platforms/directfb/qdirectfbintegration.h index 8586f33587..eb3ff41961 100644 --- a/src/plugins/platforms/directfb/qdirectfbintegration.h +++ b/src/plugins/platforms/directfb/qdirectfbintegration.h @@ -46,6 +46,7 @@ #include "qdirectfbscreen.h" #include <qpa/qplatformintegration.h> +#include <qpa/qplatformnativeinterface.h> #include <directfb.h> #include <directfb_version.h> @@ -54,7 +55,7 @@ QT_BEGIN_NAMESPACE class QThread; class QAbstractEventDispatcher; -class QDirectFbIntegration : public QPlatformIntegration +class QDirectFbIntegration : public QPlatformIntegration, public QPlatformNativeInterface { public: QDirectFbIntegration(); @@ -69,6 +70,9 @@ public: QAbstractEventDispatcher *createEventDispatcher() const; QPlatformFontDatabase *fontDatabase() const; + QPlatformServices *services() const; + QPlatformInputContext *inputContext() const { return m_inputContext; } + QPlatformNativeInterface *nativeInterface() const; protected: virtual void initializeDirectFB(); @@ -81,7 +85,8 @@ protected: QScopedPointer<QDirectFbInput> m_input; QScopedPointer<QThread> m_inputRunner; QScopedPointer<QPlatformFontDatabase> m_fontDb; - + QScopedPointer<QPlatformServices> m_services; + QPlatformInputContext *m_inputContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.cpp b/src/plugins/platforms/directfb/qdirectfbwindow.cpp index 6bdfc9f161..52ff1a7704 100644 --- a/src/plugins/platforms/directfb/qdirectfbwindow.cpp +++ b/src/plugins/platforms/directfb/qdirectfbwindow.cpp @@ -67,27 +67,39 @@ void QDirectFbWindow::createDirectFBWindow() DFBWindowDescription description; memset(&description,0,sizeof(DFBWindowDescription)); - description.flags = DFBWindowDescriptionFlags(DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS - |DWDESC_OPTIONS - |DWDESC_CAPS); - description.width = qMax(1, window()->width()); - description.height = qMax(1, window()->height()); - description.posx = window()->x(); - description.posy = window()->y(); - - if (layerConfig.surface_caps & DSCAPS_PREMULTIPLIED) - description.surface_caps = DSCAPS_PREMULTIPLIED; - description.pixelformat = layerConfig.pixelformat; - - description.options = DFBWindowOptions(DWOP_ALPHACHANNEL); - description.caps = DFBWindowCapabilities(DWCAPS_DOUBLEBUFFER|DWCAPS_ALPHACHANNEL); - - DFBResult result = layer->CreateWindow(layer, &description, m_dfbWindow.outPtr()); - if (result != DFB_OK) - DirectFBError("QDirectFbWindow: failed to create window", result); - - m_dfbWindow->SetOpacity(m_dfbWindow.data(), 0xff); - m_inputHandler->addWindow(m_dfbWindow.data(), window()); + + if (window()->type() == Qt::Desktop) { + QRect fullscreenRect(QPoint(), screen()->availableGeometry().size()); + window()->setGeometry(fullscreenRect); + + DFBResult result = layer->CreateWindow(layer, &description, m_dfbWindow.outPtr()); + if (result != DFB_OK) + DirectFBError("QDirectFbWindow: failed to create window", result); + + } else { + description.flags = DFBWindowDescriptionFlags(DWDESC_WIDTH|DWDESC_HEIGHT|DWDESC_POSX|DWDESC_POSY|DWDESC_SURFACE_CAPS + |DWDESC_OPTIONS + |DWDESC_CAPS); + description.width = qMax(1, window()->width()); + description.height = qMax(1, window()->height()); + description.posx = window()->x(); + description.posy = window()->y(); + + if (layerConfig.surface_caps & DSCAPS_PREMULTIPLIED) + description.surface_caps = DSCAPS_PREMULTIPLIED; + description.pixelformat = layerConfig.pixelformat; + + description.options = DFBWindowOptions(DWOP_ALPHACHANNEL); + description.caps = DFBWindowCapabilities(DWCAPS_DOUBLEBUFFER|DWCAPS_ALPHACHANNEL); + + + DFBResult result = layer->CreateWindow(layer, &description, m_dfbWindow.outPtr()); + if (result != DFB_OK) + DirectFBError("QDirectFbWindow: failed to create window", result); + + m_dfbWindow->SetOpacity(m_dfbWindow.data(), 0xff); + m_inputHandler->addWindow(m_dfbWindow.data(), window()); + } } QDirectFbWindow::~QDirectFbWindow() @@ -98,21 +110,9 @@ QDirectFbWindow::~QDirectFbWindow() void QDirectFbWindow::setGeometry(const QRect &rect) { -// bool isMoveOnly = (rect.topLeft() != geometry().topLeft()) && (rect.size() == geometry().size()); - QPlatformWindow::setGeometry(rect); - if (window()->isVisible()) { - m_dfbWindow->SetBounds(m_dfbWindow.data(), rect.x(),rect.y(), - rect.width(), rect.height()); -// ### TODO port, verify if this is needed -#if 0 - //Hack. When moving since the WindowSurface of a window becomes invalid when moved - if (isMoveOnly) { //if resize then windowsurface is updated. - widget()->windowSurface()->resize(rect.size()); - window()->update(); - } -#endif - } + m_dfbWindow->SetBounds(m_dfbWindow.data(), rect.x(),rect.y(), + rect.width(), rect.height()); } void QDirectFbWindow::setOpacity(qreal level) @@ -123,21 +123,23 @@ void QDirectFbWindow::setOpacity(qreal level) void QDirectFbWindow::setVisible(bool visible) { - if (visible) { - int x = geometry().x(); - int y = geometry().y(); - m_dfbWindow->MoveTo(m_dfbWindow.data(), x, y); - } else { - QDirectFBPointer<IDirectFBDisplayLayer> displayLayer; - QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(), DLID_PRIMARY, displayLayer.outPtr()); + if (window()->type() != Qt::Desktop) { + if (visible) { + int x = geometry().x(); + int y = geometry().y(); + m_dfbWindow->MoveTo(m_dfbWindow.data(), x, y); + } else { + QDirectFBPointer<IDirectFBDisplayLayer> displayLayer; + QDirectFbConvenience::dfbInterface()->GetDisplayLayer(QDirectFbConvenience::dfbInterface(), DLID_PRIMARY, displayLayer.outPtr()); + + DFBDisplayLayerConfig config; + displayLayer->GetConfiguration(displayLayer.data(), &config); + m_dfbWindow->MoveTo(m_dfbWindow.data(), config. width + 1, config.height + 1); + } - DFBDisplayLayerConfig config; - displayLayer->GetConfiguration(displayLayer.data(), &config); - m_dfbWindow->MoveTo(m_dfbWindow.data(), config. width + 1, config.height + 1); + if (window()->isTopLevel() && visible) + QPlatformWindow::setVisible(visible); } - - if (window()->isTopLevel() && visible) - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size())); } void QDirectFbWindow::setWindowFlags(Qt::WindowFlags flags) @@ -158,12 +160,14 @@ void QDirectFbWindow::setWindowFlags(Qt::WindowFlags flags) void QDirectFbWindow::raise() { - m_dfbWindow->RaiseToTop(m_dfbWindow.data()); + if (window()->type() != Qt::Desktop) + m_dfbWindow->RaiseToTop(m_dfbWindow.data()); } void QDirectFbWindow::lower() { - m_dfbWindow->LowerToBottom(m_dfbWindow.data()); + if (window()->type() != Qt::Desktop) + m_dfbWindow->LowerToBottom(m_dfbWindow.data()); } WId QDirectFbWindow::winId() const diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm index 4083c2d5a9..0143b75828 100644 --- a/src/plugins/platforms/ios/qioscontext.mm +++ b/src/plugins/platforms/ios/qioscontext.mm @@ -53,14 +53,27 @@ QIOSContext::QIOSContext(QOpenGLContext *context) : QPlatformOpenGLContext() , m_sharedContext(static_cast<QIOSContext *>(context->shareHandle())) - , m_eaglContext([[EAGLContext alloc] - initWithAPI:kEAGLRenderingAPIOpenGLES2 - sharegroup:m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil]) , m_format(context->format()) { m_format.setRenderableType(QSurfaceFormat::OpenGLES); - m_format.setMajorVersion(2); - m_format.setMinorVersion(0); + m_eaglContext = [[EAGLContext alloc] + initWithAPI:EAGLRenderingAPI(m_format.majorVersion()) + sharegroup:m_sharedContext ? [m_sharedContext->m_eaglContext sharegroup] : nil]; + + if (m_eaglContext != nil) { + EAGLContext *originalContext = [EAGLContext currentContext]; + [EAGLContext setCurrentContext:m_eaglContext]; + const GLubyte *s = glGetString(GL_VERSION); + if (s) { + QByteArray version = QByteArray(reinterpret_cast<const char *>(s)); + int major, minor; + if (QPlatformOpenGLContext::parseOpenGLVersion(version, major, minor)) { + m_format.setMajorVersion(major); + m_format.setMinorVersion(minor); + } + } + [EAGLContext setCurrentContext:originalContext]; + } // iOS internally double-buffers its rendering using copy instead of flipping, // so technically we could report that we are single-buffered so that clients diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h index 17184dc21d..20bebb1f3b 100644 --- a/src/plugins/platforms/ios/qiosglobal.h +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -65,4 +65,8 @@ int infoPlistValue(NSString* key, int defaultValue); QT_END_NAMESPACE +@interface UIResponder (QtFirstResponder) ++(id)currentFirstResponder; +@end + #endif // QIOSGLOBAL_H diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index 2ce064582e..7ff4950599 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -141,5 +141,30 @@ int infoPlistValue(NSString* key, int defaultValue) return value ? [value intValue] : defaultValue; } +// ------------------------------------------------------------------------- + +@interface QtFirstResponderEvent : UIEvent +@property (nonatomic, strong) id firstResponder; +@end + +@implementation QtFirstResponderEvent +@end + +@implementation UIResponder (QtFirstResponder) + ++(id)currentFirstResponder +{ + QtFirstResponderEvent *event = [[[QtFirstResponderEvent alloc] init] autorelease]; + [[UIApplication sharedApplication] sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event]; + return event.firstResponder; +} + +- (void)qt_findFirstResponder:(id)sender event:(QtFirstResponderEvent *)event +{ + Q_UNUSED(sender); + event.firstResponder = self; +} +@end + QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm index db579ba559..ad8bd9bdf4 100644 --- a/src/plugins/platforms/ios/qiosplatformaccessibility.mm +++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm @@ -64,9 +64,11 @@ void invalidateCache(QAccessibleInterface *iface) win = parent->window(); parent = parent->parent(); } while (!win && parent); - Q_ASSERT(win && win->handle()); - QIOSWindow *window = static_cast<QIOSWindow*>(win->handle()); - window->clearAccessibleCache(); + + if (win && win->handle()) { + QIOSWindow *window = static_cast<QIOSWindow*>(win->handle()); + window->clearAccessibleCache(); + } } diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm index e7093185aa..e51e97bd5a 100644 --- a/src/plugins/platforms/ios/qiostheme.mm +++ b/src/plugins/platforms/ios/qiostheme.mm @@ -46,6 +46,10 @@ #include <QtGui/QFont> +#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h> +#include <QtGui/private/qguiapplication_p.h> +#include <qpa/qplatformintegration.h> + #include <UIKit/UIFont.h> #include <UIKit/UIInterface.h> @@ -75,19 +79,8 @@ QVariant QIOSTheme::themeHint(ThemeHint hint) const const QFont *QIOSTheme::font(Font type) const { if (m_fonts.isEmpty()) { - // The real system font on iOS is '.Helvetica Neue UI', as returned by both [UIFont systemFontOfSize] - // and CTFontCreateUIFontForLanguage(kCTFontSystemFontType, ...), but this font is not included when - // populating the available fonts in QCoreTextFontDatabase::populateFontDatabase(), since the font - // is internal to iOS and not supposed to be used by applications. We could potentially add this - // font to the font-database, but it would then show up when enumerating user fonts from Qt - // applications since we don't have a flag in Qt to mark a font as a private system font. - // For now we hard-code the font to Helvetica, which should be very close to the actual - // system font. - QLatin1String systemFontFamilyName("Helvetica"); - m_fonts.insert(QPlatformTheme::SystemFont, new QFont(systemFontFamilyName, [UIFont systemFontSize])); - m_fonts.insert(QPlatformTheme::SmallFont, new QFont(systemFontFamilyName, [UIFont smallSystemFontSize])); - m_fonts.insert(QPlatformTheme::LabelFont, new QFont(systemFontFamilyName, [UIFont labelFontSize])); - m_fonts.insert(QPlatformTheme::PushButtonFont, new QFont(systemFontFamilyName, [UIFont buttonFontSize])); + QCoreTextFontDatabase *ctfd = static_cast<QCoreTextFontDatabase *>(QGuiApplicationPrivate::platformIntegration()->fontDatabase()); + m_fonts = ctfd->themeFonts(); } return m_fonts.value(type, 0); diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm index 76bd9bb2b5..d8dd875d83 100644 --- a/src/plugins/platforms/ios/qioswindow.mm +++ b/src/plugins/platforms/ios/qioswindow.mm @@ -85,6 +85,7 @@ QIOSWindow::~QIOSWindow() // cancellation of all touch events. [m_view touchesCancelled:0 withEvent:0]; + clearAccessibleCache(); m_view->m_qioswindow = 0; [m_view removeFromSuperview]; [m_view release]; diff --git a/src/plugins/platforms/ios/quiview_textinput.mm b/src/plugins/platforms/ios/quiview_textinput.mm index 861c8151c6..2280b8259a 100644 --- a/src/plugins/platforms/ios/quiview_textinput.mm +++ b/src/plugins/platforms/ios/quiview_textinput.mm @@ -177,7 +177,7 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); [super becomeFirstResponder]; } -- (void)updateUITextInputDelegate:(NSNumber *)intQuery +- (void)updateUITextInputDelegate:(Qt::InputMethodQueries)query { // As documented, we should not report textWillChange/textDidChange unless the text // was changed externally. That will cause spell checking etc to fail. But we don't @@ -187,7 +187,6 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); if (m_inSendEventToFocusObject) return; - Qt::InputMethodQueries query = Qt::InputMethodQueries([intQuery intValue]); if (query & (Qt::ImCursorPosition | Qt::ImAnchorPosition)) { [self.inputDelegate selectionWillChange:id<UITextInput>(self)]; [self.inputDelegate selectionDidChange:id<UITextInput>(self)]; @@ -213,7 +212,7 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); // not be any performance gain by only updating \a query. staticVariables()->inputMethodQueryEvent = QInputMethodQueryEvent(Qt::ImQueryInput); QCoreApplication::sendEvent(focusObject, &staticVariables()->inputMethodQueryEvent); - [self updateUITextInputDelegate:[NSNumber numberWithInt:int(query)]]; + [self updateUITextInputDelegate:query]; } - (void)sendEventToFocusObject:(QEvent &)e @@ -234,20 +233,23 @@ Q_GLOBAL_STATIC(StaticVariables, staticVariables); { [self setMarkedText:@"" selectedRange:NSMakeRange(0, 0)]; [self updateInputMethodWithQuery:Qt::ImQueryInput]; + // Guard agains recursive callbacks by posting calls to UITextInput - [self performSelectorOnMainThread:@selector(updateKeyboardLayout) withObject:nil waitUntilDone:NO]; - [self performSelectorOnMainThread:@selector(updateUITextInputDelegate:) - withObject:[NSNumber numberWithInt:int(Qt::ImQueryInput)] - waitUntilDone:NO]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateKeyboardLayout]; + [self updateUITextInputDelegate:Qt::ImQueryInput]; + }); } - (void)commit { [self unmarkText]; + // Guard agains recursive callbacks by posting calls to UITextInput - [self performSelectorOnMainThread:@selector(updateUITextInputDelegate:) - withObject:[NSNumber numberWithInt:int(Qt::ImSurroundingText)] - waitUntilDone:NO]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateKeyboardLayout]; + [self updateUITextInputDelegate:Qt::ImSurroundingText]; + }); } - (QVariant)imValue:(Qt::InputMethodQuery)query diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 1b2502af10..8c361d72ca 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -77,6 +77,7 @@ enum WindowsEventType // Simplify event types LeaveEvent = WindowEventFlag + 5, CloseEvent = WindowEventFlag + 6, ShowEvent = WindowEventFlag + 7, + ShowEventOnParentRestoring = WindowEventFlag + 20, HideEvent = WindowEventFlag + 8, DestroyEvent = WindowEventFlag + 9, MoveEvent = WindowEventFlag + 10, @@ -128,7 +129,7 @@ enum ProcessDpiAwareness } // namespace QtWindows -inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn) +inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamIn, LPARAM lParamIn) { switch (message) { case WM_PAINT: @@ -156,7 +157,9 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI case WM_MOVE: return QtWindows::MoveEvent; case WM_SHOWWINDOW: - return wParamIn ? QtWindows::ShowEvent : QtWindows::HideEvent; + if (wParamIn) + return lParamIn == SW_PARENTOPENING ? QtWindows::ShowEventOnParentRestoring : QtWindows::ShowEvent; + return QtWindows::HideEvent; case WM_SIZE: return QtWindows::ResizeEvent; case WM_NCCALCSIZE: diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 34a9c1df5f..40d1108f60 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -43,6 +43,7 @@ #include "qwindowswindow.h" #include "qwindowsnativeimage.h" #include "qwindowscontext.h" +#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <QtGui/QPainter> @@ -75,12 +76,10 @@ QPaintDevice *QWindowsBackingStore::paintDevice() return &m_image->image(); } -void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, - const QPoint &offset) +void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoint &offset) { Q_ASSERT(window); - const QRect br = region.boundingRect(); if (QWindowsContext::verbose > 1) qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br; QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); @@ -90,8 +89,9 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, const Qt::WindowFlags flags = window->flags(); if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) { // Windows with alpha: Use blend function to update. - QRect r = window->frameGeometry(); - QPoint frameOffset(window->frameMargins().left(), window->frameMargins().top()); + const QMargins marginsDP = rw->frameMarginsDp(); + const QRect r = rw->geometryDp() + marginsDP; + const QPoint frameOffset(marginsDP.left(), marginsDP.top()); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; @@ -135,14 +135,15 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, } } -void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) +void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip) { + const QSize size = sizeDip * QWindowsScaling::factor(); if (m_image.isNull() || m_image->image().size() != size) { #ifndef QT_NO_DEBUG_OUTPUT if (QWindowsContext::verbose && lcQpaBackingStore().isDebugEnabled()) { qCDebug(lcQpaBackingStore) - << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << region - << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); + << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << sizeDip << ' ' + << regionDip << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); } #endif const QImage::Format format = window()->format().hasAlpha() ? @@ -151,10 +152,10 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) QWindowsNativeImage *oldwni = m_image.data(); QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); - if (oldwni && !region.isEmpty()) { + if (oldwni && !regionDip.isEmpty()) { const QImage &oldimg(oldwni->image()); QImage &newimg(newwni->image()); - QRegion staticRegion(region); + QRegion staticRegion = QWindowsScaling::mapToNative(regionDip); staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height()); staticRegion &= QRect(0, 0, newimg.width(), newimg.height()); QPainter painter(&newimg); @@ -163,35 +164,38 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) painter.drawImage(rect, oldimg, rect); } + if (QWindowsScaling::isActive()) + newwni->setDevicePixelRatio(QWindowsScaling::factor()); m_image.reset(newwni); } } Q_GUI_EXPORT void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); -bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy) +bool QWindowsBackingStore::scroll(const QRegion &areaDip, int dxDip, int dyDip) { if (m_image.isNull() || m_image->image().isNull()) return false; - const QVector<QRect> rects = area.rects(); + const QPoint dp = QPoint(dxDip, dyDip) * QWindowsScaling::factor(); + const QVector<QRect> rects = areaDip.rects(); for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(m_image->image(), rects.at(i), QPoint(dx, dy)); + qt_scrollRectInImage(m_image->image(), QWindowsScaling::mapToNative(rects.at(i)), dp); return true; } -void QWindowsBackingStore::beginPaint(const QRegion ®ion) +void QWindowsBackingStore::beginPaint(const QRegion ®ionDip) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region; + qCDebug(lcQpaBackingStore) <<__FUNCTION__ << regionDip; if (m_image->image().hasAlphaChannel()) { QPainter p(&m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; - foreach (const QRect &r, region.rects()) - p.fillRect(r, blank); + foreach (const QRect &r, regionDip.rects()) + p.fillRect(QWindowsScaling::mapToNative(r), blank); } } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index e19b8a4db1..9c9500dabb 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -43,6 +43,7 @@ #define QWINDOWSBACKINGSTORE_H #include "qtwindows_additional.h" +#include "qwindowsscaling.h" #include <qpa/qplatformbackingstore.h> #include <QtCore/QScopedPointer> @@ -60,7 +61,12 @@ public: ~QWindowsBackingStore(); QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE + { + flushDp(window, QWindowsScaling::mapToNative(region.boundingRect()), + offset * QWindowsScaling::factor()); + } + void flushDp(QWindow *window, const QRect &boundingRect, const QPoint &offset); void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE; bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; void beginPaint(const QRegion &) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index dc861c963d..132f224382 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -59,6 +59,7 @@ #endif #include "qwindowsscreen.h" #include "qwindowstheme.h" +#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> @@ -88,9 +89,9 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") Q_LOGGING_CATEGORY(lcQpaGl, "qt.qpa.gl") Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime") -Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.inputmethods") +Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods") Q_LOGGING_CATEGORY(lcQpaDialogs, "qt.qpa.dialogs") -Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.tabletsupport") +Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility") int QWindowsContext::verbose = 0; @@ -1051,6 +1052,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::FocusOutEvent: handleFocusEvent(et, platformWindow); return true; + case QtWindows::ShowEventOnParentRestoring: // QTBUG-40696, prevent Windows from re-showing hidden transient children (dialogs). + if (!platformWindow->window()->isVisible()) { + *result = 0; + return true; + } + break; case QtWindows::HideEvent: platformWindow->handleHidden(); return false;// Indicate transient children should be hidden by windows (SW_PARENTCLOSING) @@ -1212,7 +1219,9 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) } } - QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos, + QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, + pos / QWindowsScaling::factor(), + globalPos / QWindowsScaling::factor(), QWindowsKeyMapper::queryKeyboardModifiers()); return true; } @@ -1240,7 +1249,7 @@ void QWindowsContext::setAsyncExpose(bool value) extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT result; - const QtWindows::WindowsEventType et = windowsEventType(message, wParam); + const QtWindows::WindowsEventType et = windowsEventType(message, wParam, lParam); const bool handled = QWindowsContext::instance()->windowsProc(hwnd, message, et, wParam, lParam, &result); if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) { if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) { diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 8352dac0b6..eca8a33215 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -44,6 +44,7 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsscreen.h" +#include "qwindowsscaling.h" #include <QtGui/QBitmap> #include <QtGui/QImage> @@ -624,9 +625,15 @@ QWindowsCursor::CursorState QWindowsCursor::cursorState() return CursorHidden; } +QPoint QWindowsCursor::pos() const +{ + return mousePosition() / QWindowsScaling::factor(); +} + void QWindowsCursor::setPos(const QPoint &pos) { - SetCursorPos(pos.x(), pos.y()); + const QPoint posDp = pos * QWindowsScaling::factor(); + SetCursorPos(posDp.x() , posDp.y()); } /*! diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index 34cb668856..89214156e8 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -102,7 +102,7 @@ public: QWindowsCursor() {} void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE; - QPoint pos() const Q_DECL_OVERRIDE { return mousePosition(); } + QPoint pos() const Q_DECL_OVERRIDE; void setPos(const QPoint &pos) Q_DECL_OVERRIDE; static HCURSOR createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index f70b5b4e2b..1f930822d8 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -1273,7 +1273,6 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel { wchar_t *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16())); switch (l) { - break; case QFileDialogOptions::FileName: m_fileDialog->SetFileNameLabel(wText); break; diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 716d892472..e1b4aca0c4 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -41,6 +41,7 @@ #include "qwindowsdrag.h" #include "qwindowscontext.h" +#include "qwindowsscaling.h" #ifndef QT_NO_CLIPBOARD # include "qwindowsclipboard.h" #endif @@ -50,6 +51,7 @@ #include "qwindowswindow.h" #include "qwindowsmousehandler.h" #include "qwindowscursor.h" +#include "qwindowsscaling.h" #include <QtGui/QMouseEvent> #include <QtGui/QPixmap> @@ -295,12 +297,19 @@ void QWindowsOleDropSource::createCursors() const QDrag *drag = m_drag->currentDrag(); const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); + const int scaleFactor = QWindowsScaling::factor(); + const QSize pixmapSizeDp = pixmap.size() * scaleFactor; + const bool scalePixmap = hasPixmap + && m_mode != TouchDrag // Touch drag: pixmap is shown in a separate QWindow, which will be scaled. + && (scaleFactor != 1 && scaleFactor != qRound(pixmap.devicePixelRatio())); + const QPixmap drawPixmap = scalePixmap + ? pixmap.scaled(pixmapSizeDp, Qt::KeepAspectRatio, Qt::SmoothTransformation) : pixmap; Qt::DropAction actions[] = { Qt::MoveAction, Qt::CopyAction, Qt::LinkAction, Qt::IgnoreAction }; int actionCount = int(sizeof(actions) / sizeof(actions[0])); if (!hasPixmap) --actionCount; // No Qt::IgnoreAction unless pixmap - const QPoint hotSpot = drag->hotSpot(); + const QPoint hotSpot = drag->hotSpot() * scaleFactor; for (int cnum = 0; cnum < actionCount; ++cnum) { const Qt::DropAction action = actions[cnum]; QPixmap cursorPixmap = drag->dragCursor(action); @@ -320,15 +329,14 @@ void QWindowsOleDropSource::createCursors() if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); - const int x2 = qMax(pixmap.width() - hotSpot.x(), cursorPixmap.width()); + const int x2 = qMax(pixmapSizeDp.width() - hotSpot.x(), cursorPixmap.width()); const int y1 = qMin(-hotSpot.y(), 0); - const int y2 = qMax(pixmap.height() - hotSpot.y(), cursorPixmap.height()); + const int y2 = qMax(pixmapSizeDp.height() - hotSpot.y(), cursorPixmap.height()); QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1); newCursor.fill(Qt::transparent); QPainter p(&newCursor); - const QRect srcRect = pixmap.rect(); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); - p.drawPixmap(pmDest, pixmap, srcRect); + p.drawPixmap(pmDest, drawPixmap); p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); newPixmap = newCursor; newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); @@ -454,7 +462,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) if (!m_touchDragWindow) m_touchDragWindow = new QWindowsDragCursorWindow; m_touchDragWindow->setPixmap(e.pixmap); - m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot); + m_touchDragWindow->setFramePosition((QWindowsCursor::mousePosition() - e.hotSpot) / QWindowsScaling::factor()); if (!m_touchDragWindow->isVisible()) m_touchDragWindow->show(); break; @@ -530,7 +538,9 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); const QPlatformDragQtResponse response = - QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); + QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), + m_lastPoint / QWindowsScaling::factor(), + actions); m_answerRect = response.answerRect(); const Qt::DropAction action = response.acceptedAction(); @@ -622,7 +632,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const QPlatformDropQtResponse response = - QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint, + QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), + m_lastPoint / QWindowsScaling::factor(), translateToQDragDropActions(*pdwEffect)); if (response.isAccepted()) { diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index d3cbea0b92..35b7f13ea4 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -1345,6 +1345,7 @@ void QWindowsMultiFontEngine::loadEngine(int at) fontEngine->fontDef.pixelSize, data); fedw->fontDef = fontDef; + fedw->fontDef.family = fam; fedw->ref.ref(); engines[at] = fedw; @@ -1370,6 +1371,7 @@ void QWindowsMultiFontEngine::loadEngine(int at) engines[at] = new QWindowsFontEngine(fam, hfont, stockFont, lf, data); engines[at]->ref.ref(); engines[at]->fontDef = fontDef; + engines[at]->fontDef.family = fam; qCDebug(lcQpaFonts) << __FUNCTION__ << at << fam; // TODO: increase cost in QFontCache for the font engine loaded here diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index 8f55e20536..15b14aff1a 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -574,7 +574,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, int size = width * height * 3; BYTE *alphaValues = new BYTE[size]; - memset(alphaValues, size, 0); + memset(alphaValues, 0, size); hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index f8676c30f7..2284c47ed6 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -44,6 +44,7 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsmousehandler.h" +#include "qwindowsscaling.h" #include <QtCore/QDebug> #include <QtCore/QObject> @@ -214,9 +215,10 @@ void QWindowsInputContext::cursorRectChanged() if (!m_compositionContext.hwnd) return; const QInputMethod *inputMethod = QGuiApplication::inputMethod(); - QRect cursorRectangle = inputMethod->cursorRectangle().toRect(); - if (!cursorRectangle.isValid()) + const QRect cursorRectangleDip = inputMethod->cursorRectangle().toRect(); + if (!cursorRectangleDip.isValid()) return; + const QRect cursorRectangle = QWindowsScaling::mapToNative(cursorRectangleDip); qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 7c50ac69c2..7afda853e8 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -41,6 +41,7 @@ ****************************************************************************/ #include "qwindowsintegration.h" +#include "qwindowsscaling.h" #include "qwindowswindow.h" #include "qwindowscontext.h" #include "qwindowsopenglcontext.h" @@ -229,6 +230,12 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL m_context.setProcessDpiAwareness(dpiAwareness); dpiAwarenessSet = true; } + // Determine suitable scale factor, don't mix Windows and Qt scaling + if (dpiAwareness != QtWindows::ProcessDpiUnaware) + QWindowsScaling::setFactor(QWindowsScaling::determineUiScaleFactor()); + qCDebug(lcQpaWindows) + << __FUNCTION__ << "DpiAwareness=" << dpiAwareness <<",Scaling=" + << QWindowsScaling::factor(); } QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate() @@ -289,7 +296,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const { QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = window->geometry(); + requested.geometry = QWindowsScaling::mapToNative(window->geometry()); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) @@ -310,7 +317,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const window->setFlags(obtained.flags); // Trigger geometry change signals of QWindow. if ((obtained.flags & Qt::Desktop) != Qt::Desktop && requested.geometry != obtained.geometry) - QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); + QWindowSystemInterface::handleGeometryChange(window, QWindowsScaling::mapFromNative(obtained.geometry)); } #ifndef QT_NO_OPENGL diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index dc1de047fe..540236bda7 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -43,6 +43,7 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsguieventdispatcher.h" +#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> @@ -767,11 +768,10 @@ static void showSystemMenu(QWindow* w) #undef enabled #undef disabled #endif // !Q_OS_WINCE + const QPoint topLeft = topLevel->geometry().topLeft() * QWindowsScaling::factor(); const int ret = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, - topLevel->geometry().x(), topLevel->geometry().y(), - topLevelHwnd, - 0); + topLeft.x(), topLeft.y(), topLevelHwnd, 0); if (ret) qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, ret, 0); } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 4633378342..2e677102a5 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -191,8 +191,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, const QPoint globalPosition = winEventPosition; const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); - QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, - globalPosition, buttons, + QWindowSystemInterface::handleFrameStrutMouseEvent(window, + clientPosition / QWindowsScaling::factor(), + globalPosition / QWindowsScaling::factor(), + buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); return false; // Allow further event processing (dragging of windows). @@ -334,7 +336,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, m_windowUnderMouse = currentWindowUnderMouse; } - QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, + QWindowSystemInterface::handleMouseEvent(window, + winEventPosition / QWindowsScaling::factor(), + globalPosition / QWindowsScaling::factor(), + buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); m_previousCaptureWindow = hasCapture ? window : 0; @@ -388,10 +393,11 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND, } if (handleEvent) { + const QPoint posDip = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos) / QWindowsScaling::factor(); QWindowSystemInterface::handleWheelEvent(receiver, - QWindowsGeometryHint::mapFromGlobal(receiver, globalPos), - globalPos, - delta, orientation, mods); + posDip, globalPos / QWindowsScaling::factor(), + delta / QWindowsScaling::factor(), + orientation, mods); } return true; @@ -419,6 +425,7 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo); QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + const qreal screenPosFactor = 0.01 / qreal(QWindowsScaling::factor()); for (int i = 0; i < winTouchPointCount; ++i) { const TOUCHINPUT &winTouchInput = winTouchInputs[i]; int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1); @@ -432,10 +439,9 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, if (m_lastTouchPositions.contains(id)) touchPoint.normalPosition = m_lastTouchPositions.value(id); - QPointF screenPos = QPointF(qreal(winTouchInput.x) / qreal(100.), qreal(winTouchInput.y) / qreal(100.)); + const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) * screenPosFactor; if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA) - touchPoint.area.setSize(QSizeF(qreal(winTouchInput.cxContact) / qreal(100.), - qreal(winTouchInput.cyContact) / qreal(100.))); + touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) * screenPosFactor); touchPoint.area.moveCenter(screenPos); QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(), screenPos.y() / screenGeometry.height()); diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h index 399bead323..98b7fc9bc5 100644 --- a/src/plugins/platforms/windows/qwindowsnativeimage.h +++ b/src/plugins/platforms/windows/qwindowsnativeimage.h @@ -67,6 +67,8 @@ public: HDC hdc() const { return m_hdc; } + void setDevicePixelRatio(qreal scaleFactor) { m_image.setDevicePixelRatio(scaleFactor); } + static QImage::Format systemFormat(); private: diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index ce28166e4f..06f9f709c9 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -64,7 +64,7 @@ enum ResourceType { static int resourceType(const QByteArray &key) { - static const QByteArray names[] = { // match ResourceType + static const char *names[] = { // match ResourceType "renderingcontext", "eglcontext", "egldisplay", @@ -74,8 +74,8 @@ static int resourceType(const QByteArray &key) "getdc", "releasedc" }; - const QByteArray *end = names + sizeof(names) / sizeof(names[0]); - const QByteArray *result = std::find(names, end, key); + const char ** const end = names + sizeof(names) / sizeof(names[0]); + const char **result = std::find(names, end, key); if (result == end) result = std::find(names, end, key.toLower()); return int(result - names); diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.h b/src/plugins/platforms/windows/qwindowsscaling.cpp index 50c0d497af..fcc3440b42 100644 --- a/src/plugins/platforms/android/qandroidplatformrasterwindow.h +++ b/src/plugins/platforms/windows/qwindowsscaling.cpp @@ -1,7 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. @@ -40,31 +39,41 @@ ** ****************************************************************************/ -#ifndef QANDROIDPLATFORMRASTERWINDOW_H -#define QANDROIDPLATFORMRASTERWINDOW_H +#include "qwindowsscaling.h" +#include "qwindowsscreen.h" + +#include <QtCore/QDebug> +#include <QtCore/QCoreApplication> -#include "qandroidplatformwindow.h" QT_BEGIN_NAMESPACE -class QAndroidPlatformBackingStore; -class QAndroidPlatformRasterWindow : public QObject, public QAndroidPlatformWindow -{ - Q_OBJECT -public: - QAndroidPlatformRasterWindow(QWindow *window); +/*! + \class QWindowsScaling + \brief Windows scaling utilities - void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; } - QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; } - void repaint(const QRegion®ion); + \internal + \ingroup qt-lighthouse-win +*/ -public slots: - void setGeometry(const QRect &rect); +int QWindowsScaling::m_factor = 1; -private: - QAndroidPlatformBackingStore *m_backingStore = nullptr; - QRect m_oldGeometry; +static const char devicePixelRatioEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; -}; +// Suggest a scale factor by checking monitor sizes. +int QWindowsScaling::determineUiScaleFactor() +{ + if (!qEnvironmentVariableIsSet(devicePixelRatioEnvVar)) + return 1; + const QByteArray envDevicePixelRatioEnv = qgetenv(devicePixelRatioEnvVar); + // Auto: Suggest a scale factor by checking monitor resolution. + if (envDevicePixelRatioEnv == QByteArrayLiteral("auto")) { + const int maxResolution = QWindowsScreen::maxMonitorHorizResolution(); + return maxResolution > 180 ? maxResolution / 96 : 1; + } + // Get factor from environment + bool ok = false; + const int envFactor = envDevicePixelRatioEnv.toInt(&ok); + return ok && envFactor > 0 ? envFactor : 1; +} QT_END_NAMESPACE -#endif // QANDROIDPLATFORMRASTERWINDOW_H diff --git a/src/plugins/platforms/windows/qwindowsscaling.h b/src/plugins/platforms/windows/qwindowsscaling.h new file mode 100644 index 0000000000..99fec7c810 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsscaling.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSSCALING_H +#define QWINDOWSSCALING_H + +#include <QtGui/QRegion> +#include <QtCore/QVector> +#include <QtCore/QRect> + +QT_BEGIN_NAMESPACE + +enum +#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) + : int +#endif +{ QWINDOWSIZE_MAX = 16777215 }; + +class QWindowsScaling { +public: + static bool isActive() { return m_factor > 1; } + static int factor() { return m_factor; } + static void setFactor(int factor) { m_factor = factor; } + static int determineUiScaleFactor(); + + // Scaling helpers for size constraints. + static int mapToNativeConstrained(int qt) + { return m_factor != 1 && qt > 0 && qt < QWINDOWSIZE_MAX ? qt * m_factor : qt; } + + static int mapFromNativeConstrained(int dp) + { return m_factor != 1 && dp > 0 && dp < QWINDOWSIZE_MAX ? dp / m_factor : dp; } + + static QSize mapToNativeConstrained(const QSize &qt) + { return QSize(mapToNativeConstrained(qt.width()), mapToNativeConstrained(qt.height())); } + + static QRect mapToNative(const QRect &qRect) + { + return QRect(qRect.x() * m_factor, qRect.y() * m_factor, qRect.width() * m_factor, qRect.height() * m_factor); + } + + static QRect mapFromNative(const QRect &dp) + { + return isActive() ? + QRect(dp.x() / m_factor, dp.y() / m_factor, (dp.width() + 1) / m_factor, (dp.height() + 1) / m_factor) : + dp; + } + + static QRegion mapToNative(const QRegion ®ionQt) + { + if (!QWindowsScaling::isActive() || regionQt.isEmpty()) + return regionQt; + + QRegion result; + foreach (const QRect &rectQt, regionQt.rects()) + result += QWindowsScaling::mapToNative(rectQt); + return result; + } + + static QRegion mapFromNative(const QRegion ®ionDp) + { + if (!QWindowsScaling::isActive() || regionDp.isEmpty()) + return regionDp; + + QRegion result; + foreach (const QRect &rectDp, regionDp.rects()) + result += QWindowsScaling::mapFromNative(rectDp); + return result; + } + +private: + static int m_factor; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSSCALING_H diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index bcdb8a2352..a5a291a8d8 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -101,21 +101,19 @@ static inline QDpi deviceDPI(const QSize &pixels, const QSizeF &physicalSizeMM) typedef QList<QWindowsScreenData> WindowsScreenDataList; -// from QDesktopWidget, taking WindowsScreenDataList as LPARAM -BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) { MONITORINFOEX info; memset(&info, 0, sizeof(MONITORINFOEX)); info.cbSize = sizeof(MONITORINFOEX); if (GetMonitorInfo(hMonitor, &info) == FALSE) - return TRUE; + return false; - WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); - QWindowsScreenData data; - data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); - data.name = QString::fromWCharArray(info.szDevice); - if (data.name == QLatin1String("WinDisc")) { - data.flags |= QWindowsScreenData::LockScreen; + data->geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); + data->availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); + data->name = QString::fromWCharArray(info.szDevice); + if (data->name == QLatin1String("WinDisc")) { + data->flags |= QWindowsScreenData::LockScreen; } else { #ifdef Q_OS_WINCE //Windows CE, just supports one Display and expects to get only DISPLAY, @@ -127,40 +125,48 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM if (hdc) { #ifndef Q_OS_WINCE const QDpi dpi = monitorDPI(hMonitor); - data.dpi = dpi.first ? dpi : deviceDPI(hdc); + data->dpi = dpi.first ? dpi : deviceDPI(hdc); #else - data.dpi = deviceDPI(hdc); + data->dpi = deviceDPI(hdc); #endif - data.depth = GetDeviceCaps(hdc, BITSPIXEL); - data.format = data.depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; - data.physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); + data->depth = GetDeviceCaps(hdc, BITSPIXEL); + data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; + data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); const int refreshRate = GetDeviceCaps(hdc, VREFRESH); if (refreshRate > 1) // 0,1 means hardware default. - data.refreshRateHz = refreshRate; + data->refreshRateHz = refreshRate; DeleteDC(hdc); } else { qWarning("%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.", __FUNCTION__, qPrintable(QString::fromWCharArray(info.szDevice)), - data.dpi.first); + data->dpi.first); } // CreateDC() failed } // not lock screen - data.geometry = QRect(QPoint(info.rcMonitor.left, info.rcMonitor.top), QPoint(info.rcMonitor.right - 1, info.rcMonitor.bottom - 1)); - data.availableGeometry = QRect(QPoint(info.rcWork.left, info.rcWork.top), QPoint(info.rcWork.right - 1, info.rcWork.bottom - 1)); - data.orientation = data.geometry.height() > data.geometry.width() ? + data->orientation = data->geometry.height() > data->geometry.width() ? Qt::PortraitOrientation : Qt::LandscapeOrientation; // EnumDisplayMonitors (as opposed to EnumDisplayDevices) enumerates only // virtual desktop screens. - data.flags |= QWindowsScreenData::VirtualDesktop; - if (info.dwFlags & MONITORINFOF_PRIMARY) { - data.flags |= QWindowsScreenData::PrimaryScreen; + data->flags |= QWindowsScreenData::VirtualDesktop; + if (info.dwFlags & MONITORINFOF_PRIMARY) + data->flags |= QWindowsScreenData::PrimaryScreen; + return true; +} + +// from QDesktopWidget, taking WindowsScreenDataList as LPARAM +BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +{ + QWindowsScreenData data; + if (monitorData(hMonitor, &data)) { + WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); // QPlatformIntegration::screenAdded() documentation specifies that first // added screen will be the primary screen, so order accordingly. // Note that the side effect of this policy is that there is no way to change primary // screen reported by Qt, unless we want to delete all existing screens and add them // again whenever primary screen changes. - result->prepend(data); - } else { - result->append(data); + if (data.flags & QWindowsScreenData::PrimaryScreen) + result->prepend(data); + else + result->append(data); } return TRUE; } @@ -217,14 +223,36 @@ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) : { } +BOOL QT_WIN_CALLBACK monitorResolutionEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) +{ + QWindowsScreenData data; + if (monitorData(hMonitor, &data)) { + int *maxHorizResolution = reinterpret_cast<int *>(p); + const int horizResolution = qRound(data.dpi.first); + if (horizResolution > *maxHorizResolution) + *maxHorizResolution = horizResolution; + } + return TRUE; +} + +int QWindowsScreen::maxMonitorHorizResolution() +{ + int result = 0; + EnumDisplayMonitors(0, 0, monitorResolutionEnumCallback, (LPARAM)&result); + return result; +} + Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); -QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const +QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const { RECT r; HWND hwnd = window ? (HWND)window : GetDesktopWindow(); GetClientRect(hwnd, &r); - + const int x = qX * QWindowsScaling::factor(); + const int y = qY * QWindowsScaling::factor(); + int width = qWidth * QWindowsScaling::factor(); + int height = qHeight * QWindowsScaling::factor(); if (width < 0) width = r.right - r.left; if (height < 0) height = r.bottom - r.top; @@ -248,6 +276,10 @@ QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int heig DeleteObject(bitmap); ReleaseDC(0, display_dc); + if (QWindowsScaling::isActive()) { + const qreal factor = 1.0 / qreal(QWindowsScaling::factor()); + return pixmap.transformed(QTransform::fromScale(factor, factor)); + } return pixmap; } diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index c9d8a5662c..49581db41a 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -43,11 +43,13 @@ #define QWINDOWSSCREEN_H #include "qwindowscursor.h" +#include "qwindowsscaling.h" #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif #include <QtCore/QList> +#include <QtCore/QVector> #include <QtCore/QPair> #include <QtCore/QSharedPointer> #include <qpa/qplatformscreen.h> @@ -88,24 +90,28 @@ public: static QWindowsScreen *screenOf(const QWindow *w = 0); - QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } - QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; } + QRect geometryDp() const { return m_data.geometry; } + QRect geometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(geometryDp()); } + QRect availableGeometryDp() const { return m_data.availableGeometry; } + QRect availableGeometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(availableGeometryDp()); } int depth() const Q_DECL_OVERRIDE { return m_data.depth; } QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; } QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; } - QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_data.dpi; } + QDpi logicalDpi() const Q_DECL_OVERRIDE + { return QDpi(m_data.dpi.first / QWindowsScaling::factor(), m_data.dpi.second / QWindowsScaling::factor()); } + qreal devicePixelRatio() const Q_DECL_OVERRIDE { return QWindowsScaling::factor(); } qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } QString name() const Q_DECL_OVERRIDE { return m_data.name; } Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; } QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE; QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE - { return QWindowsScreen::findTopLevelAt(point, CWP_SKIPINVISIBLE); } + { return QWindowsScreen::findTopLevelAt(point * QWindowsScaling::factor() , CWP_SKIPINVISIBLE); } static QWindow *findTopLevelAt(const QPoint &point, unsigned flags); static QWindow *windowAt(const QPoint &point, unsigned flags = CWP_SKIPINVISIBLE); static QWindow *windowUnderMouse(unsigned flags = CWP_SKIPINVISIBLE); - QPixmap grabWindow(WId window, int x, int y, int width, int height) const Q_DECL_OVERRIDE; + QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const Q_DECL_OVERRIDE; inline void handleChanges(const QWindowsScreenData &newData); @@ -117,6 +123,7 @@ public: #endif // !QT_NO_CURSOR const QWindowsScreenData &data() const { return m_data; } + static int maxMonitorHorizResolution(); private: QWindowsScreenData m_data; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index d1737de907..7d020ff9d6 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qwindowstabletsupport.h" +#include "qwindowsscaling.h" #ifndef QT_NO_TABLETEVENT @@ -275,6 +276,8 @@ static inline QTabletEvent::TabletDevice deviceType(const UINT cursorType) { if (((cursorType & 0x0006) == 0x0002) && ((cursorType & CursorTypeBitMask) != 0x0902)) return QTabletEvent::Stylus; + if (cursorType == 0x4020) // Surface Pro 2 tablet device + return QTabletEvent::Stylus; switch (cursorType & CursorTypeBitMask) { case 0x0802: return QTabletEvent::Stylus; @@ -403,7 +406,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() // in which case we snap the position to the mouse position. // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext // area is always the virtual desktop. - const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); + const QRect virtualDesktopArea + = QWindowsScaling::mapToNative(QGuiApplication::primaryScreen()->virtualGeometry()); qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount << "target:" << QGuiApplicationPrivate::tabletPressTarget; @@ -423,7 +427,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() QPoint globalPos = globalPosF.toPoint(); // Get Mouse Position and compare to tablet info - const QPoint mouseLocation = QWindowsCursor::mousePosition(); + QPoint mouseLocation = QWindowsCursor::mousePosition(); // Positions should be almost the same if we are in absolute // mode. If they are not, use the mouse location. @@ -479,7 +483,9 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - QWindowSystemInterface::handleTabletEvent(target, QPointF(localPos), globalPosF, + const QPointF localPosDip = QPointF(localPos / QWindowsScaling::factor()); + const QPointF globalPosDip = globalPosF / qreal(QWindowsScaling::factor()); + QWindowSystemInterface::handleTabletEvent(target, localPosDip, globalPosDip, currentDevice, currentPointer, static_cast<Qt::MouseButtons>(packet.pkButtons), pressureNew, tiltX, tiltY, diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 3b54feabbf..e6b996c685 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -44,6 +44,7 @@ #include "qwindowscontext.h" #include "qwindowsdrag.h" #include "qwindowsscreen.h" +#include "qwindowsscaling.h" #ifdef QT_NO_CURSOR # include "qwindowscursor.h" #endif @@ -576,7 +577,9 @@ QWindowsWindowData const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL); - QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); + const QRect geometryDip = QWindowsScaling::mapFromNative(data.geometry); + QRect fixedGeometryDip = QPlatformWindow::initialGeometry(w, geometryDip, defaultWindowWidth, defaultWindowHeight); + const QRect rect = fixedGeometryDip != geometryDip ? QWindowsScaling::mapToNative(fixedGeometryDip) : data.geometry; if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); @@ -683,11 +686,9 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe \ingroup qt-lighthouse-win */ -#define QWINDOWSIZE_MAX ((1<<24)-1) - QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : - minimumSize(w->minimumSize()), - maximumSize(w->maximumSize()), + minimumSize(QWindowsScaling::mapToNativeConstrained(w->minimumSize())), + maximumSize(QWindowsScaling::mapToNativeConstrained(w->maximumSize())), customMargins(cm) { } @@ -930,7 +931,8 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) clearFlag(Exposed); else setFlag(Exposed); - QWindowSystemInterface::handleExposeEvent(window(), region); + QWindowSystemInterface::handleExposeEvent(window(), + QWindowsScaling::mapFromNative(region)); } static inline QWindow *findTransientChild(const QWindow *parent) @@ -1106,7 +1108,7 @@ bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const return m_data.embedded; } -QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const +QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos); @@ -1114,7 +1116,7 @@ QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const return pos; } -QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const +QPoint QWindowsWindow::mapFromGlobalDp(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos); @@ -1286,22 +1288,22 @@ static QRect normalFrameGeometry(HWND hwnd) return QRect(); } -QRect QWindowsWindow::normalGeometry() const +QRect QWindowsWindow::normalGeometryDp() const { // Check for fake 'fullscreen' mode. const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); - const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); + const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMarginsDp(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; } -void QWindowsWindow::setGeometry(const QRect &rectIn) +void QWindowsWindow::setGeometryDp(const QRect &rectIn) { QRect rect = rectIn; // This means it is a call from QWindow::setFramePosition() and // the coordinates include the frame (size is still the contents rectangle). if (QWindowsGeometryHint::positionIncludesFrame(window())) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); } const QSize oldSize = m_data.geometry.size(); @@ -1383,8 +1385,9 @@ void QWindowsWindow::handleGeometryChange() return; const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); - QPlatformWindow::setGeometry(m_data.geometry); - QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); + const QRect geometryDip = QWindowsScaling::mapFromNative(m_data.geometry); + QPlatformWindow::setGeometry(geometryDip); + QWindowSystemInterface::handleGeometryChange(window(), geometryDip); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive // expose events when shrinking, synthesize. if (!testFlag(OpenGL_ES2) && isExposed() @@ -1404,7 +1407,7 @@ void QWindowsWindow::handleGeometryChange() void QWindowsWindow::setGeometry_sys(const QRect &rect) const { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); const QRect frameGeometry = rect + margins; qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() @@ -1441,7 +1444,7 @@ QRect QWindowsWindow::frameGeometry_sys() const QRect QWindowsWindow::geometry_sys() const { - return frameGeometry_sys().marginsRemoved(frameMargins()); + return frameGeometry_sys().marginsRemoved(frameMarginsDp()); } /*! @@ -1514,7 +1517,7 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: " << QWindowsWindow::debugWindowFlags(m_data.flags) << "\n to: " << QWindowsWindow::debugWindowFlags(flags); - const QRect oldGeometry = geometry(); + const QRect oldGeometry = geometryDp(); if (m_data.flags != flags) { m_data.flags = flags; if (m_data.hwnd) { @@ -1602,7 +1605,8 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() && geometry_sys() == window()->screen()->geometry(); + return window()->isTopLevel() + && geometry_sys() == QWindowsScaling::mapToNative(window()->screen()->geometry()); } /*! @@ -1683,14 +1687,15 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). const QScreen *screen = window()->screen(); - const QRect r = screen->geometry(); + const QRect rDip = screen->geometry(); + const QRect r = QWindowsScaling::mapToNative(rDip); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); if (!wasSync) clearFlag(SynchronousGeometryChangeEvent); - QWindowSystemInterface::handleGeometryChange(window(), r); + QWindowSystemInterface::handleGeometryChange(window(), rDip); QWindowSystemInterface::flushWindowSystemEvents(); } else if (newState != Qt::WindowMinimized) { // Restore saved state. @@ -1778,7 +1783,7 @@ void QWindowsWindow::propagateSizeHints() qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); } -QMargins QWindowsWindow::frameMargins() const +QMargins QWindowsWindow::frameMarginsDp() const { // Frames are invalidated by style changes (window state, flags). // As they are also required for geometry calculations in resize @@ -1820,17 +1825,17 @@ static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion) } } -static HRGN qRegionToWinRegion(const QRegion ®ion) +static HRGN qRegionToWinRegion(const QRegion ®ionDip) { - const QVector<QRect> rects = region.rects(); + const QVector<QRect> rects = regionDip.rects(); if (rects.isEmpty()) return NULL; const int rectCount = rects.size(); if (rectCount == 1) - return createRectRegion(region.boundingRect()); + return createRectRegion(QWindowsScaling::mapToNative(regionDip.boundingRect())); HRGN hRegion = createRectRegion(rects.front()); for (int i = 1; i < rectCount; ++i) - addRectToWinRegion(rects.at(i), &hRegion); + addRectToWinRegion(QWindowsScaling::mapToNative(rects.at(i)), &hRegion); return hRegion; } @@ -1844,7 +1849,7 @@ void QWindowsWindow::setMask(const QRegion ®ion) // Mask is in client area coordinates, so offset it in case we have a frame if (window()->isTopLevel()) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); OffsetRgn(winRegion, margins.left(), margins.top()); } @@ -1981,23 +1986,23 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re || (m_data.flags & Qt::FramelessWindowHint)) { return false; } - const QSize minimumSize = w->minimumSize(); + const QSize minimumSize = QWindowsScaling::mapToNativeConstrained(w->minimumSize()); if (minimumSize.isEmpty()) return false; - const QSize maximumSize = w->maximumSize(); + const QSize maximumSize = QWindowsScaling::mapToNativeConstrained(w->maximumSize()); const bool fixedWidth = minimumSize.width() == maximumSize.width(); const bool fixedHeight = minimumSize.height() == maximumSize.height(); if (!fixedWidth && !fixedHeight) return false; - const QPoint localPos = w->mapFromGlobal(globalPos); - const QSize size = w->size(); + const QPoint localPos = mapFromGlobalDp(globalPos); + const QSize size = w->size() * QWindowsScaling::factor(); if (fixedHeight) { if (localPos.y() >= size.height()) { *result = HTBORDER; // Unspecified border, no resize cursor. return true; } if (localPos.y() < 0) { - const QMargins margins = frameMargins(); + const QMargins margins = frameMarginsDp(); const int topResizeBarPos = margins.left() - margins.top(); if (localPos.y() < topResizeBarPos) { *result = HTCAPTION; // Extend caption over top resize bar, let's user move the window. @@ -2249,6 +2254,10 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon) The property can be set using QPlatformNativeInterface::setWindowProperty() or, before platform window creation, by setting a dynamic property on the QWindow (see QWindowsIntegration::createPlatformWindow()). + + Note: The function uses (unscaled) device pixels since the QWizard also + uses AdjustWindowRect() and using device independent pixels would introduce + rounding errors. */ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 19d2236688..cb9da6fe27 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -46,6 +46,7 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif +#include "qwindowsscaling.h" #include "qwindowscursor.h" #include "qwindowsopenglcontext.h" @@ -152,18 +153,28 @@ public: ~QWindowsWindow(); QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; - QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } - QRect normalGeometry() const Q_DECL_OVERRIDE; - + void setGeometryDp(const QRect &rectIn); + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE + { setGeometryDp(QWindowsScaling::mapToNative(rect)); } + QRect geometryDp() const { return m_data.geometry; } + QRect geometry() const Q_DECL_OVERRIDE + { return QWindowsScaling::mapFromNative(geometryDp()); } + QRect normalGeometryDp() const; + QRect normalGeometry() const Q_DECL_OVERRIDE + { return QWindowsScaling::mapFromNative(normalGeometryDp()); } + qreal devicePixelRatio() const Q_DECL_OVERRIDE + { return qreal(QWindowsScaling::factor()); } void setVisible(bool visible) Q_DECL_OVERRIDE; bool isVisible() const; bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); } bool isActive() const Q_DECL_OVERRIDE; bool isEmbedded(const QPlatformWindow *parentWindow) const Q_DECL_OVERRIDE; - QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; - QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; - + QPoint mapToGlobalDp(const QPoint &pos) const; + QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE + { return mapToGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } + QPoint mapFromGlobalDp(const QPoint &pos) const; + QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE + { return mapFromGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; @@ -179,7 +190,8 @@ public: void windowEvent(QEvent *event); void propagateSizeHints() Q_DECL_OVERRIDE; - QMargins frameMargins() const Q_DECL_OVERRIDE; + QMargins frameMarginsDp() const; + QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMarginsDp() / QWindowsScaling::factor(); } void setOpacity(qreal level) Q_DECL_OVERRIDE; void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; @@ -190,7 +202,7 @@ public: bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE; + bool startSystemResize(const QPoint &, Qt::Corner corner) Q_DECL_OVERRIDE; void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index 104d882fba..8e5f35d293 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -39,7 +39,8 @@ SOURCES += \ $$PWD/qwindowsdialoghelpers.cpp \ $$PWD/qwindowsservices.cpp \ $$PWD/qwindowsnativeimage.cpp \ - $$PWD/qwindowsnativeinterface.cpp + $$PWD/qwindowsnativeinterface.cpp \ + $$PWD/qwindowsscaling.cpp HEADERS += \ $$PWD/qwindowswindow.h \ @@ -64,7 +65,8 @@ HEADERS += \ $$PWD/qwindowsservices.h \ $$PWD/qplatformfunctions_wince.h \ $$PWD/qwindowsnativeimage.h \ - $$PWD/qwindowsnativeinterface.h + $$PWD/qwindowsnativeinterface.h \ + $$PWD/qwindowsscaling.h !wince: HEADERS += $$PWD/qwindowsopengltester.h diff --git a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp index 98eb83f5eb..2bc8e6602f 100644 --- a/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp +++ b/src/plugins/platforms/winrt/qwinrteventdispatcher.cpp @@ -42,7 +42,6 @@ #include "qwinrteventdispatcher.h" #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatformscreen.h> -#include <qpa/qplatformscreenpageflipper.h> #include <QtCore/QThread> #include <QtGui/QGuiApplication> diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index ef99e6da6b..6c905735dd 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -512,8 +512,6 @@ QWinRTScreen::QWinRTScreen() d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); d->surfaceFormat.setSamples(1); d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - d->surfaceFormat.setDepthBufferSize(24); - d->surfaceFormat.setStencilBufferSize(8); hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]); Q_ASSERT_SUCCEEDED(hr); diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp index 592a6b1921..7004abf888 100644 --- a/src/plugins/platforms/winrt/qwinrttheme.cpp +++ b/src/plugins/platforms/winrt/qwinrttheme.cpp @@ -112,6 +112,7 @@ QWinRTTheme::QWinRTTheme() Q_ASSERT_SUCCEEDED(hr); d->palette.setColor(QPalette::ButtonText, fromColor(color)); d->palette.setColor(QPalette::Text, fromColor(color)); + d->palette.setColor(QPalette::WindowText, fromColor(color)); hr = uiSettings()->UIElementColor(UIElementType_TextMedium, &color); Q_ASSERT_SUCCEEDED(hr); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 6258b29fc7..2daadb8649 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -280,13 +280,14 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion) { if (!m_image) return; - - m_image->preparePaint(region); + const int dpr = int(m_image->image()->devicePixelRatio()); + QRegion xRegion = dpr == 1 ? region : QTransform::fromScale(dpr,dpr).map(region); + m_image->preparePaint(xRegion); if (m_image->image()->hasAlphaChannel()) { QPainter p(m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); - const QVector<QRect> rects = region.rects(); + const QVector<QRect> rects = xRegion.rects(); const QColor blank = Qt::transparent; for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { p.fillRect(*it, blank); @@ -323,9 +324,13 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin return; } + const int dpr = int(window->devicePixelRatio()); + QVector<QRect> rects = clipped.rects(); - for (int i = 0; i < rects.size(); ++i) - m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset)); + for (int i = 0; i < rects.size(); ++i) { + QRect rect = QRect(rects.at(i).topLeft() * dpr, rects.at(i).size() * dpr); + m_image->put(platformWindow->xcb_window(), rect.topLeft(), rect.translated(offset * dpr)); + } Q_XCB_NOOP(connection()); @@ -355,9 +360,11 @@ void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, c void QXcbBackingStore::resize(const QSize &size, const QRegion &) { - if (m_image && size == m_image->size()) - return; + const int dpr = int(window()->devicePixelRatio()); + const QSize xSize = size * dpr; + if (m_image && xSize == m_image->size()) + return; Q_XCB_NOOP(connection()); QXcbScreen *screen = static_cast<QXcbScreen *>(window()->screen()->handle()); @@ -369,7 +376,8 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &) QXcbWindow* win = static_cast<QXcbWindow *>(pw); delete m_image; - m_image = new QXcbShmImage(screen, size, win->depth(), win->imageFormat()); + m_image = new QXcbShmImage(screen, xSize, win->depth(), win->imageFormat()); + m_image->image()->setDevicePixelRatio(dpr); Q_XCB_NOOP(connection()); } @@ -380,12 +388,14 @@ bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy) if (!m_image || m_image->image()->isNull()) return false; + const int dpr = int(m_image->image()->devicePixelRatio()); + QRegion xArea = dpr == 1 ? area : QTransform::fromScale(dpr,dpr).map(area); m_image->preparePaint(area); - const QVector<QRect> rects = area.rects(); - for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(*m_image->image(), rects.at(i), QPoint(dx, dy)); - + QPoint delta(dx * dpr, dy * dpr); + const QVector<QRect> xRects = xArea.rects(); + for (int i = 0; i < xRects.size(); ++i) + qt_scrollRectInImage(*m_image->image(), xRects.at(i), delta); return true; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index ff8a6e2d76..ed5fe6d7c0 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -92,6 +92,9 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpaXInput, "qt.qpa.input") +Q_LOGGING_CATEGORY(lcQpaXInputDevices, "qt.qpa.input.devices") + #ifdef XCB_USE_XLIB static const char * const xcbConnectionErrors[] = { "No error", /* Error 0 */ @@ -324,8 +327,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra , has_input_shape(false) , has_touch_without_mouse_emulation(false) , has_xkb(false) - , debug_xinput_devices(false) - , debug_xinput(false) , m_buttons(0) , m_focusWindow(0) , m_systemTrayTracker(0) @@ -798,8 +799,7 @@ void QXcbConnection::handleButtonPress(xcb_generic_event_t *ev) // the rest we need to manage ourselves m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state); m_buttons |= translateMouseButton(event->detail); - if (Q_UNLIKELY(debug_xinput)) - qDebug("xcb: pressed mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons)); + qCDebug(lcQpaXInput, "xcb: pressed mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons)); } void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev) @@ -810,8 +810,7 @@ void QXcbConnection::handleButtonRelease(xcb_generic_event_t *ev) // the rest we need to manage ourselves m_buttons = (m_buttons & ~0x7) | translateMouseButtons(event->state); m_buttons &= ~translateMouseButton(event->detail); - if (Q_UNLIKELY(debug_xinput)) - qDebug("xcb: released mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons)); + qCDebug(lcQpaXInput, "xcb: released mouse button %d, button state %X", event->detail, static_cast<unsigned int>(m_buttons)); } #ifndef QT_NO_XKB @@ -864,7 +863,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) handleButtonRelease(event); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); case XCB_MOTION_NOTIFY: - if (Q_UNLIKELY(debug_xinput)) { + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) { xcb_motion_notify_event_t *mev = (xcb_motion_notify_event_t *)event; qDebug("xcb: moved mouse to %4d, %4d; button state %X", mev->event_x, mev->event_y, static_cast<unsigned int>(m_buttons)); } diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 44ee38e5de..01dd048ea3 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -52,6 +52,7 @@ #include <QVector> #include <QVarLengthArray> #include <qpa/qwindowsysteminterface.h> +#include <QtCore/QLoggingCategory> // This is needed to make Qt compile together with XKB. xkb.h is using a variable // which is called 'explicit', this is a reserved keyword in c++ @@ -73,7 +74,7 @@ #define XCB_USE_XINPUT22 // XI 2.2 adds multi-point touch support #endif #endif -struct XInput2DeviceData; +struct XInput2TouchDeviceData; #endif struct xcb_randr_get_output_info_reply_t; @@ -81,6 +82,9 @@ struct xcb_randr_get_output_info_reply_t; QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcQpaXInput) +Q_DECLARE_LOGGING_CATEGORY(lcQpaXInputDevices) + class QXcbScreen; class QXcbWindow; class QXcbDrag; @@ -504,7 +508,7 @@ private: void initializeXInput2(); void finalizeXInput2(); void xi2SetupDevices(); - XInput2DeviceData *deviceForId(int id); + XInput2TouchDeviceData *touchDeviceForId(int id); void xi2HandleEvent(xcb_ge_event_t *event); void xi2HandleHierachyEvent(void *event); int m_xiOpCode, m_xiEventBase, m_xiErrorBase; @@ -579,7 +583,7 @@ private: QXcbEventReader *m_reader; #if defined(XCB_USE_XINPUT2) QHash<int, QWindowSystemInterface::TouchPoint> m_touchPoints; - QHash<int, XInput2DeviceData*> m_touchDevices; + QHash<int, XInput2TouchDeviceData*> m_touchDevices; #endif #if defined(XCB_USE_EGL) void *m_egl_display; @@ -613,8 +617,6 @@ private: bool has_input_shape; bool has_touch_without_mouse_emulation; bool has_xkb; - bool debug_xinput_devices; - bool debug_xinput; Qt::MouseButtons m_buttons; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 512e574859..84d00d0e09 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -53,8 +53,8 @@ #include <X11/extensions/XI2proto.h> #define FINGER_MAX_WIDTH_MM 10 -struct XInput2DeviceData { - XInput2DeviceData() +struct XInput2TouchDeviceData { + XInput2TouchDeviceData() : xiDeviceInfo(0) , qtTouchDevice(0) { @@ -71,8 +71,11 @@ struct XInput2DeviceData { void QXcbConnection::initializeXInput2() { - debug_xinput = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT"); - debug_xinput_devices = qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES"); + // TODO Qt 6 (or perhaps earlier): remove these redundant env variables + if (qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT")) + const_cast<QLoggingCategory&>(lcQpaXInput()).setEnabled(QtDebugMsg, true); + if (qEnvironmentVariableIsSet("QT_XCB_DEBUG_XINPUT_DEVICES")) + const_cast<QLoggingCategory&>(lcQpaXInputDevices()).setEnabled(QtDebugMsg, true); Display *xDisplay = static_cast<Display *>(m_xlib_display); if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) { int xiMajor = 2; @@ -87,11 +90,10 @@ void QXcbConnection::initializeXInput2() } else m_xi2Enabled = true; if (m_xi2Enabled) { - if (Q_UNLIKELY(debug_xinput_devices)) #ifdef XCB_USE_XINPUT22 - qDebug("XInput version %d.%d is available and Qt supports 2.2 or greater", xiMajor, m_xi2Minor); + qCDebug(lcQpaXInputDevices, "XInput version %d.%d is available and Qt supports 2.2 or greater", xiMajor, m_xi2Minor); #else - qDebug("XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor); + qCDebug(lcQpaXInputDevices, "XInput version %d.%d is available and Qt supports 2.0", xiMajor, m_xi2Minor); #endif } @@ -116,8 +118,7 @@ void QXcbConnection::xi2SetupDevices() // Only non-master pointing devices are relevant here. if (devices[i].use != XISlavePointer) continue; - if (Q_UNLIKELY(debug_xinput_devices)) - qDebug() << "input device "<< devices[i].name; + qCDebug(lcQpaXInputDevices) << "input device "<< devices[i].name; #ifndef QT_NO_TABLETEVENT TabletData tabletData; #endif @@ -127,8 +128,7 @@ void QXcbConnection::xi2SetupDevices() case XIValuatorClass: { XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]); const int valuatorAtom = qatom(vci->label); - if (Q_UNLIKELY(debug_xinput_devices)) - qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); + qCDebug(lcQpaXInputDevices) << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); #ifndef QT_NO_TABLETEVENT if (valuatorAtom < QXcbAtom::NAtoms) { TabletData::ValuatorClassInfo info; @@ -173,10 +173,18 @@ void QXcbConnection::xi2SetupDevices() if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight)) scrollingDevice.legacyOrientations |= Qt::Horizontal; } + qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons); break; } #endif + case XIKeyClass: + qCDebug(lcQpaXInputDevices) << " it's a keyboard"; + break; + case XITouchClass: + // will be handled in deviceForId() + break; default: + qCDebug(lcQpaXInputDevices) << " has class" << devices[i].classes[c]->type; break; } } @@ -192,8 +200,7 @@ void QXcbConnection::xi2SetupDevices() tabletData.pointerType = QTabletEvent::Eraser; m_tabletData.append(tabletData); isTablet = true; - if (Q_UNLIKELY(debug_xinput_devices)) - qDebug() << " it's a tablet with pointer type" << tabletData.pointerType; + qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << tabletData.pointerType; } #endif // QT_NO_TABLETEVENT @@ -203,23 +210,24 @@ void QXcbConnection::xi2SetupDevices() // Only use legacy wheel button events when we don't have real scroll valuators. scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations; m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); - if (Q_UNLIKELY(debug_xinput_devices)) - qDebug() << " it's a scrolling device"; + qCDebug(lcQpaXInputDevices) << " it's a scrolling device"; } #endif if (!isTablet) { - XInput2DeviceData *dev = deviceForId(devices[i].deviceid); - if (Q_UNLIKELY(debug_xinput_devices)) { - if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) - qDebug(" it's a touchscreen with type %d capabilities 0x%X max touch points %d", - dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), - dev->qtTouchDevice->maximumTouchPoints()); - else if (dev && dev->qtTouchDevice->type() == QTouchDevice::TouchPad) - qDebug(" it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", - dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), - dev->qtTouchDevice->maximumTouchPoints(), - dev->size.width(), dev->size.height()); + // touchDeviceForId populates XInput2DeviceData the first time it is called + // with a new deviceId. On subsequent calls it will return the cached object. + XInput2TouchDeviceData *dev = touchDeviceForId(devices[i].deviceid); + if (dev && lcQpaXInputDevices().isDebugEnabled()) { + if (dev->qtTouchDevice->type() == QTouchDevice::TouchScreen) + qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints()); + else if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad) + qCDebug(lcQpaXInputDevices, " it's a touchpad with type %d capabilities 0x%X max touch points %d size %f x %f", + dev->qtTouchDevice->type(), (unsigned int)dev->qtTouchDevice->capabilities(), + dev->qtTouchDevice->maximumTouchPoints(), + dev->size.width(), dev->size.height()); } } } @@ -228,7 +236,7 @@ void QXcbConnection::xi2SetupDevices() void QXcbConnection::finalizeXInput2() { - foreach (XInput2DeviceData *dev, m_touchDevices) { + foreach (XInput2TouchDeviceData *dev, m_touchDevices) { if (dev->xiDeviceInfo) XIFreeDeviceInfo(dev->xiDeviceInfo); delete dev; @@ -324,14 +332,16 @@ void QXcbConnection::xi2Select(xcb_window_t window) } } -XInput2DeviceData *QXcbConnection::deviceForId(int id) +XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) { - XInput2DeviceData *dev = m_touchDevices[id]; + XInput2TouchDeviceData *dev = m_touchDevices[id]; if (!dev) { - int unused = 0; + int nrDevices = 0; QTouchDevice::Capabilities caps = 0; - dev = new XInput2DeviceData; - dev->xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), id, &unused); + dev = new XInput2TouchDeviceData; + dev->xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), id, &nrDevices); + if (nrDevices <= 0) + return 0; int type = -1; int maxTouchPoints = 1; bool hasRelativeCoords = false; @@ -342,8 +352,7 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) case XITouchClass: { XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo); maxTouchPoints = tci->num_touches; - if (Q_UNLIKELY(debug_xinput_devices)) - qDebug(" has touch class with mode %d", tci->mode); + qCDebug(lcQpaXInputDevices, " has touch class with mode %d", tci->mode); switch (tci->mode) { case XIDependentTouch: type = QTouchDevice::TouchPad; @@ -372,6 +381,8 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id) } break; } + default: + break; } } if (type < 0 && caps && hasRelativeCoords) { @@ -444,14 +455,14 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) #ifdef XCB_USE_XINPUT22 if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) { xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); - if (Q_UNLIKELY(debug_xinput)) - qDebug("XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f", - event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, - fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), - fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) ); + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) + qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f", + event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail, + fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), + fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y) ); if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { - XInput2DeviceData *dev = deviceForId(xiDeviceEvent->sourceid); + XInput2TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid); Q_ASSERT(dev); const bool firstTouch = m_touchPoints.isEmpty(); if (xiEvent->evtype == XI_TouchBegin) { @@ -474,9 +485,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) double value; if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value)) continue; - if (Q_UNLIKELY(debug_xinput)) - qDebug(" valuator %20s value %lf from range %lf -> %lf", - atomName(vci->label).constData(), value, vci->min, vci->max ); + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) + qCDebug(lcQpaXInput, " valuator %20s value %lf from range %lf -> %lf", + atomName(vci->label).constData(), value, vci->min, vci->max ); if (vci->label == atom(QXcbAtom::RelX)) { nx = valuatorNormalized(value, vci); } else if (vci->label == atom(QXcbAtom::RelY)) { @@ -552,9 +563,9 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) touchPoint.area = QRectF(x - w/2, y - h/2, w, h); touchPoint.normalPosition = QPointF(nx, ny); - if (Q_UNLIKELY(debug_xinput)) - qDebug() << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << - " area " << touchPoint.area << " pressure " << touchPoint.pressure; + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) + qCDebug(lcQpaXInput) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << + " area " << touchPoint.area << " pressure " << touchPoint.pressure; QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiEvent->time, dev->qtTouchDevice, m_touchPoints.values()); if (touchPoint.state == Qt::TouchPointReleased) // If a touchpoint was released, we can forget it, because the ID won't be reused. @@ -643,8 +654,9 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin } } if (!angleDelta.isNull()) { - QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); - QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); + const int dpr = int(platformWindow->devicePixelRatio()); + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr); Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); if (modifiers & Qt::AltModifier) { std::swap(angleDelta.rx(), angleDelta.ry()); @@ -670,8 +682,9 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin angleDelta.setX(-120); } if (!angleDelta.isNull()) { - QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); - QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); + const int dpr = int(platformWindow->devicePixelRatio()); + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr); Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); if (modifiers & Qt::AltModifier) std::swap(angleDelta.rx(), angleDelta.ry()); @@ -805,13 +818,11 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData) tabletData->pointerType, tabletData->serialId); } - if (Q_UNLIKELY(debug_xinput)) { - // TODO maybe have a hash of tabletData->deviceId to device data so we can - // look up the tablet name here, and distinguish multiple tablets - qDebug("XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d", - ev->deviceid, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID], - ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool); - } + // TODO maybe have a hash of tabletData->deviceId to device data so we can + // look up the tablet name here, and distinguish multiple tablets + qCDebug(lcQpaXInput, "XI2 proximity change on tablet %d (USB %x): last tool: %x id %x current tool: %x id %x TabletDevice %d", + ev->deviceid, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID], + ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], tabletData->tool); } XFree(data); } @@ -872,8 +883,8 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) } } - if (Q_UNLIKELY(debug_xinput)) - qDebug("XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) + qCDebug(lcQpaXInput, "XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", ev->deviceid, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y), fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y), diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index 6dbac90e0c..c9adf00673 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -629,16 +629,18 @@ void QXcbCursor::queryPointer(QXcbConnection *c, xcb_window_t *rootWin, QPoint * QPoint QXcbCursor::pos() const { + const int dpr = int(m_screen->devicePixelRatio()); QPoint p; queryPointer(connection(), 0, &p); - return p; + return p / dpr; } void QXcbCursor::setPos(const QPoint &pos) { + const int dpr = int(m_screen->devicePixelRatio()); xcb_window_t root = 0; queryPointer(connection(), &root, 0); - xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y()); + xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x()*dpr, pos.y()*dpr); xcb_flush(xcb_connection()); } diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index bd28548cba..fa5ccf58ef 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -300,6 +300,11 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md void QXcbDrag::move(const QMouseEvent *me) { + // The mouse event is in the coordinate system of the window that started the drag. + // We do not know which window that was at this point, so we just use the device pixel ratio + // of the QGuiApplication. This will break once we support screens with different DPR. Fixing + // this properly requires some redesign of the drag and drop architecture. + static const int dpr = int(qApp->devicePixelRatio()); QBasicDrag::move(me); QPoint globalPos = me->globalPos(); @@ -336,7 +341,7 @@ void QXcbDrag::move(const QMouseEvent *me) // qt_xdnd_current_screen = screen; xcb_window_t rootwin = current_screen->root(); xcb_translate_coordinates_reply_t *translate = - ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y()); + ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x() * dpr, globalPos.y() * dpr); if (!translate) return; @@ -459,7 +464,7 @@ void QXcbDrag::move(const QMouseEvent *me) move.type = atom(QXcbAtom::XdndPosition); move.data.data32[0] = connection()->clipboard()->owner(); move.data.data32[1] = 0; // flags - move.data.data32[2] = (globalPos.x() << 16) + globalPos.y(); + move.data.data32[2] = (globalPos.x() * dpr << 16) + globalPos.y() * dpr; move.data.data32[3] = connection()->time(); move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers())); DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; @@ -705,7 +710,9 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); Q_ASSERT(w); QRect geometry = w->geometry(); + const int dpr = int(w->handle()->devicePixelRatio()); + p /= dpr; p -= geometry.topLeft(); if (!w || (w->type() == Qt::Desktop)) @@ -824,10 +831,12 @@ void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event) updateCursor(Qt::IgnoreAction); } + static const int dpr = int(qApp->devicePixelRatio()); + if ((event->data.data32[1] & 2) == 0) { QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff); QSize s((event->data.data32[3] & 0xffff0000) >> 16, event->data.data32[3] & 0x0000ffff); - source_sameanswer = QRect(p, s); + source_sameanswer = QRect(p / dpr, s / dpr); } else { source_sameanswer = QRect(); } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 5673d41811..a00da04c26 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -85,7 +85,8 @@ static int resourceType(const QByteArray &key) QByteArrayLiteral("appusertime"), QByteArrayLiteral("hintstyle"), QByteArrayLiteral("startupid"), QByteArrayLiteral("traywindow"), QByteArrayLiteral("gettimestamp"), QByteArrayLiteral("x11screen"), - QByteArrayLiteral("rootwindow") + QByteArrayLiteral("rootwindow"), + QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingEnabled") }; const QByteArray *end = names + sizeof(names) / sizeof(names[0]); const QByteArray *result = std::find(names, end, key); @@ -277,6 +278,12 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resource, Q case ScreenHintStyle: result = reinterpret_cast<void *>(xcbScreen->hintStyle() + 1); break; + case ScreenSubpixelType: + result = reinterpret_cast<void *>(xcbScreen->subpixelType() + 1); + break; + case ScreenAntialiasingEnabled: + result = reinterpret_cast<void *>(xcbScreen->antialiasingEnabled() + 1); + break; case TrayWindow: if (QXcbSystemTrayTracker *s = systemTrayTracker(screen)) result = (void *)quintptr(s->trayWindow()); diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index c63cdf0254..1cd764914a 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -73,7 +73,9 @@ public: TrayWindow, GetTimestamp, X11Screen, - RootWindow + RootWindow, + ScreenSubpixelType, + ScreenAntialiasingEnabled }; QXcbNativeInterface(); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 85f4dfbd43..83ffb02362 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -68,7 +68,10 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, , m_number(number) , m_refreshRate(60) , m_forcedDpi(-1) + , m_devicePixelRatio(1) , m_hintStyle(QFontEngine::HintStyle(-1)) + , m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1)) + , m_antialiasingEnabled(-1) , m_xSettings(0) { if (connection->hasXRandr()) @@ -76,19 +79,18 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, updateGeometry(output ? output->timestamp : 0); updateRefreshRate(); - + const int dpr = int(devicePixelRatio()); // On VNC, it can be that physical size is unknown while // virtual size is known (probably back-calculated from DPI and resolution) if (m_sizeMillimeters.isEmpty()) m_sizeMillimeters = m_virtualSizeMillimeters; if (m_geometry.isEmpty()) - m_geometry = QRect(QPoint(), m_virtualSize); + m_geometry = QRect(QPoint(), m_virtualSize/dpr); if (m_availableGeometry.isEmpty()) - m_availableGeometry = QRect(QPoint(), m_virtualSize); + m_availableGeometry = m_geometry; readXResources(); - #ifdef Q_XCB_DEBUG qDebug(); qDebug("Screen output %s of xcb screen %d:", m_outputName.toUtf8().constData(), m_number); @@ -99,6 +101,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *scr, qDebug(" virtual height.: %lf", m_virtualSizeMillimeters.height()); qDebug(" virtual geom...: %d x %d", m_virtualSize.width(), m_virtualSize.height()); qDebug(" avail virt geom: %d x %d +%d +%d", m_availableGeometry.width(), m_availableGeometry.height(), m_availableGeometry.x(), m_availableGeometry.y()); + qDebug(" pixel ratio....: %d", m_devicePixelRatio); qDebug(" depth..........: %d", screen()->root_depth); qDebug(" white pixel....: %x", screen()->white_pixel); qDebug(" black pixel....: %x", screen()->black_pixel); @@ -220,8 +223,9 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const { xcb_window_t root = m_screen->root; - int x = p.x(); - int y = p.y(); + int dpr = int(devicePixelRatio()); + int x = p.x() / dpr; + int y = p.y() / dpr; xcb_window_t parent = root; xcb_window_t child = root; @@ -312,11 +316,25 @@ QImage::Format QXcbScreen::format() const QDpi QXcbScreen::logicalDpi() const { + int dpr = int(devicePixelRatio()); + if (m_forcedDpi > 0) - return QDpi(m_forcedDpi, m_forcedDpi); + return QDpi(m_forcedDpi/dpr, m_forcedDpi/dpr); + + return QDpi(Q_MM_PER_INCH * m_virtualSize.width() / m_virtualSizeMillimeters.width() / dpr, + Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height() / dpr); +} + - return QDpi(Q_MM_PER_INCH * m_virtualSize.width() / m_virtualSizeMillimeters.width(), - Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height()); +qreal QXcbScreen::devicePixelRatio() const +{ + static int override_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toInt(); + static bool auto_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toLower() == "auto"; + if (override_dpr > 0) + return override_dpr; + if (auto_dpr) + return m_devicePixelRatio; + return 1.0; } QPlatformCursor *QXcbScreen::cursor() const @@ -394,12 +412,15 @@ void QXcbScreen::handleScreenChange(xcb_randr_screen_change_notify_event_t *chan void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp) { + QRect xGeometry; + QRect xAvailableGeometry; + if (connection()->hasXRandr()) { xcb_randr_get_crtc_info_reply_t *crtc = xcb_randr_get_crtc_info_reply(xcb_connection(), xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp), NULL); if (crtc) { - m_geometry = QRect(crtc->x, crtc->y, crtc->width, crtc->height); - m_availableGeometry = m_geometry; + xGeometry = QRect(crtc->x, crtc->y, crtc->width, crtc->height); + xAvailableGeometry = xGeometry; free(crtc); } } @@ -420,10 +441,16 @@ void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp) QRect virtualAvailableGeometry(geom[0], geom[1], geom[2], geom[3]); // Take the intersection of the desktop's available geometry with this screen's geometry // to get the part of the available geometry which belongs to this screen. - m_availableGeometry = m_geometry & virtualAvailableGeometry; + xAvailableGeometry = xGeometry & virtualAvailableGeometry; } free(workArea); + qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4); + m_devicePixelRatio = qRound(dpi/96); + const int dpr = int(devicePixelRatio()); // we may override m_devicePixelRatio + m_geometry = QRect(xGeometry.topLeft()/dpr, xGeometry.size()/dpr); + m_availableGeometry = QRect(xAvailableGeometry.topLeft()/dpr, xAvailableGeometry.size()/dpr); + QWindowSystemInterface::handleScreenAvailableGeometryChange(QPlatformScreen::screen(), m_availableGeometry); } @@ -547,32 +574,52 @@ QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) return result; } +static bool parseXftInt(const QByteArray& stringValue, int *value) +{ + Q_ASSERT(value != 0); + bool ok; + *value = stringValue.toInt(&ok); + return ok; +} + +static QFontEngine::HintStyle parseXftHintStyle(const QByteArray& stringValue) +{ + if (stringValue == "hintfull") + return QFontEngine::HintFull; + else if (stringValue == "hintnone") + return QFontEngine::HintNone; + else if (stringValue == "hintmedium") + return QFontEngine::HintMedium; + else if (stringValue == "hintslight") + return QFontEngine::HintLight; + + return QFontEngine::HintStyle(-1); +} + +static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray& stringValue) +{ + if (stringValue == "none") + return QFontEngine::Subpixel_None; + else if (stringValue == "rgb") + return QFontEngine::Subpixel_RGB; + else if (stringValue == "bgr") + return QFontEngine::Subpixel_BGR; + else if (stringValue == "vrgb") + return QFontEngine::Subpixel_VRGB; + else if (stringValue == "vbgr") + return QFontEngine::Subpixel_VBGR; + + return QFontEngine::SubpixelAntialiasingType(-1); +} + bool QXcbScreen::xResource(const QByteArray &identifier, const QByteArray &expectedIdentifier, - int *value) + QByteArray& stringValue) { - Q_ASSERT(value != 0); if (identifier.startsWith(expectedIdentifier)) { - QByteArray stringValue = identifier.mid(expectedIdentifier.size()); - - bool ok; - *value = stringValue.toInt(&ok); - if (!ok) { - if (stringValue == "hintfull") - *value = QFontEngine::HintFull; - else if (stringValue == "hintnone") - *value = QFontEngine::HintNone; - else if (stringValue == "hintmedium") - *value = QFontEngine::HintMedium; - else if (stringValue == "hintslight") - *value = QFontEngine::HintLight; - - return *value != 0; - } - + stringValue = identifier.mid(expectedIdentifier.size()); return true; } - return false; } @@ -604,10 +651,18 @@ void QXcbScreen::readXResources() for (int i = 0; i < split.size(); ++i) { const QByteArray &r = split.at(i); int value; - if (xResource(r, "Xft.dpi:\t", &value)) - m_forcedDpi = value; - else if (xResource(r, "Xft.hintstyle:\t", &value)) - m_hintStyle = QFontEngine::HintStyle(value); + QByteArray stringValue; + if (xResource(r, "Xft.dpi:\t", stringValue)) { + if (parseXftInt(stringValue, &value)) + m_forcedDpi = value; + } else if (xResource(r, "Xft.hintstyle:\t", stringValue)) { + m_hintStyle = parseXftHintStyle(stringValue); + } else if (xResource(r, "Xft.antialias:\t", stringValue)) { + if (parseXftInt(stringValue, &value)) + m_antialiasingEnabled = value; + } else if (xResource(r, "Xft.rgba:\t", stringValue)) { + m_subpixelType = parseXftRgba(stringValue); + } } } diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index 53ac65bb09..06dc2a32a2 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -75,6 +75,7 @@ public: QImage::Format format() const; QSizeF physicalSize() const { return m_sizeMillimeters; } QDpi logicalDpi() const; + qreal devicePixelRatio() const; QPlatformCursor *cursor() const; qreal refreshRate() const { return m_refreshRate; } Qt::ScreenOrientation orientation() const { return m_orientation; } @@ -104,13 +105,15 @@ public: void readXResources(); QFontEngine::HintStyle hintStyle() const { return m_hintStyle; } + QFontEngine::SubpixelAntialiasingType subpixelType() const { return m_subpixelType; } + int antialiasingEnabled() const { return m_antialiasingEnabled; } QXcbXSettings *xSettings() const; private: static bool xResource(const QByteArray &identifier, - const QByteArray &expectedIdentifier, - int *value); + const QByteArray &expectedIdentifier, + QByteArray &stringValue); void sendStartupMessage(const QByteArray &message) const; xcb_screen_t *m_screen; @@ -132,7 +135,10 @@ private: QXcbCursor *m_cursor; int m_refreshRate; int m_forcedDpi; + int m_devicePixelRatio; QFontEngine::HintStyle m_hintStyle; + QFontEngine::SubpixelAntialiasingType m_subpixelType; + int m_antialiasingEnabled; QXcbXSettings *m_xSettings; }; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index cb647e946d..e4feda2c81 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -154,6 +154,30 @@ enum QX11EmbedMessageType { const quint32 XEMBED_VERSION = 0; +static inline QRect mapToNative(const QRect &qtRect, int dpr) +{ + return QRect(qtRect.x() * dpr, qtRect.y() * dpr, qtRect.width() * dpr, qtRect.height() * dpr); +} + +// When converting native rects to Qt rects: round top/left towards the origin and +// bottom/right away from the origin, making sure that we cover the whole widget + +static inline QPoint dpr_floor(const QPoint &p, int dpr) +{ + return QPoint(p.x()/dpr, p.y()/dpr); +} + +static inline QPoint dpr_ceil(const QPoint &p, int dpr) +{ + return QPoint((p.x() + dpr - 1) / dpr, (p.y() + dpr - 1) / dpr); +} + +static inline QRect mapFromNative(const QRect &xRect, int dpr) +{ + return QRect(dpr_floor(xRect.topLeft(), dpr), dpr_ceil(xRect.bottomRight(), dpr)); +} + + // Returns \c true if we should set WM_TRANSIENT_FOR on \a w static inline bool isTransient(const QWindow *w) { @@ -288,11 +312,12 @@ void QXcbWindow::create() // currently no way to implement it for frame-exclusive geometries. QRect rect = window()->geometry(); QPlatformWindow::setGeometry(rect); + const int dpr = int(devicePixelRatio()); QSize minimumSize = window()->minimumSize(); if (rect.width() > 0 || rect.height() > 0) { - rect.setWidth(qBound(1, rect.width(), XCOORD_MAX)); - rect.setHeight(qBound(1, rect.height(), XCOORD_MAX)); + rect.setWidth(qBound(1, rect.width(), XCOORD_MAX/dpr)); + rect.setHeight(qBound(1, rect.height(), XCOORD_MAX/dpr)); } else if (minimumSize.width() > 0 || minimumSize.height() > 0) { rect.setSize(minimumSize); } else { @@ -350,7 +375,9 @@ void QXcbWindow::create() m_visualId = visualInfo->visualid; - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), + const QRect xRect = mapToNative(rect, dpr); + + m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, xRect.x(), xRect.y(), xRect.width(), xRect.height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBackPixel|CWBorderPixel|CWColormap, &a); @@ -561,7 +588,9 @@ void QXcbWindow::setGeometry(const QRect &rect) QPlatformWindow::setGeometry(rect); propagateSizeHints(); - const QRect wmGeometry = windowToWmGeometry(rect); + + const QRect xRect = mapToNative(rect, int(devicePixelRatio())); + const QRect wmGeometry = windowToWmGeometry(xRect); if (qt_window_private(window())->positionAutomatic) { const quint32 mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; @@ -1444,23 +1473,26 @@ void QXcbWindow::propagateSizeHints() xcb_size_hints_t hints; memset(&hints, 0, sizeof(hints)); - const QRect rect = windowToWmGeometry(geometry()); + const int dpr = int(devicePixelRatio()); + const QRect xRect = mapToNative(windowToWmGeometry(geometry()), dpr); QWindow *win = window(); if (!qt_window_private(win)->positionAutomatic) - xcb_size_hints_set_position(&hints, true, rect.x(), rect.y()); - if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX) - xcb_size_hints_set_size(&hints, true, rect.width(), rect.height()); + xcb_size_hints_set_position(&hints, true, xRect.x(), xRect.y()); + if (xRect.width() < QWINDOWSIZE_MAX || xRect.height() < QWINDOWSIZE_MAX) + xcb_size_hints_set_size(&hints, true, xRect.width(), xRect.height()); xcb_size_hints_set_win_gravity(&hints, m_gravity); - QSize minimumSize = win->minimumSize(); - QSize maximumSize = win->maximumSize(); - QSize baseSize = win->baseSize(); - QSize sizeIncrement = win->sizeIncrement(); + QSize minimumSize = win->minimumSize() * dpr; + QSize maximumSize = win->maximumSize() * dpr; + QSize baseSize = win->baseSize() * dpr; + QSize sizeIncrement = win->sizeIncrement() * dpr; if (minimumSize.width() > 0 || minimumSize.height() > 0) - xcb_size_hints_set_min_size(&hints, minimumSize.width(), minimumSize.height()); + xcb_size_hints_set_min_size(&hints, + qMin(XCOORD_MAX,minimumSize.width()), + qMin(XCOORD_MAX,minimumSize.height())); if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX) xcb_size_hints_set_max_size(&hints, @@ -1664,9 +1696,10 @@ void QXcbWindow::setWmWindowType(QXcbWindowFunctions::WmWindowTypes types) class ExposeCompressor { public: - ExposeCompressor(xcb_window_t window, QRegion *region) + ExposeCompressor(xcb_window_t window, QRegion *region, int devicePixelRatio) : m_window(window) , m_region(region) + , m_dpr(devicePixelRatio) , m_pending(true) { } @@ -1682,7 +1715,7 @@ public: return false; if (expose->count == 0) m_pending = false; - *m_region |= QRect(expose->x, expose->y, expose->width, expose->height); + *m_region |= mapFromNative(QRect(expose->x, expose->y, expose->width, expose->height), m_dpr); return true; } @@ -1694,6 +1727,7 @@ public: private: xcb_window_t m_window; QRegion *m_region; + int m_dpr; bool m_pending; }; @@ -1707,14 +1741,16 @@ bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result) void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { - QRect rect(event->x, event->y, event->width, event->height); + const int dpr = int(devicePixelRatio()); + QRect x_rect(event->x, event->y, event->width, event->height); + QRect rect = mapFromNative(x_rect, dpr); if (m_exposeRegion.isEmpty()) m_exposeRegion = rect; else m_exposeRegion |= rect; - ExposeCompressor compressor(m_window, &m_exposeRegion); + ExposeCompressor compressor(m_window, &m_exposeRegion, dpr); xcb_generic_event_t *filter = 0; do { filter = connection()->checkEvent(compressor); @@ -1808,7 +1844,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } } - QRect rect(pos, QSize(event->width, event->height)); + QRect rect = mapFromNative(QRect(pos, QSize(event->width, event->height)), int(devicePixelRatio())); QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); @@ -1850,15 +1886,16 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const if (!m_embedded) return pos; + const int dpr = int(devicePixelRatio()); QPoint ret; xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(), m_screen->root(), - pos.x(), pos.y()); + pos.x() * dpr, pos.y() * dpr); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { - ret.setX(reply->dst_x); - ret.setY(reply->dst_y); + ret.setX(reply->dst_x / dpr); + ret.setY(reply->dst_y / dpr); free(reply); } @@ -1869,15 +1906,17 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const { if (!m_embedded) return pos; + + const int dpr = int(devicePixelRatio()); QPoint ret; xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), m_screen->root(), xcb_window(), - pos.x(), pos.y()); + pos.x() *dpr, pos.y() * dpr); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { - ret.setX(reply->dst_x); - ret.setY(reply->dst_y); + ret.setX(reply->dst_x / dpr); + ret.setY(reply->dst_y / dpr); free(reply); } @@ -1893,7 +1932,7 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) if (m_configureNotifyPending) m_deferredExpose = true; else - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size() * int(devicePixelRatio()))); } } @@ -1924,9 +1963,9 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS); } } - - QPoint local(event->event_x, event->event_y); - QPoint global(event->root_x, event->root_y); + const int dpr = int(devicePixelRatio()); + QPoint local(event->event_x/dpr, event->event_y/dpr); + QPoint global(event->root_x/dpr, event->root_y/dpr); Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); @@ -1949,8 +1988,9 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event) { - QPoint local(event->event_x, event->event_y); - QPoint global(event->root_x, event->root_y); + const int dpr = int(devicePixelRatio()); + QPoint local(event->event_x/dpr, event->event_y/dpr); + QPoint global(event->root_x/dpr, event->root_y/dpr); Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); if (event->detail >= 4 && event->detail <= 7) { @@ -1963,8 +2003,9 @@ void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *even void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) { - QPoint local(event->event_x, event->event_y); - QPoint global(event->root_x, event->root_y); + const int dpr = int(devicePixelRatio()); + QPoint local(event->event_x/dpr, event->event_y/dpr); + QPoint global(event->root_x/dpr, event->root_y/dpr); Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); handleMouseEvent(event->time, local, global, modifiers); @@ -2014,9 +2055,9 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) { return; } - - const QPoint local(event->event_x, event->event_y); - const QPoint global(event->root_x, event->root_y); + const int dpr = int(devicePixelRatio()); + const QPoint local(event->event_x/dpr, event->event_y/dpr); + const QPoint global(event->root_x/dpr, event->root_y/dpr); QWindowSystemInterface::handleEnterEvent(window(), local, global); } @@ -2036,8 +2077,9 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0; if (enterWindow) { - QPoint local(enter->event_x, enter->event_y); - QPoint global(enter->root_x, enter->root_y); + const int dpr = int(devicePixelRatio()); + QPoint local(enter->event_x/dpr, enter->event_y/dpr); + QPoint global(enter->root_x/dpr, enter->root_y/dpr); QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global); } else { @@ -2190,6 +2232,7 @@ void QXcbWindow::windowEvent(QEvent *event) bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) { + const int dpr = int(devicePixelRatio()); const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE); if (!connection()->wmSupport()->isSupportedByWM(moveResize)) return false; @@ -2198,7 +2241,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) xev.type = moveResize; xev.window = xcb_window(); xev.format = 32; - const QPoint globalPos = window()->mapToGlobal(pos); + const QPoint globalPos = window()->mapToGlobal(pos) * dpr; xev.data.data32[0] = globalPos.x(); xev.data.data32[1] = globalPos.y(); const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner; @@ -2316,9 +2359,10 @@ void QXcbWindow::setMask(const QRegion ®ion) xcb_shape_mask(connection()->xcb_connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, xcb_window(), 0, 0, XCB_NONE); } else { + const int dpr = devicePixelRatio(); QVector<xcb_rectangle_t> rects; foreach (const QRect &r, region.rects()) - rects.push_back(qRectToXCBRectangle(r)); + rects.push_back(qRectToXCBRectangle(mapToNative(r, dpr))); xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, xcb_window(), 0, 0, rects.size(), &rects[0]); @@ -2352,4 +2396,9 @@ void QXcbWindow::postSyncWindowRequest() } } +qreal QXcbWindow::devicePixelRatio() const +{ + return m_screen ? m_screen->devicePixelRatio() : 1.0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index af9b06a791..4a81fff5b8 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -160,6 +160,8 @@ public: void postSyncWindowRequest(); void clearSyncWindowRequest() { m_pendingSyncRequest = 0; } + qreal devicePixelRatio() const; + public Q_SLOTS: void updateSyncRequestCounter(); |