summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/bearer/generic/qgenericengine.cpp2
-rw-r--r--src/plugins/bearer/nla/nla.pro2
-rw-r--r--src/plugins/bearer/nla/qnlaengine.cpp39
-rw-r--r--src/plugins/imageformats/ico/qicohandler.cpp24
-rw-r--r--src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp10
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp107
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm272
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm52
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm1
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h12
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm98
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm1
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h31
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm220
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm53
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.mm15
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm19
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm10
-rw-r--r--src/plugins/platforms/cocoa/qnsview_gestures.mm10
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm42
-rw-r--r--src/plugins/platforms/cocoa/qnsview_touch.mm8
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm4
-rw-r--r--src/plugins/platforms/direct2d/direct2d.pro4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp4
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp2
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm11
-rw-r--r--src/plugins/platforms/openwfd/qopenwfdscreen.h1
-rw-r--r--src/plugins/platforms/qnx/qnx.pro2
-rw-r--r--src/plugins/platforms/qnx/qqnxforeignwindow.cpp65
-rw-r--r--src/plugins/platforms/qnx/qqnxforeignwindow.h61
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp34
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h7
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp49
-rw-r--r--src/plugins/platforms/qnx/qqnxscreentraits.h127
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp96
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h8
-rw-r--r--src/plugins/platforms/wasm/qtloader.js16
-rw-r--r--src/plugins/platforms/wasm/qtlogo.svg29
-rw-r--r--src/plugins/platforms/wasm/qwasmeventtranslator.cpp9
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.cpp8
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp30
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h7
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.cpp16
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp12
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.cpp15
-rw-r--r--src/plugins/platforms/wasm/qwasmtheme.h3
-rw-r--r--src/plugins/platforms/wasm/wasm.pro3
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html6
-rw-r--r--src/plugins/platforms/windows/.prev_CMakeLists.txt226
-rw-r--r--src/plugins/platforms/windows/CMakeLists.txt37
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp51
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h4
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp22
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.cpp22
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp11
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h3
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp26
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp5
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp59
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.h8
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.cpp16
-rw-r--r--src/plugins/platforms/windows/qwindowsnativeinterface.h1
-rw-r--r--src/plugins/platforms/windows/qwindowsole.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsopengltester.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp93
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.h5
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp17
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h4
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp84
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.h2
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp343
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h62
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp64
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h1
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp168
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h73
-rw-r--r--src/plugins/platforms/windows/uiautomation/uiautomation.pri5
-rw-r--r--src/plugins/platforms/windows/windows.pri16
-rw-r--r--src/plugins/platforms/windows/windows.pro3
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.cpp18
-rw-r--r--src/plugins/platforms/winrt/qwinrttheme.h1
-rw-r--r--src/plugins/platforms/winrt/winrt.pro3
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp4
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp1
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp6
-rw-r--r--src/plugins/printsupport/windows/windows.pro3
-rw-r--r--src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp1
-rw-r--r--src/plugins/sqldrivers/sqlite2/smain.cpp1
-rw-r--r--src/plugins/sqldrivers/tds/main.cpp1
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm161
-rw-r--r--src/plugins/styles/windowsvista/windowsvista.pro2
117 files changed, 2563 insertions, 841 deletions
diff --git a/src/plugins/bearer/generic/qgenericengine.cpp b/src/plugins/bearer/generic/qgenericengine.cpp
index 7472758418..b1f28849a7 100644
--- a/src/plugins/bearer/generic/qgenericengine.cpp
+++ b/src/plugins/bearer/generic/qgenericengine.cpp
@@ -300,7 +300,7 @@ void QGenericEngine::doRequestUpdate()
if (interface.flags() & QNetworkInterface::IsLoopBack)
continue;
-#ifndef Q_OS_WINRT
+#ifndef Q_OS_WIN
// ignore WLAN interface handled in separate engine
if (qGetInterfaceType(interface.name()) == QNetworkConfiguration::BearerWLAN)
continue;
diff --git a/src/plugins/bearer/nla/nla.pro b/src/plugins/bearer/nla/nla.pro
index 113d0667d2..76f3279d25 100644
--- a/src/plugins/bearer/nla/nla.pro
+++ b/src/plugins/bearer/nla/nla.pro
@@ -2,7 +2,7 @@ TARGET = qnlabearer
QT = core core-private network network-private
-LIBS += -lws2_32
+QMAKE_USE_PRIVATE += ws2_32
HEADERS += qnlaengine.h \
../platformdefs_win.h \
diff --git a/src/plugins/bearer/nla/qnlaengine.cpp b/src/plugins/bearer/nla/qnlaengine.cpp
index 726e1efb92..e1e60389f1 100644
--- a/src/plugins/bearer/nla/qnlaengine.cpp
+++ b/src/plugins/bearer/nla/qnlaengine.cpp
@@ -75,38 +75,38 @@ QWindowsSockInit2::~QWindowsSockInit2()
#ifdef BEARER_MANAGEMENT_DEBUG
static void printBlob(NLA_BLOB *blob)
{
- qDebug() << "==== BEGIN NLA_BLOB ====" << endl
+ qDebug() << "==== BEGIN NLA_BLOB ====" << Qt::endl
- << "type:" << blob->header.type << endl
- << "size:" << blob->header.dwSize << endl
+ << "type:" << blob->header.type << Qt::endl
+ << "size:" << blob->header.dwSize << Qt::endl
<< "next offset:" << blob->header.nextOffset;
switch (blob->header.type) {
case NLA_RAW_DATA:
- qDebug() << "Raw Data" << endl
+ qDebug() << "Raw Data" << Qt::endl
<< '\t' << blob->data.rawData;
break;
case NLA_INTERFACE:
- qDebug() << "Interface" << endl
- << "\ttype:" << blob->data.interfaceData.dwType << endl
- << "\tspeed:" << blob->data.interfaceData.dwSpeed << endl
+ qDebug() << "Interface" << Qt::endl
+ << "\ttype:" << blob->data.interfaceData.dwType << Qt::endl
+ << "\tspeed:" << blob->data.interfaceData.dwSpeed << Qt::endl
<< "\tadapter:" << blob->data.interfaceData.adapterName;
break;
case NLA_802_1X_LOCATION:
- qDebug() << "802.1x Location" << endl
+ qDebug() << "802.1x Location" << Qt::endl
<< '\t' << blob->data.locationData.information;
break;
case NLA_CONNECTIVITY:
- qDebug() << "Connectivity" << endl
- << "\ttype:" << blob->data.connectivity.type << endl
+ qDebug() << "Connectivity" << Qt::endl
+ << "\ttype:" << blob->data.connectivity.type << Qt::endl
<< "\tinternet:" << blob->data.connectivity.internet;
break;
case NLA_ICS:
- qDebug() << "ICS" << endl
- << "\tspeed:" << blob->data.ICS.remote.speed << endl
- << "\ttype:" << blob->data.ICS.remote.type << endl
- << "\tstate:" << blob->data.ICS.remote.state << endl
- << "\tmachine name:" << blob->data.ICS.remote.machineName << endl
+ qDebug() << "ICS" << Qt::endl
+ << "\tspeed:" << blob->data.ICS.remote.speed << Qt::endl
+ << "\ttype:" << blob->data.ICS.remote.type << Qt::endl
+ << "\tstate:" << blob->data.ICS.remote.state << Qt::endl
+ << "\tmachine name:" << blob->data.ICS.remote.machineName << Qt::endl
<< "\tshared adapter name:" << blob->data.ICS.remote.sharedAdapterName;
break;
default:
@@ -119,9 +119,6 @@ static void printBlob(NLA_BLOB *blob)
static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interface)
{
-#ifdef Q_OS_WINCE
- Q_UNUSED(interface)
-#else
unsigned long oid;
DWORD bytesWritten;
@@ -177,8 +174,6 @@ static QNetworkConfiguration::BearerType qGetInterfaceType(const QString &interf
qDebug() << medium << physicalMedium;
#endif
-#endif
-
return QNetworkConfiguration::BearerUnknown;
}
@@ -307,16 +302,12 @@ void QNlaThread::run()
break;
}
-#ifndef Q_OS_WINCE
// Not interested in unrelated IO completion events
// although we also don't want to block them
while (WaitForSingleObjectEx(changeEvent, WSA_INFINITE, true) != WAIT_IO_COMPLETION &&
handle)
{
}
-#else
- WaitForSingleObject(changeEvent, WSA_INFINITE);
-#endif
mutex.lock();
if (handle) {
diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp
index 30935cacda..4908850cc5 100644
--- a/src/plugins/imageformats/ico/qicohandler.cpp
+++ b/src/plugins/imageformats/ico/qicohandler.cpp
@@ -523,17 +523,21 @@ QImage ICOReader::iconAt(int index)
if (!image.isNull()) {
readBMP(image);
if (!image.isNull()) {
- QImage mask(image.width(), image.height(), QImage::Format_Mono);
- if (!mask.isNull()) {
- mask.setColorCount(2);
- mask.setColor(0, qRgba(255,255,255,0xff));
- mask.setColor(1, qRgba(0 ,0 ,0 ,0xff));
- read1BitBMP(mask);
+ if (icoAttrib.depth == 32) {
+ img = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ } else {
+ QImage mask(image.width(), image.height(), QImage::Format_Mono);
if (!mask.isNull()) {
- img = image;
- img.setAlphaChannel(mask);
- // (Luckily, it seems that setAlphaChannel() does not ruin the alpha values
- // of partially transparent pixels in those icons that have that)
+ mask.setColorCount(2);
+ mask.setColor(0, qRgba(255,255,255,0xff));
+ mask.setColor(1, qRgba(0 ,0 ,0 ,0xff));
+ read1BitBMP(mask);
+ if (!mask.isNull()) {
+ img = image;
+ img.setAlphaChannel(mask);
+ // (Luckily, it seems that setAlphaChannel() does not ruin the alpha values
+ // of partially transparent pixels in those icons that have that)
+ }
}
}
}
diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
index 57fe7c2fa2..4e9828663f 100644
--- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontext.cpp
@@ -40,6 +40,7 @@
#include <QtCore/QCoreApplication>
#include <QtGui/QKeyEvent>
+#include <QtGui/QGuiApplication>
#include <locale.h>
@@ -121,7 +122,14 @@ bool QComposeInputContext::filterEvent(const QEvent *event)
QInputMethodEvent event;
event.setCommitString(composedText);
- QCoreApplication::sendEvent(m_focusObject, &event);
+
+ if (!m_focusObject && qApp)
+ m_focusObject = qApp->focusObject();
+
+ if (m_focusObject)
+ QCoreApplication::sendEvent(m_focusObject, &event);
+ else
+ qCWarning(lcXkbCompose, "no focus object");
reset();
return true;
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 6ae429b24e..70dde46ffa 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -485,7 +485,7 @@ static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring pa
}
if (Q_UNLIKELY(!m_main)) {
- qCritical() << "dlsym failed:" << dlerror() << endl
+ qCritical() << "dlsym failed:" << dlerror() << Qt::endl
<< "Could not find main method";
return false;
}
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index c31e43e0bb..db40c30d7d 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -791,7 +791,7 @@ void QAndroidInputContext::longPress(int x, int y)
return;
}
QList<QInputMethodEvent::Attribute> imAttributes;
- imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, 0, QVariant()));
+ imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, QVariant()));
imAttributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant()));
QInputMethodEvent event(QString(), imAttributes);
QGuiApplication::sendEvent(m_focusObject, &event);
@@ -978,15 +978,25 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right
m_composingText.clear();
m_composingTextStart = -1;
- QString text = query->value(Qt::ImSurroundingText).toString();
- if (text.isEmpty())
- return JNI_TRUE;
-
if (leftLength < 0) {
rightLength += -leftLength;
leftLength = 0;
}
+ QVariant textBeforeCursor = query->value(Qt::ImTextBeforeCursor);
+ QVariant textAfterCursor = query->value(Qt::ImTextAfterCursor);
+ if (textBeforeCursor.isValid() && textAfterCursor.isValid()) {
+ leftLength = qMin(leftLength, textBeforeCursor.toString().length());
+ rightLength = qMin(rightLength, textAfterCursor.toString().length());
+ } else {
+ int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ leftLength = qMin(leftLength, cursorPos);
+ rightLength = qMin(rightLength, query->value(Qt::ImSurroundingText).toString().length() - cursorPos);
+ }
+
+ if (leftLength == 0 && rightLength == 0)
+ return JNI_TRUE;
+
QInputMethodEvent event;
event.setCommitString(QString(), -leftLength, leftLength+rightLength);
sendInputMethodEvent(&event);
@@ -1075,6 +1085,14 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex
int cpos = localPos + composeLength; //actual cursor pos relative to the current block
int localOffset = 0; // start of extracted text relative to the current block
+ if (blockPos > 0) {
+ QString prevBlockEnding = query->value(Qt::ImTextBeforeCursor).toString();
+ prevBlockEnding.chop(localPos);
+ if (prevBlockEnding.endsWith(QLatin1Char('\n'))) {
+ localOffset = -qMin(20, prevBlockEnding.length());
+ blockText = prevBlockEnding.right(-localOffset) + blockText;
+ }
+ }
// It is documented that we should try to return hintMaxChars
// characters, but that's not what the standard Android controls do, and
@@ -1111,46 +1129,63 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/)
QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
{
- //### the preedit text could theoretically be after the cursor
- QVariant textAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, QVariant(length));
- if (textAfter.isValid()) {
- return textAfter.toString().left(length);
- }
-
- //compatibility code for old controls that do not implement the new API
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
- if (query.isNull())
+ if (length <= 0)
return QString();
- QString text = query->value(Qt::ImSurroundingText).toString();
- if (!text.length())
- return text;
+ QString text;
+
+ QVariant reportedTextAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, length);
+ if (reportedTextAfter.isValid()) {
+ text = reportedTextAfter.toString();
+ } else {
+ // Compatibility code for old controls that do not implement the new API
+ QSharedPointer<QInputMethodQueryEvent> query =
+ focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText);
+ if (query) {
+ const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ text = query->value(Qt::ImSurroundingText).toString().mid(cursorPos);
+ }
+ }
+
+ // Controls do not report preedit text, so we have to add it
+ if (!m_composingText.isEmpty()) {
+ const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
+ text = m_composingText.midRef(cursorPosInsidePreedit) + text;
+ }
- int cursorPos = query->value(Qt::ImCursorPosition).toInt();
- return text.mid(cursorPos, length);
+ text.truncate(length);
+ return text;
}
QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
{
- QVariant textBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, QVariant(length));
- if (textBefore.isValid())
- return textBefore.toString().rightRef(length) + m_composingText;
-
- //compatibility code for old controls that do not implement the new API
- QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
- if (query.isNull())
+ if (length <= 0)
return QString();
- int cursorPos = query->value(Qt::ImCursorPosition).toInt();
- QString text = query->value(Qt::ImSurroundingText).toString();
- if (!text.length())
- return text;
+ QString text;
- //### the preedit text does not need to be immediately before the cursor
- if (cursorPos <= length)
- return text.leftRef(cursorPos) + m_composingText;
- else
- return text.midRef(cursorPos - length, length) + m_composingText;
+ QVariant reportedTextBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, length);
+ if (reportedTextBefore.isValid()) {
+ text = reportedTextBefore.toString();
+ } else {
+ // Compatibility code for old controls that do not implement the new API
+ QSharedPointer<QInputMethodQueryEvent> query =
+ focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText);
+ if (query) {
+ const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ text = query->value(Qt::ImSurroundingText).toString().left(cursorPos);
+ }
+ }
+
+ // Controls do not report preedit text, so we have to add it
+ if (!m_composingText.isEmpty()) {
+ const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart;
+ text += m_composingText.leftRef(cursorPosInsidePreedit);
+ }
+
+ if (text.length() > length)
+ text = text.right(length);
+ return text;
}
/*
@@ -1213,6 +1248,8 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
if (query.isNull())
return JNI_FALSE;
+ if (start == end)
+ return JNI_TRUE;
if (start > end)
qSwap(start, end);
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 368cf56c80..db4ec251ae 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -177,7 +177,7 @@ NSString *macRole(QAccessibleInterface *interface)
if (roleMap.isEmpty())
populateRoleMap();
- // MAC_ACCESSIBILTY_DEBUG() << "role for" << interface.object() << "interface role" << hex << qtRole;
+ // MAC_ACCESSIBILTY_DEBUG() << "role for" << interface.object() << "interface role" << Qt::hex << qtRole;
if (roleMap.contains(qtRole)) {
// MAC_ACCESSIBILTY_DEBUG() << "return" << roleMap[qtRole];
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index 914aaa2b1b..7fbe729381 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -52,7 +52,7 @@
@class QT_MANGLE_NAMESPACE(QMacAccessibilityElement);
-@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject
+@interface QT_MANGLE_NAMESPACE(QMacAccessibilityElement) : NSObject <NSAccessibilityElement>
- (instancetype)initWithId:(QAccessible::Id)anId;
+ (instancetype)elementWithId:(QAccessible::Id)anId;
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index f0ef70e3a3..3560c9d9b5 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -174,6 +174,17 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
// accessibility protocol
//
+- (BOOL)isAccessibilityFocused
+{
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid()) {
+ return false;
+ }
+ // Just check if the app thinks we're focused.
+ id focusedElement = NSApp.accessibilityApplicationFocusedUIElement;
+ return [focusedElement isEqual:self];
+}
+
// attributes
+ (id) lineNumberForIndex: (int)index forText:(const QString &)text
@@ -187,54 +198,58 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return YES;
}
-- (NSArray<NSString *> *)accessibilityAttributeNames {
- static NSArray<NSString *> *defaultAttributes = [@[
- NSAccessibilityRoleAttribute,
- NSAccessibilityRoleDescriptionAttribute,
- NSAccessibilitySubroleAttribute,
- NSAccessibilityChildrenAttribute,
- NSAccessibilityFocusedAttribute,
- NSAccessibilityParentAttribute,
- NSAccessibilityWindowAttribute,
- NSAccessibilityTopLevelUIElementAttribute,
- NSAccessibilityPositionAttribute,
- NSAccessibilitySizeAttribute,
- NSAccessibilityTitleAttribute,
- NSAccessibilityDescriptionAttribute,
- NSAccessibilityEnabledAttribute
- ] retain];
+- (NSString *) accessibilityRole {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return NSAccessibilityUnknownRole;
+ return QCocoaAccessible::macRole(iface);
+}
+- (NSString *) accessibilitySubRole {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface || !iface->isValid())
- return defaultAttributes;
+ return NSAccessibilityUnknownRole;
+ return QCocoaAccessible::macSubrole(iface);
+}
- NSMutableArray<NSString *> *attributes = [[NSMutableArray<NSString *> alloc] initWithCapacity:defaultAttributes.count];
- [attributes addObjectsFromArray:defaultAttributes];
+- (NSString *) accessibilityRoleDescription {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return NSAccessibilityUnknownRole;
+ return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole);
+}
- if (QCocoaAccessible::hasValueAttribute(iface)) {
- [attributes addObject:NSAccessibilityValueAttribute];
- }
+- (NSArray *) accessibilityChildren {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return nil;
+ return QCocoaAccessible::unignoredChildren(iface);
+}
- if (iface->textInterface()) {
- [attributes addObjectsFromArray:@[
- NSAccessibilityNumberOfCharactersAttribute,
- NSAccessibilitySelectedTextAttribute,
- NSAccessibilitySelectedTextRangeAttribute,
- NSAccessibilityVisibleCharacterRangeAttribute,
- NSAccessibilityInsertionPointLineNumberAttribute
- ]];
-
-// TODO: multi-selection: NSAccessibilitySelectedTextRangesAttribute,
- }
+- (id) accessibilityWindow {
+ // We're in the same window as our parent.
+ return [self.accessibilityParent accessibilityWindow];
+}
- if (iface->valueInterface()) {
- [attributes addObjectsFromArray:@[
- NSAccessibilityMinValueAttribute,
- NSAccessibilityMaxValueAttribute
- ]];
- }
+- (id) accessibilityTopLevelUIElementAttribute {
+ // We're in the same top level element as our parent.
+ return [self.accessibilityParent accessibilityTopLevelUIElementAttribute];
+}
- return [attributes autorelease];
+- (NSString *) accessibilityTitle {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return nil;
+ if (iface->role() == QAccessible::StaticText)
+ return nil;
+ return iface->text(QAccessible::Name).toNSString();
+}
+
+- (BOOL) accessibilityEnabledAttribute {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return false;
+ return !iface->state().disabled;
}
- (id)accessibilityParent {
@@ -271,112 +286,117 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return QCocoaScreen::mapToNative(iface->rect());
}
-- (id) minValueAttribute:(QAccessibleInterface*)iface {
+- (NSString*)accessibilityLabel {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid()) {
+ qWarning() << "Called accessibilityLabel on invalid object: " << axid;
+ return nil;
+ }
+ return iface->text(QAccessible::Description).toNSString();
+}
+
+- (void)setAccessibilityLabel:(NSString*)label{
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return;
+ iface->setText(QAccessible::Description, QString::fromNSString(label));
+}
+
+- (id) accessibilityMinValue:(QAccessibleInterface*)iface {
if (QAccessibleValueInterface *val = iface->valueInterface())
return @(val->minimumValue().toDouble());
return nil;
}
-- (id) maxValueAttribute:(QAccessibleInterface*)iface {
+- (id) accessibilityMaxValue:(QAccessibleInterface*)iface {
if (QAccessibleValueInterface *val = iface->valueInterface())
return @(val->maximumValue().toDouble());
return nil;
}
-- (id)accessibilityAttributeValue:(NSString *)attribute {
+- (id) accessibilityValue {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
- qWarning() << "Called attribute on invalid object: " << axid;
+ if (!iface || !iface->isValid())
return nil;
- }
- if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
- return QCocoaAccessible::macRole(iface);
- } else if ([attribute isEqualToString:NSAccessibilitySubroleAttribute]) {
- return QCocoaAccessible::macSubrole(iface);
- } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
- return NSAccessibilityRoleDescription(QCocoaAccessible::macRole(iface),
- [self accessibilityAttributeValue:NSAccessibilitySubroleAttribute]);
- } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
- return QCocoaAccessible::unignoredChildren(iface);
- } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
- // Just check if the app thinks we're focused.
- id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
- return @([focusedElement isEqual:self]);
- } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
- return self.accessibilityParent;
- } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
- // We're in the same window as our parent.
- return [[self accessibilityParent] accessibilityAttributeValue:NSAccessibilityWindowAttribute];
- } else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) {
- // We're in the same top level element as our parent.
- return [[self accessibilityParent] accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
- } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
- // The position in points of the element's lower-left corner in screen-relative coordinates
- QPointF qtPosition = QRectF(iface->rect()).bottomLeft();
- return [NSValue valueWithPoint:QCocoaScreen::mapToNative(qtPosition)];
- } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
- QSize qtSize = iface->rect().size();
- return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())];
- } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
- if (iface->role() == QAccessible::StaticText)
- return nil;
- return iface->text(QAccessible::Name).toNSString();
- } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
- return iface->text(QAccessible::Description).toNSString();
- } else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) {
- return @(!iface->state().disabled);
- } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
- // VoiceOver asks for the value attribute for all elements. Return nil
- // if we don't want the element to have a value attribute.
- if (!QCocoaAccessible::hasValueAttribute(iface))
- return nil;
+ // VoiceOver asks for the value attribute for all elements. Return nil
+ // if we don't want the element to have a value attribute.
+ if (!QCocoaAccessible::hasValueAttribute(iface))
+ return nil;
+
+ return QCocoaAccessible::getValueAttribute(iface);
+}
- return QCocoaAccessible::getValueAttribute(iface);
+- (NSInteger) accessibilityNumberOfCharacters {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return 0;
+ if (QAccessibleTextInterface *text = iface->textInterface())
+ return text->characterCount();
+ return 0;
+}
- } else if ([attribute isEqualToString:NSAccessibilityNumberOfCharactersAttribute]) {
- if (QAccessibleTextInterface *text = iface->textInterface())
- return @(text->characterCount());
+- (NSString *) accessibilitySelectedText {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
return nil;
- } else if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]) {
- if (QAccessibleTextInterface *text = iface->textInterface()) {
- int start = 0;
- int end = 0;
+ if (QAccessibleTextInterface *text = iface->textInterface()) {
+ int start = 0;
+ int end = 0;
+ text->selection(0, &start, &end);
+ return text->text(start, end).toNSString();
+ }
+ return nil;
+}
+
+- (NSRange) accessibilitySelectedTextRange {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return NSRange();
+ if (QAccessibleTextInterface *text = iface->textInterface()) {
+ int start = 0;
+ int end = 0;
+ if (text->selectionCount() > 0) {
text->selection(0, &start, &end);
- return text->text(start, end).toNSString();
- }
- return nil;
- } else if ([attribute isEqualToString:NSAccessibilitySelectedTextRangeAttribute]) {
- if (QAccessibleTextInterface *text = iface->textInterface()) {
- int start = 0;
- int end = 0;
- if (text->selectionCount() > 0) {
- text->selection(0, &start, &end);
- } else {
- start = text->cursorPosition();
- end = start;
- }
- return [NSValue valueWithRange:NSMakeRange(quint32(start), quint32(end - start))];
- }
- return [NSValue valueWithRange: NSMakeRange(0, 0)];
- } else if ([attribute isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) {
- // FIXME This is not correct and may impact performance for big texts
- if (QAccessibleTextInterface *text = iface->textInterface())
- return [NSValue valueWithRange: NSMakeRange(0, text->characterCount())];
- return [NSValue valueWithRange: NSMakeRange(0, iface->text(QAccessible::Name).length())];
- } else if ([attribute isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) {
- if (QAccessibleTextInterface *text = iface->textInterface()) {
- int position = text->cursorPosition();
- return [self accessibilityAttributeValue:NSAccessibilityLineForIndexParameterizedAttribute forParameter:@(position)];
+ } else {
+ start = text->cursorPosition();
+ end = start;
}
- return nil;
- } else if ([attribute isEqualToString:NSAccessibilityMinValueAttribute]) {
- return [self minValueAttribute:iface];
- } else if ([attribute isEqualToString:NSAccessibilityMaxValueAttribute]) {
- return [self maxValueAttribute:iface];
+ return NSMakeRange(quint32(start), quint32(end - start));
}
+ return NSMakeRange(0, 0);
+}
- return nil;
+- (NSInteger)accessibilityLineForIndex:(NSInteger)index {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return 0;
+ if (QAccessibleTextInterface *text = iface->textInterface()) {
+ QString textToPos = text->text(0, index);
+ return textToPos.count('\n');
+ }
+ return 0;
+}
+
+- (NSRange)accessibilityVisibleCharacterRange {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return NSRange();
+ // FIXME This is not correct and may impact performance for big texts
+ if (QAccessibleTextInterface *text = iface->textInterface())
+ return NSMakeRange(0, static_cast<uint>(text->characterCount()));
+ return NSMakeRange(0, static_cast<uint>(iface->text(QAccessible::Name).length()));
+}
+
+- (NSInteger) accessibilityInsertionPointLineNumber {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return 0;
+ if (QAccessibleTextInterface *text = iface->textInterface()) {
+ int position = text->cursorPosition();
+ return [self accessibilityLineForIndex:position];
+ }
+ return 0;
}
- (NSArray *)accessibilityParameterizedAttributeNames {
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index 508f24d578..acddc3ecc8 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -76,9 +76,12 @@ public:
void endPaint() override;
void flush(QWindow *, const QRegion &, const QPoint &) override;
+#ifndef QT_NO_OPENGL
void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, bool translucentBackground) override;
+#endif
+ QImage toImage() const override;
QPlatformGraphicsBuffer *graphicsBuffer() const override;
private:
@@ -93,6 +96,7 @@ private:
QRegion dirtyRegion; // In unscaled coordinates
QImage *asImage();
+ qreal devicePixelRatio() const { return m_devicePixelRatio; }
private:
qreal m_devicePixelRatio;
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 8e4e928bc5..c381f87844 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -273,18 +273,6 @@ void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const
// ----------------------------------------------------------------------------
-// https://stackoverflow.com/a/52722575/2761869
-template<class R>
-struct backwards_t {
- R r;
- constexpr auto begin() const { using std::rbegin; return rbegin(r); }
- constexpr auto begin() { using std::rbegin; return rbegin(r); }
- constexpr auto end() const { using std::rend; return rend(r); }
- constexpr auto end() { using std::rend; return rend(r); }
-};
-template<class R>
-constexpr backwards_t<R> backwards(R&& r) { return {std::forward<R>(r)}; }
-
QCALayerBackingStore::QCALayerBackingStore(QWindow *window)
: QPlatformBackingStore(window)
{
@@ -460,12 +448,29 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
+ // If the backingstore is just flushed, without being painted to first, then we may
+ // end in a situation where the backingstore is flushed to a layer with a different
+ // scale factor than the one it was created for in beginPaint. This is the client's
+ // fault in not picking up the change in scale factor of the window and re-painting
+ // the backingstore accordingly. To smoothing things out, we warn about this situation,
+ // and change the layer's contentsScale to match the scale of the back buffer, so that
+ // we at least cover the whole layer. This is necessary since we set the view's
+ // contents placement policy to NSViewLayerContentsPlacementTopLeft, which means
+ // AppKit will not do any scaling on our behalf.
+ if (m_buffers.back()->devicePixelRatio() != flushedView.layer.contentsScale) {
+ qCWarning(lcQpaBackingStore) << "Back buffer dpr of" << m_buffers.back()->devicePixelRatio()
+ << "doesn't match" << flushedView.layer << "contents scale of" << flushedView.layer.contentsScale
+ << "- updating layer to match.";
+ flushedView.layer.contentsScale = m_buffers.back()->devicePixelRatio();
+ }
+
id backBufferSurface = (__bridge id)m_buffers.back()->surface();
if (flushedView.layer.contents == backBufferSurface) {
// We've managed to paint to the back buffer again before Core Animation had time
- // to flush the transaction and persist the layer changes to the window server.
- // The layer already knows about the back buffer, and we don't need to re-apply
- // it to pick up the surface changes, so bail out early.
+ // to flush the transaction and persist the layer changes to the window server, or
+ // we've been asked to flush without painting anything. The layer already knows about
+ // the back buffer, and we don't need to re-apply it to pick up any possible surface
+ // changes, so bail out early.
qCInfo(lcQpaBackingStore).nospace() << "Skipping flush of " << flushedView
<< ", layer already reflects back buffer";
return;
@@ -506,6 +511,7 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region,
// the window server.
}
+#ifndef QT_NO_OPENGL
void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
QPlatformTextureList *textures, bool translucentBackground)
{
@@ -514,6 +520,22 @@ void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion &regio
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground);
}
+#endif
+
+QImage QCALayerBackingStore::toImage() const
+{
+ if (!const_cast<QCALayerBackingStore*>(this)->prepareForFlush())
+ return QImage();
+
+ // We need to make a copy here, as the returned image could be used just
+ // for reading, in which case it won't detach, and then the underlying
+ // image data might change under the feet of the client when we re-use
+ // the buffer at a later point.
+ m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
+ QImage imageCopy = m_buffers.back()->asImage()->copy();
+ m_buffers.back()->unlock();
+ return imageCopy;
+}
QPlatformGraphicsBuffer *QCALayerBackingStore::graphicsBuffer() const
{
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index d1695ea860..5f32400af0 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -51,7 +51,6 @@
#include "qt_mac_p.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
-#include <qregexp.h>
#include <qbuffer.h>
#include <qdebug.h>
#include <qstringlist.h>
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 69aa7937b6..69a1854598 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -176,6 +176,18 @@ T qt_mac_resolveOption(const T &fallback, QWindow *window, const QByteArray &pro
return fallback;
}
+// https://stackoverflow.com/a/52722575/2761869
+template<class R>
+struct backwards_t {
+ R r;
+ constexpr auto begin() const { using std::rbegin; return rbegin(r); }
+ constexpr auto begin() { using std::rbegin; return rbegin(r); }
+ constexpr auto end() const { using std::rend; return rend(r); }
+ constexpr auto end() { using std::rend; return rend(r); }
+};
+template<class R>
+constexpr backwards_t<R> backwards(R&& r) { return {std::forward<R>(r)}; }
+
// -------------------------------------------------------------------------
#if !defined(Q_PROCESSOR_X86_64)
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 9c705616ba..1b184cd60f 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -63,7 +63,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
Q_LOGGING_CATEGORY(lcQpaDrawing, "qt.qpa.drawing");
Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse", QtCriticalMsg);
-Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen");
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen", QtCriticalMsg);
//
// Conversion Functions
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 04cb4e1226..bfc3bfe9de 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -61,8 +61,6 @@
QT_BEGIN_NAMESPACE
-class QCocoaScreen;
-
class QCocoaIntegration : public QObject, public QPlatformIntegration
{
Q_OBJECT
@@ -113,9 +111,6 @@ public:
Qt::KeyboardModifiers queryKeyboardModifiers() const override;
QList<int> possibleKeys(const QKeyEvent *event) const override;
- void updateScreens();
- QCocoaScreen *screenForNSScreen(NSScreen *nsScreen);
-
void setToolbar(QWindow *window, NSToolbar *toolbar);
NSToolbar *toolbar(QWindow *window) const;
void clearToolbars();
@@ -143,8 +138,6 @@ private:
QScopedPointer<QCocoaAccessibility> mAccessibility;
#endif
QScopedPointer<QPlatformTheme> mPlatformTheme;
- QList<QCocoaScreen *> mScreens;
- QMacScopedObserver m_screensObserver;
#ifndef QT_NO_CLIPBOARD
QCocoaClipboard *mCocoaClipboard;
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index fb3d05d3e4..300082d694 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -207,9 +207,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
// which will resolve to an actual value and result in screen invalidation.
cocoaApplication.presentationOptions = NSApplicationPresentationDefault;
- m_screensObserver = QMacScopedObserver([NSApplication sharedApplication],
- NSApplicationDidChangeScreenParametersNotification, [&]() { updateScreens(); });
- updateScreens();
+ QCocoaScreen::initializeScreens();
QMacInternalPasteboardMime::initializeMimeTypes();
QCocoaMimeTypes::initializeMimeTypes();
@@ -242,10 +240,7 @@ QCocoaIntegration::~QCocoaIntegration()
QMacInternalPasteboardMime::destroyMimeTypes();
#endif
- // Delete screens in reverse order to avoid crash in case of multiple screens
- while (!mScreens.isEmpty()) {
- QWindowSystemInterface::handleScreenRemoved(mScreens.takeLast());
- }
+ QCocoaScreen::cleanupScreens();
clearToolbars();
}
@@ -260,88 +255,6 @@ QCocoaIntegration::Options QCocoaIntegration::options() const
return mOptions;
}
-/*!
- \brief Synchronizes the screen list, adds new screens, removes deleted ones
-*/
-void QCocoaIntegration::updateScreens()
-{
- NSArray<NSScreen *> *scrs = [NSScreen screens];
- NSMutableArray<NSScreen *> *screens = [NSMutableArray<NSScreen *> arrayWithArray:scrs];
- if ([screens count] == 0)
- if ([NSScreen mainScreen])
- [screens addObject:[NSScreen mainScreen]];
- if ([screens count] == 0)
- return;
- QSet<QCocoaScreen*> remainingScreens = QSet<QCocoaScreen*>::fromList(mScreens);
- QList<QPlatformScreen *> siblings;
- uint screenCount = [screens count];
- for (uint i = 0; i < screenCount; i++) {
- NSScreen* scr = [screens objectAtIndex:i];
- CGDirectDisplayID dpy = scr.qt_displayId;
- // If this screen is a mirror and is not the primary one of the mirror set, ignore it.
- // Exception: The NSScreen API has been observed to a return a screen list with one
- // mirrored, non-primary screen when Qt is running as a startup item. Always use the
- // screen if there's only one screen in the list.
- if (screenCount > 1 && CGDisplayIsInMirrorSet(dpy)) {
- CGDirectDisplayID primary = CGDisplayMirrorsDisplay(dpy);
- if (primary != kCGNullDirectDisplay && primary != dpy)
- continue;
- }
- QCocoaScreen* screen = nullptr;
- foreach (QCocoaScreen* existingScr, mScreens) {
- // NSScreen documentation says do not cache the array returned from [NSScreen screens].
- // However in practice, we can identify a screen by its pointer: if resolution changes,
- // the NSScreen object will be the same instance, just with different values.
- if (existingScr->nativeScreen() == scr) {
- screen = existingScr;
- break;
- }
- }
- if (screen) {
- remainingScreens.remove(screen);
- screen->updateProperties();
- } else {
- screen = new QCocoaScreen(i);
- mScreens.append(screen);
- qCDebug(lcQpaScreen) << "Adding" << screen;
- QWindowSystemInterface::handleScreenAdded(screen);
- }
- siblings << screen;
- }
-
- // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the
- // mirrors. Note that some of the screens we update the siblings list for here may be deleted
- // below, but update anyway to keep the to-be-deleted screens out of the siblings list.
- foreach (QCocoaScreen* screen, mScreens)
- screen->setVirtualSiblings(siblings);
-
- // Now the leftovers in remainingScreens are no longer current, so we can delete them.
- foreach (QCocoaScreen* screen, remainingScreens) {
- mScreens.removeOne(screen);
- // Prevent stale references to NSScreen during destroy
- screen->m_screenIndex = -1;
- qCDebug(lcQpaScreen) << "Removing" << screen;
- QWindowSystemInterface::handleScreenRemoved(screen);
- }
-}
-
-QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen)
-{
- NSUInteger index = [[NSScreen screens] indexOfObject:nsScreen];
- if (index == NSNotFound)
- return nullptr;
-
- if (index >= unsigned(mScreens.count()))
- updateScreens();
-
- for (QCocoaScreen *screen : mScreens) {
- if (screen->nativeScreen() == nsScreen)
- return screen;
- }
-
- return nullptr;
-}
-
bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
@@ -490,8 +403,13 @@ QCocoaServices *QCocoaIntegration::services() const
QVariant QCocoaIntegration::styleHint(StyleHint hint) const
{
- if (hint == QPlatformIntegration::FontSmoothingGamma)
+ switch (hint) {
+ case FontSmoothingGamma:
return QCoreTextFontEngine::fontSmoothingGamma();
+ case ShowShortcutsInContextMenus:
+ return QVariant(false);
+ default: break;
+ }
return QPlatformIntegration::styleHint(hint);
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index e54b6284e5..32fc3ab660 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -53,6 +53,7 @@
#include <QtGui/private/qcoregraphics_p.h>
#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
index 9ded98df32..491af2fe9c 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.h
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -48,10 +48,14 @@
QT_BEGIN_NAMESPACE
+class QCocoaIntegration;
+
class QCocoaScreen : public QPlatformScreen
{
public:
- QCocoaScreen(int screenIndex);
+ static void initializeScreens();
+ static void cleanupScreens();
+
~QCocoaScreen();
// ----------------------------------------------------
@@ -61,19 +65,18 @@ public:
QRect availableGeometry() const override { return m_availableGeometry; }
int depth() const override { return m_depth; }
QImage::Format format() const override { return m_format; }
- qreal devicePixelRatio() const override;
+ qreal devicePixelRatio() const override { return m_devicePixelRatio; }
QSizeF physicalSize() const override { return m_physicalSize; }
QDpi logicalDpi() const override { return m_logicalDpi; }
qreal refreshRate() const override { return m_refreshRate; }
QString name() const override { return m_name; }
QPlatformCursor *cursor() const override { return m_cursor; }
QWindow *topLevelAt(const QPoint &point) const override;
- QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; }
+ QList<QPlatformScreen *> virtualSiblings() const override;
QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
// ----------------------------------------------------
- // Additional methods
- void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; }
+
NSScreen *nativeScreen() const;
void updateProperties();
@@ -82,14 +85,21 @@ public:
bool isRunningDisplayLink() const;
static QCocoaScreen *primaryScreen();
+ static QCocoaScreen *get(NSScreen *nsScreen);
+ static QCocoaScreen *get(CGDirectDisplayID displayId);
static CGPoint mapToNative(const QPointF &pos, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
static CGRect mapToNative(const QRectF &rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
static QPointF mapFromNative(CGPoint pos, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
static QRectF mapFromNative(CGRect rect, QCocoaScreen *screen = QCocoaScreen::primaryScreen());
-public:
- int m_screenIndex;
+private:
+ QCocoaScreen(CGDirectDisplayID displayId);
+ static void add(CGDirectDisplayID displayId);
+ void remove();
+
+ CGDirectDisplayID m_displayId = 0;
+
QRect m_geometry;
QRect m_availableGeometry;
QDpi m_logicalDpi;
@@ -99,11 +109,13 @@ public:
QImage::Format m_format;
QSizeF m_physicalSize;
QCocoaCursor *m_cursor;
- QList<QPlatformScreen *> m_siblings;
+ qreal m_devicePixelRatio;
CVDisplayLinkRef m_displayLink = nullptr;
dispatch_source_t m_displayLinkSource = nullptr;
QAtomicInt m_pendingUpdates;
+
+ friend QDebug operator<<(QDebug debug, const QCocoaScreen *screen);
};
#ifndef QT_NO_DEBUG_STREAM
@@ -116,5 +128,4 @@ QT_END_NAMESPACE
@property(readonly) CGDirectDisplayID qt_displayId;
@end
-#endif
-
+#endif // QCOCOASCREEN_H
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index 6a5b0e6e3e..392099d083 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -41,6 +41,7 @@
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
+#include "qcocoaintegration.h"
#include <QtCore/qcoreapplication.h>
#include <QtGui/private/qcoregraphics_p.h>
@@ -53,34 +54,104 @@
QT_BEGIN_NAMESPACE
-class QCoreTextFontEngine;
-class QFontEngineFT;
+void QCocoaScreen::initializeScreens()
+{
+ uint32_t displayCount = 0;
+ if (CGGetActiveDisplayList(0, nullptr, &displayCount) != kCGErrorSuccess)
+ qFatal("Failed to get number of active displays");
+
+ CGDirectDisplayID activeDisplays[displayCount];
+ if (CGGetActiveDisplayList(displayCount, &activeDisplays[0], &displayCount) != kCGErrorSuccess)
+ qFatal("Failed to get active displays");
+
+ for (CGDirectDisplayID displayId : activeDisplays)
+ QCocoaScreen::add(displayId);
+
+ CGDisplayRegisterReconfigurationCallback([](CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo) {
+ if (flags & kCGDisplayBeginConfigurationFlag)
+ return; // Wait for changes to apply
+
+ Q_UNUSED(userInfo);
+
+ QCocoaScreen *cocoaScreen = QCocoaScreen::get(displayId);
+
+ if ((flags & kCGDisplayAddFlag) || !cocoaScreen) {
+ if (!CGDisplayIsActive(displayId)) {
+ qCDebug(lcQpaScreen) << "Not adding inactive display" << displayId;
+ return; // Will be added when activated
+ }
+ QCocoaScreen::add(displayId);
+ } else if ((flags & kCGDisplayRemoveFlag) || !CGDisplayIsActive(displayId)) {
+ cocoaScreen->remove();
+ } else {
+ // Detect changes to the primary screen immediately, instead of
+ // waiting for a display reconfigure with kCGDisplaySetMainFlag.
+ // This ensures that any property updates to the other screens
+ // will be in reference to the correct primary screen.
+ QCocoaScreen *mainDisplay = QCocoaScreen::get(CGMainDisplayID());
+ if (QGuiApplication::primaryScreen()->handle() != mainDisplay) {
+ mainDisplay->updateProperties();
+ qCInfo(lcQpaScreen) << "Primary screen changed to" << mainDisplay;
+ QWindowSystemInterface::handlePrimaryScreenChanged(mainDisplay);
+ }
-QCocoaScreen::QCocoaScreen(int screenIndex)
- : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0)
+ if (cocoaScreen == mainDisplay)
+ return; // Already reconfigured
+
+ cocoaScreen->updateProperties();
+ qCInfo(lcQpaScreen) << "Reconfigured" << cocoaScreen;
+ }
+ }, nullptr);
+}
+
+void QCocoaScreen::add(CGDirectDisplayID displayId)
+{
+ QCocoaScreen *cocoaScreen = new QCocoaScreen(displayId);
+ qCInfo(lcQpaScreen) << "Adding" << cocoaScreen;
+ QWindowSystemInterface::handleScreenAdded(cocoaScreen, CGDisplayIsMain(displayId));
+}
+
+QCocoaScreen::QCocoaScreen(CGDirectDisplayID displayId)
+ : QPlatformScreen(), m_displayId(displayId)
{
updateProperties();
m_cursor = new QCocoaCursor;
}
-QCocoaScreen::~QCocoaScreen()
+void QCocoaScreen::cleanupScreens()
{
- delete m_cursor;
+ // Remove screens in reverse order to avoid crash in case of multiple screens
+ for (QScreen *screen : backwards(QGuiApplication::screens()))
+ static_cast<QCocoaScreen*>(screen->handle())->remove();
+}
- CVDisplayLinkRelease(m_displayLink);
- if (m_displayLinkSource)
- dispatch_release(m_displayLinkSource);
+void QCocoaScreen::remove()
+{
+ m_displayId = 0; // Prevent stale references during removal
+
+ // This may result in the application responding to QGuiApplication::screenRemoved
+ // by moving the window to another screen, either by setGeometry, or by setScreen.
+ // If the window isn't moved by the application, Qt will as a fallback move it to
+ // the primary screen via setScreen. Due to the way setScreen works, this won't
+ // actually recreate the window on the new screen, it will just assign the new
+ // QScreen to the window. The associated NSWindow will have an NSScreen determined
+ // by AppKit. AppKit will then move the window to another screen by changing the
+ // geometry, and we will get a callback in QCocoaWindow::windowDidMove and then
+ // QCocoaWindow::windowDidChangeScreen. At that point the window will appear to have
+ // already changed its screen, but that's only true if comparing the Qt screens,
+ // not when comparing the NSScreens.
+ QWindowSystemInterface::handleScreenRemoved(this);
}
-NSScreen *QCocoaScreen::nativeScreen() const
+QCocoaScreen::~QCocoaScreen()
{
- NSArray<NSScreen *> *screens = [NSScreen screens];
+ Q_ASSERT_X(!screen(), "QCocoaScreen", "QScreen should be deleted first");
- // Stale reference, screen configuration has changed
- if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count])
- return nil;
+ delete m_cursor;
- return [screens objectAtIndex:m_screenIndex];
+ CVDisplayLinkRelease(m_displayLink);
+ if (m_displayLinkSource)
+ dispatch_release(m_displayLinkSource);
}
static QString displayName(CGDirectDisplayID displayID)
@@ -117,35 +188,37 @@ static QString displayName(CGDirectDisplayID displayID)
void QCocoaScreen::updateProperties()
{
- NSScreen *nsScreen = nativeScreen();
- if (!nsScreen)
- return;
+ Q_ASSERT(m_displayId);
const QRect previousGeometry = m_geometry;
const QRect previousAvailableGeometry = m_availableGeometry;
const QDpi previousLogicalDpi = m_logicalDpi;
const qreal previousRefreshRate = m_refreshRate;
+ // Some properties are only available via NSScreen
+ NSScreen *nsScreen = nativeScreen();
+ Q_ASSERT(nsScreen);
+
// The reference screen for the geometry is always the primary screen
- QRectF primaryScreenGeometry = QRectF::fromCGRect([[NSScreen screens] firstObject].frame);
+ QRectF primaryScreenGeometry = QRectF::fromCGRect(CGDisplayBounds(CGMainDisplayID()));
m_geometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.frame), primaryScreenGeometry).toRect();
m_availableGeometry = qt_mac_flip(QRectF::fromCGRect(nsScreen.visibleFrame), primaryScreenGeometry).toRect();
+ m_devicePixelRatio = nsScreen.backingScaleFactor;
+
m_format = QImage::Format_RGB32;
- m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
+ m_depth = NSBitsPerPixelFromDepth(nsScreen.depth);
- CGDirectDisplayID dpy = nsScreen.qt_displayId;
- CGSize size = CGDisplayScreenSize(dpy);
+ CGSize size = CGDisplayScreenSize(m_displayId);
m_physicalSize = QSizeF(size.width, size.height);
m_logicalDpi.first = 72;
m_logicalDpi.second = 72;
- CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(dpy);
+
+ QCFType<CGDisplayModeRef> displayMode = CGDisplayCopyDisplayMode(m_displayId);
float refresh = CGDisplayModeGetRefreshRate(displayMode);
- CGDisplayModeRelease(displayMode);
- if (refresh > 0)
- m_refreshRate = refresh;
+ m_refreshRate = refresh > 0 ? refresh : 60.0;
- m_name = displayName(dpy);
+ m_name = displayName(m_displayId);
const bool didChangeGeometry = m_geometry != previousGeometry || m_availableGeometry != previousAvailableGeometry;
@@ -155,24 +228,6 @@ void QCocoaScreen::updateProperties()
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second);
if (m_refreshRate != previousRefreshRate)
QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate);
-
- qCDebug(lcQpaScreen) << "Updated properties for" << this;
-
- if (didChangeGeometry) {
- // When a screen changes its geometry, AppKit will send us a NSWindowDidMoveNotification
- // for each window, resulting in calls to handleGeometryChange(), but this happens before
- // the NSApplicationDidChangeScreenParametersNotification, so when we map the new geometry
- // (which is correct at that point) to the screen using QCocoaScreen::mapFromNative(), we
- // end up using the stale screen geometry, and the new window geometry we report is wrong.
- // To make sure we finally report the correct window geometry, we need to do another pass
- // of geometry reporting, now that the screen properties have been updates. FIXME: Ideally
- // this would be solved by not caching the screen properties in QCocoaScreen, but that
- // requires more research.
- for (QWindow *window : windows()) {
- if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow*>(window->handle()))
- cocoaWindow->handleGeometryChange();
- }
- }
}
// ----------------------- Display link -----------------------
@@ -181,8 +236,10 @@ Q_LOGGING_CATEGORY(lcQpaScreenUpdates, "qt.qpa.screen.updates", QtCriticalMsg);
void QCocoaScreen::requestUpdate()
{
+ Q_ASSERT(m_displayId);
+
if (!m_displayLink) {
- CVDisplayLinkCreateWithCGDisplay(nativeScreen().qt_displayId, &m_displayLink);
+ CVDisplayLinkCreateWithCGDisplay(m_displayId, &m_displayLink);
CVDisplayLinkSetOutputCallback(m_displayLink, [](CVDisplayLinkRef, const CVTimeStamp*,
const CVTimeStamp*, CVOptionFlags, CVOptionFlags*, void* displayLinkContext) -> int {
// FIXME: It would be nice if update requests would include timing info
@@ -269,6 +326,9 @@ struct DeferredDebugHelper
void QCocoaScreen::deliverUpdateRequests()
{
+ if (!m_displayId)
+ return; // Screen removed
+
QMacAutoReleasePool pool;
// The CVDisplayLink callback is a notification that it's a good time to produce a new frame.
@@ -283,7 +343,7 @@ void QCocoaScreen::deliverUpdateRequests()
const int pendingUpdates = ++m_pendingUpdates;
DeferredDebugHelper screenUpdates(lcQpaScreenUpdates());
- qDeferredDebug(screenUpdates) << "display link callback for screen " << m_screenIndex;
+ qDeferredDebug(screenUpdates) << "display link callback for screen " << m_displayId;
if (const int framesAheadOfDelivery = pendingUpdates - 1) {
// If we have more than one update pending it means that a previous display link callback
@@ -370,13 +430,6 @@ bool QCocoaScreen::isRunningDisplayLink() const
// -----------------------------------------------------------
-qreal QCocoaScreen::devicePixelRatio() const
-{
- QMacAutoReleasePool pool;
- NSScreen *nsScreen = nativeScreen();
- return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0);
-}
-
QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const
{
QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint();
@@ -430,7 +483,7 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height)
{
// Determine the grab rect. FIXME: The rect should be bounded by the view's
// geometry, but note that for the pixeltool use case that window will be the
- // desktop widgets's view, which currently gets resized to fit one screen
+ // desktop widget's view, which currently gets resized to fit one screen
// only, since its NSWindow has the NSWindowStyleMaskTitled flag set.
Q_UNUSED(view);
QRect grabRect = QRect(x, y, width, height);
@@ -482,7 +535,7 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height)
for (uint i = 0; i < displayCount; ++i)
dpr = qMax(dpr, images.at(i).devicePixelRatio());
- // Alocate target pixmap and draw each screen's content
+ // Allocate target pixmap and draw each screen's content
qCDebug(lcQpaScreen) << "Create grap pixmap" << grabRect.size() << "at devicePixelRatio" << dpr;
QPixmap windowPixmap(grabRect.size() * dpr);
windowPixmap.setDevicePixelRatio(dpr);
@@ -499,7 +552,57 @@ QPixmap QCocoaScreen::grabWindow(WId view, int x, int y, int width, int height)
*/
QCocoaScreen *QCocoaScreen::primaryScreen()
{
- return static_cast<QCocoaScreen *>(QGuiApplication::primaryScreen()->handle());
+ auto screen = static_cast<QCocoaScreen *>(QGuiApplication::primaryScreen()->handle());
+ Q_ASSERT_X(screen == get(CGMainDisplayID()), "QCocoaScreen",
+ "The application's primary screen should always be in sync with the main display");
+ return screen;
+}
+
+QList<QPlatformScreen*> QCocoaScreen::virtualSiblings() const
+{
+ QList<QPlatformScreen*> siblings;
+
+ // Screens on macOS are always part of the same virtual desktop
+ for (QScreen *screen : QGuiApplication::screens())
+ siblings << screen->handle();
+
+ return siblings;
+}
+
+QCocoaScreen *QCocoaScreen::get(NSScreen *nsScreen)
+{
+ return get(nsScreen.qt_displayId);
+}
+
+QCocoaScreen *QCocoaScreen::get(CGDirectDisplayID displayId)
+{
+ for (QScreen *screen : QGuiApplication::screens()) {
+ QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen*>(screen->handle());
+ if (cocoaScreen->m_displayId == displayId)
+ return cocoaScreen;
+ }
+
+ return nullptr;
+}
+
+NSScreen *QCocoaScreen::nativeScreen() const
+{
+ if (!m_displayId)
+ return nil; // The display has been disconnected
+
+ // A single display may have different displayIds depending on
+ // which GPU is in use or which physical port the display is
+ // connected to. By comparing UUIDs instead of display IDs we
+ // ensure that we always pick up the appropriate NSScreen.
+ QCFType<CFUUIDRef> uuid = CGDisplayCreateUUIDFromDisplayID(m_displayId);
+
+ for (NSScreen *screen in [NSScreen screens]) {
+ if (CGDisplayCreateUUIDFromDisplayID(screen.qt_displayId) == uuid)
+ return screen;
+ }
+
+ qCWarning(lcQpaScreen) << "Could not find NSScreen for display ID" << m_displayId;
+ return nil;
}
CGPoint QCocoaScreen::mapToNative(const QPointF &pos, QCocoaScreen *screen)
@@ -533,11 +636,10 @@ QDebug operator<<(QDebug debug, const QCocoaScreen *screen)
debug.nospace();
debug << "QCocoaScreen(" << (const void *)screen;
if (screen) {
- debug << ", index=" << screen->m_screenIndex;
- debug << ", native=" << screen->nativeScreen();
debug << ", geometry=" << screen->geometry();
debug << ", dpr=" << screen->devicePixelRatio();
debug << ", name=" << screen->name();
+ debug << ", native=" << screen->nativeScreen();
}
debug << ')';
return debug;
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index d831612c22..6779bda491 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -42,8 +42,9 @@
#define QCOCOASYSTEMTRAYICON_P_H
#include <QtCore/qglobal.h>
+#include <QtGui/qtguiglobal.h>
-#ifndef QT_NO_SYSTEMTRAYICON
+#if QT_CONFIG(systemtrayicon)
#include "QtCore/qstring.h"
#include "QtGui/qpa/qplatformsystemtrayicon.h"
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index 4982f5ee05..de5cf85854 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -383,9 +383,9 @@ QT_END_NAMESPACE
}
- (QRectF)geometry {
- if (NSWindow *window = [[item view] window]) {
- if (QCocoaScreen *screen = QCocoaIntegration::instance()->screenForNSScreen([window screen]))
- return screen->mapFromNative([window frame]);
+ if (NSWindow *window = item.view.window) {
+ if (QCocoaScreen *screen = QCocoaScreen::get(window.screen))
+ return screen->mapFromNative(window.frame);
}
return QRectF();
}
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 298d11fe08..67b0cbdfe9 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -1086,9 +1086,11 @@ void QCocoaWindow::setEmbeddedInForeignView()
void QCocoaWindow::viewDidChangeFrame()
{
- if (isContentView())
- return; // Handled below
-
+ // Note: When the view is the content view, it would seem redundant
+ // to deliver geometry changes both from windowDidResize and this
+ // callback, but in some cases such as when macOS native tabbed
+ // windows are enabled we may end up with the wrong geometry in
+ // the initial windowDidResize callback when a new tab is created.
handleGeometryChange();
}
@@ -1208,23 +1210,34 @@ void QCocoaWindow::windowDidChangeScreen()
if (!window())
return;
- const bool wasRunningDisplayLink = static_cast<QCocoaScreen *>(screen())->isRunningDisplayLink();
-
- if (QCocoaScreen *newScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen)) {
- if (newScreen == screen()) {
- // Screen properties have changed. Will be handled by
- // NSApplicationDidChangeScreenParametersNotification
- // in QCocoaIntegration::updateScreens().
- return;
- }
-
- qCDebug(lcQpaWindow) << window() << "moved to" << newScreen;
- QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(window(), newScreen->screen());
-
- if (hasPendingUpdateRequest() && wasRunningDisplayLink)
- requestUpdate(); // Restart display-link on new screen
- } else {
- qCWarning(lcQpaWindow) << "Failed to get QCocoaScreen for" << m_view.window.screen;
+ // Note: When a window is resized to 0x0 Cocoa will report the window's screen as nil
+ auto *currentScreen = QCocoaScreen::get(m_view.window.screen);
+ auto *previousScreen = static_cast<QCocoaScreen*>(screen());
+
+ Q_ASSERT_X(!m_view.window.screen || currentScreen,
+ "QCocoaWindow", "Failed to get QCocoaScreen for NSScreen");
+
+ // Note: The previous screen may be the same as the current screen, either because
+ // a) the screen was just reconfigured, which still results in AppKit sending an
+ // NSWindowDidChangeScreenNotification, b) because the previous screen was removed,
+ // and we ended up calling QWindow::setScreen to move the window, which doesn't
+ // actually move the window to the new screen, or c) because we've delivered the
+ // screen change to the top level window, which will make all the child windows
+ // of that window report the new screen when requested via QWindow::screen().
+ // We still need to deliver the screen change in all these cases, as the
+ // device-pixel ratio may have changed, and needs to be delivered to all
+ // windows, both top level and child windows.
+
+ qCDebug(lcQpaWindow) << "Screen changed for" << window() << "from" << previousScreen << "to" << currentScreen;
+ QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(
+ window(), currentScreen ? currentScreen->screen() : nullptr);
+
+ if (currentScreen && hasPendingUpdateRequest()) {
+ // Restart display-link on new screen. We need to do this unconditionally,
+ // since we can't rely on the previousScreen reflecting whether or not the
+ // window actually moved from one screen to another, or just stayed on the
+ // same screen.
+ currentScreen->requestUpdate();
}
}
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm
index ba6cfca219..358a6b49fd 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.mm
+++ b/src/plugins/platforms/cocoa/qmacclipboard.mm
@@ -489,19 +489,16 @@ QMacPasteboard::retrieveData(const QString &format, QVariant::Type) const
QMacInternalPasteboardMime *c = mimes.at(mime);
QString c_flavor = c->flavorFor(format);
if (!c_flavor.isEmpty()) {
- // Handle text/plain a little differently. Try handling Unicode first.
- bool checkForUtf16 = (c_flavor == QLatin1String("com.apple.traditional-mac-plain-text")
- || c_flavor == QLatin1String("public.utf8-plain-text"));
- if (checkForUtf16 || c_flavor == QLatin1String("public.utf16-plain-text")) {
- // Try to get the NSStringPboardType from NSPasteboard, newlines are mapped
- // correctly (as '\n') in this data. The 'public.utf16-plain-text' type
- // usually maps newlines to '\r' instead.
+ // Converting via PasteboardCopyItemFlavorData below will for some UITs result
+ // in newlines mapping to '\r' instead of '\n'. To work around this we shortcut
+ // the conversion via NSPasteboard's NSStringPboardType if possible.
+ if (c_flavor == QLatin1String("com.apple.traditional-mac-plain-text")
+ || c_flavor == QLatin1String("public.utf8-plain-text")
+ || c_flavor == QLatin1String("public.utf16-plain-text")) {
QString str = qt_mac_get_pasteboardString(paste);
if (!str.isEmpty())
return str;
}
- if (checkForUtf16 && hasFlavor(QLatin1String("public.utf16-plain-text")))
- c_flavor = QLatin1String("public.utf16-plain-text");
QVariant ret;
QList<QByteArray> retList;
diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm
index 002cb3279e..37e972dba9 100644
--- a/src/plugins/platforms/cocoa/qnsview_dragging.mm
+++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm
@@ -293,7 +293,26 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation));
+ // Qt starts drag-and-drop on a mouse button press event. Cococa in
+ // this case won't send the matching release event, so we have to
+ // synthesize it here.
m_buttons = currentlyPressedMouseButtons();
+ const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
+
+ NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin;
+ NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil];
+
+ QPoint qtWindowPoint(nsViewPoint.x, nsViewPoint.y);
+ QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
+
+ QWindowSystemInterface::handleMouseEvent(
+ target,
+ mapWindowCoordinates(m_platformWindow->window(), target, qtWindowPoint),
+ qtScreenPoint,
+ m_buttons,
+ Qt::NoButton,
+ QEvent::MouseButtonRelease,
+ modifiers);
qCDebug(lcQpaMouse) << "Drag session" << session << "ended, with" << m_buttons;
}
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
index cb1799b039..d2e6f848a0 100644
--- a/src/plugins/platforms/cocoa/qnsview_drawing.mm
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -154,6 +154,7 @@
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
[super setLayer:layer];
+ layer.delegate = self;
}
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
@@ -188,6 +189,15 @@
- (void)displayLayer:(CALayer *)layer
{
+ if (!NSThread.isMainThread) {
+ // Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads,
+ // which we shouldn't do. This may result in AppKit (wrongly) triggering a display on
+ // the thread where we made the call, so block it here and defer to the main thread.
+ qCWarning(lcQpaDrawing) << "Display non non-main thread! Deferring to main thread";
+ dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
+ return;
+ }
+
Q_ASSERT(layer == self.layer);
if (!m_platformWindow)
diff --git a/src/plugins/platforms/cocoa/qnsview_gestures.mm b/src/plugins/platforms/cocoa/qnsview_gestures.mm
index 61d551ee0e..f6cd3af4da 100644
--- a/src/plugins/platforms/cocoa/qnsview_gestures.mm
+++ b/src/plugins/platforms/cocoa/qnsview_gestures.mm
@@ -70,7 +70,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
if ([self handleGestureAsBeginEnd:event])
return;
- qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaGestures) << "magnifyWithEvent" << [event magnification] << "from device" << Qt::hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -85,7 +85,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
return;
static bool zoomIn = true;
- qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaGestures) << "smartMagnifyWithEvent" << zoomIn << "from device" << Qt::hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -116,7 +116,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
if (!m_platformWindow)
return;
- qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaGestures) << "swipeWithEvent" << [event deltaX] << [event deltaY] << "from device" << Qt::hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
@@ -145,7 +145,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
QPointF windowPoint;
QPointF screenPoint;
[self convertFromScreen:[self screenMousePoint:event] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
- qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaGestures) << "beginGestureWithEvent @" << windowPoint << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleGestureEvent(m_platformWindow->window(), QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), timestamp, Qt::BeginNativeGesture,
windowPoint, screenPoint);
}
@@ -155,7 +155,7 @@ Q_LOGGING_CATEGORY(lcQpaGestures, "qt.qpa.input.gestures")
if (!m_platformWindow)
return;
- qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaGestures) << "endGestureWithEvent" << "from device" << Qt::hex << [event deviceID];
const NSTimeInterval timestamp = [event timestamp];
QPointF windowPoint;
QPointF screenPoint;
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index 0ab09b97d3..4408385aa8 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -147,9 +147,34 @@
ulong timestamp = [theEvent timestamp] * 1000;
- auto eventType = cocoaEvent2QtMouseEvent(theEvent);
- qCInfo(lcQpaMouse) << "Frame-strut" << eventType << "at" << qtWindowPoint << "with" << m_frameStrutButtons << "in" << self.window;
- QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
+ const auto button = cocoaButton2QtButton(theEvent);
+ auto eventType = [&]() {
+ switch (theEvent.type) {
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeOtherMouseDown:
+ return QEvent::NonClientAreaMouseButtonPress;
+
+ case NSEventTypeLeftMouseUp:
+ case NSEventTypeRightMouseUp:
+ case NSEventTypeOtherMouseUp:
+ return QEvent::NonClientAreaMouseButtonRelease;
+
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeOtherMouseDragged:
+ return QEvent::NonClientAreaMouseMove;
+
+ default:
+ break;
+ }
+
+ return QEvent::None;
+ }();
+
+ qCInfo(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_frameStrutButtons << "in" << self.window;
+ QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(),
+ timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons, button, eventType);
}
@end
@@ -477,12 +502,15 @@
// uses the legacy cursorRect API, so the cursor is reset to the arrow
// cursor. See rdar://34183708
- if (self.cursor && self.cursor != NSCursor.currentCursor) {
- qCInfo(lcQpaMouse) << "Updating cursor for" << self << "to" << self.cursor;
+ auto previousCursor = NSCursor.currentCursor;
+
+ if (self.cursor)
[self.cursor set];
- } else {
+ else
[super cursorUpdate:theEvent];
- }
+
+ if (NSCursor.currentCursor != previousCursor)
+ qCInfo(lcQpaMouse) << "Cursor update for" << self << "resulted in new cursor" << NSCursor.currentCursor;
}
- (void)mouseMovedImpl:(NSEvent *)theEvent
diff --git a/src/plugins/platforms/cocoa/qnsview_touch.mm b/src/plugins/platforms/cocoa/qnsview_touch.mm
index e789213f70..9330844aec 100644
--- a/src/plugins/platforms/cocoa/qnsview_touch.mm
+++ b/src/plugins/platforms/cocoa/qnsview_touch.mm
@@ -60,7 +60,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
@@ -71,7 +71,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
@@ -82,7 +82,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
@@ -93,7 +93,7 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
- qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << hex << [event deviceID];
+ qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << Qt::hex << [event deviceID];
QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QTouchDevice::TouchPad, [event deviceID]), points);
}
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 087cb3651f..9502a315d8 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -51,7 +51,9 @@ static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*"));
static QCocoaWindow *toPlatformWindow(NSWindow *window)
{
- return qnsview_cast(window.contentView).platformWindow;
+ if ([window conformsToProtocol:@protocol(QNSWindowProtocol)])
+ return static_cast<QCocoaNSWindow *>(window).platformWindow;
+ return nullptr;
}
@implementation QNSWindowDelegate
diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro
index 9764272632..6e73bd14f9 100644
--- a/src/plugins/platforms/direct2d/direct2d.pro
+++ b/src/plugins/platforms/direct2d/direct2d.pro
@@ -8,8 +8,8 @@ QT += \
qtConfig(accessibility): QT += accessibility_support-private
qtConfig(vulkan): QT += vulkan_support-private
-LIBS += -ldwmapi -lversion -lgdi32
-QMAKE_USE_PRIVATE += dwrite_1 d2d1_1 d3d11_1 dxgi1_2
+LIBS += -ldwmapi -lversion
+QMAKE_USE_PRIVATE += gdi32 dwrite_1 d2d1_1 d3d11_1 dxgi1_2
include(../windows/windows.pri)
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
index 48469b0f8c..c8a1ddf9b9 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
@@ -199,6 +199,10 @@ QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const
QEglFSWindow *w = qt_egl_device_integration()->createWindow(window);
w->create();
+ const auto showWithoutActivating = window->property("_q_showWithoutActivating");
+ if (showWithoutActivating.isValid() && showWithoutActivating.toBool())
+ return w;
+
// Activate only the window for the primary screen to make input work
if (window->type() != Qt::ToolTip && window->screen() == QGuiApplication::primaryScreen())
w->requestActivateWindow();
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index 98e9ee4728..c1d5af47aa 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -167,6 +167,9 @@ void QEglFSWindow::create()
void QEglFSWindow::destroy()
{
+ if (!m_flags.testFlag(Created))
+ return; // already destroyed
+
#ifndef QT_NO_OPENGL
QOpenGLCompositor::instance()->removeWindow(this);
#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 24051c352e..09a10bcc9c 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -157,7 +157,7 @@ gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig)
const auto gbmDevice = static_cast<QEglFSKmsGbmDevice *>(device())->gbmDevice();
EGLint native_format = -1;
EGLBoolean success = eglGetConfigAttrib(display(), eglConfig, EGL_NATIVE_VISUAL_ID, &native_format);
- qCDebug(qLcEglfsKmsDebug) << "Got native format" << hex << native_format << dec << "from eglGetConfigAttrib() with return code" << bool(success);
+ qCDebug(qLcEglfsKmsDebug) << "Got native format" << Qt::hex << native_format << Qt::dec << "from eglGetConfigAttrib() with return code" << bool(success);
if (success)
m_gbm_surface = gbm_surface_create(gbmDevice,
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h
index a19cf7e8bc..ee4b7978f1 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.h
@@ -55,6 +55,9 @@ public:
: QEglFSWindow(w),
m_integration(integration)
{ }
+
+ ~QEglFSKmsGbmWindow() { destroy(); }
+
void resetSurface() override;
void invalidateSurface() override;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
index ef732f9832..2c6b4245b7 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -117,6 +117,8 @@ public:
, m_framePending(false)
{ }
+ ~QEglFSKmsEglDeviceWindow() { destroy(); }
+
void invalidateSurface() override;
void resetSurface() override;
void flip();
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp
index 0d9b6b6290..d1250ec9bf 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qeglfskmsvsp2integration.cpp
@@ -205,6 +205,9 @@ public:
: QEglFSWindow(w)
, m_integration(integration)
{}
+
+ ~QEglFSKmsVsp2Window() { destroy(); }
+
void resetSurface() override;
void invalidateSurface() override;
const QEglFSKmsVsp2Integration *m_integration;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
index 738c30c65a..b8f04cf978 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp
@@ -221,7 +221,7 @@ EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow
QSurfaceFormat QEglFSOpenWFDIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
{
- QSurfaceFormat format;
+ QSurfaceFormat format = inputFormat;
format.setRedBufferSize(8);
format.setGreenBufferSize(8);
format.setBlueBufferSize(8);
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index e5419b1766..0561a826c6 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -834,9 +834,14 @@ static void executeBlockWithoutAnimation(Block block)
- (void)updateSelection
{
if (!hasSelection()) {
- _cursorLayer.visible = NO;
- _anchorLayer.visible = NO;
- QIOSTextInputOverlay::s_editMenu.visible = NO;
+ if (_cursorLayer.visible) {
+ _cursorLayer.visible = NO;
+ _anchorLayer.visible = NO;
+ // Only hide the edit menu if we had a selection from before, since
+ // the edit menu can also be used for other purposes by others (in
+ // which case we try our best not to interfere).
+ QIOSTextInputOverlay::s_editMenu.visible = NO;
+ }
return;
}
diff --git a/src/plugins/platforms/openwfd/qopenwfdscreen.h b/src/plugins/platforms/openwfd/qopenwfdscreen.h
index dede0025a9..dec51d306b 100644
--- a/src/plugins/platforms/openwfd/qopenwfdscreen.h
+++ b/src/plugins/platforms/openwfd/qopenwfdscreen.h
@@ -48,7 +48,6 @@
#include <WF/wfd.h>
#include <QtCore/QVarLengthArray>
-#include <QtCore/QLinkedList>
#define BUFFER_NUM 4
diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro
index 96bfa1dd19..bfd56e8d13 100644
--- a/src/plugins/platforms/qnx/qnx.pro
+++ b/src/plugins/platforms/qnx/qnx.pro
@@ -33,6 +33,7 @@ QT += \
SOURCES = main.cpp \
qqnxbuffer.cpp \
+ qqnxforeignwindow.cpp \
qqnxintegration.cpp \
qqnxscreen.cpp \
qqnxwindow.cpp \
@@ -50,6 +51,7 @@ SOURCES = main.cpp \
HEADERS = main.h \
qqnxbuffer.h \
+ qqnxforeignwindow.h \
qqnxkeytranslator.h \
qqnxintegration.h \
qqnxscreen.h \
diff --git a/src/plugins/platforms/qnx/qqnxforeignwindow.cpp b/src/plugins/platforms/qnx/qqnxforeignwindow.cpp
new file mode 100644
index 0000000000..94608215dc
--- /dev/null
+++ b/src/plugins/platforms/qnx/qqnxforeignwindow.cpp
@@ -0,0 +1,65 @@
+/***************************************************************************
+**
+** Copyright (C) 2018 QNX Software Systems. All rights reserved.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqnxforeignwindow.h"
+#include "qqnxintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+QQnxForeignWindow::QQnxForeignWindow(QWindow *window,
+ screen_context_t context,
+ screen_window_t screenWindow)
+ : QQnxWindow(window, context, screenWindow)
+{
+ initWindow();
+}
+
+bool QQnxForeignWindow::isForeignWindow() const
+{
+ return true;
+}
+
+int QQnxForeignWindow::pixelFormat() const
+{
+ int result = SCREEN_FORMAT_RGBA8888;
+ screen_get_window_property_iv(nativeHandle(), SCREEN_PROPERTY_FORMAT, &result);
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxforeignwindow.h b/src/plugins/platforms/qnx/qqnxforeignwindow.h
new file mode 100644
index 0000000000..22dde643e4
--- /dev/null
+++ b/src/plugins/platforms/qnx/qqnxforeignwindow.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+**
+** Copyright (C) 2018 QNX Software Systems. All rights reserved.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXFOREIGNWINDOW_H
+#define QQNXFOREIGNWINDOW_H
+
+#include "qqnxwindow.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQnxForeignWindow : public QQnxWindow
+{
+public:
+ QQnxForeignWindow(QWindow *window,
+ screen_context_t context,
+ screen_window_t screenWindow);
+
+ bool isForeignWindow() const override;
+ int pixelFormat() const override;
+ void resetBuffers() override {}
+};
+
+QT_END_NAMESPACE
+
+#endif // QQNXFOREIGNWINDOW_H
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index a45dcabeb7..f479e94988 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -51,6 +51,7 @@
#include "qqnxabstractvirtualkeyboard.h"
#include "qqnxservices.h"
+#include "qqnxforeignwindow.h"
#include "qqnxrasterwindow.h"
#if !defined(QT_NO_OPENGL)
#include "qqnxeglwindow.h"
@@ -147,6 +148,7 @@ static inline int getContextCapabilities(const QStringList &paramList)
QQnxIntegration::QQnxIntegration(const QStringList &paramList)
: QPlatformIntegration()
+ , m_screenContextId(256, 0)
, m_screenEventThread(0)
, m_navigatorEventHandler(new QQnxNavigatorEventHandler())
, m_virtualKeyboard(0)
@@ -178,6 +180,11 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
qFatal("%s - Screen: Failed to create screen context - Error: %s (%i)",
Q_FUNC_INFO, strerror(errno), errno);
}
+ screen_get_context_property_cv(m_screenContext,
+ SCREEN_PROPERTY_ID,
+ m_screenContextId.size(),
+ m_screenContextId.data());
+ m_screenContextId.resize(strlen(m_screenContextId.constData()));
#if QT_CONFIG(qqnx_pps)
// Create/start navigator event notifier
@@ -310,6 +317,7 @@ bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
qIntegrationDebug();
switch (cap) {
case MultipleWindows:
+ case ForeignWindows:
case ThreadedPixmaps:
return true;
#if !defined(QT_NO_OPENGL)
@@ -323,6 +331,18 @@ bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
}
}
+QPlatformWindow *QQnxIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ screen_window_t screenWindow = reinterpret_cast<screen_window_t>(nativeHandle);
+ if (this->window(screenWindow)) {
+ qWarning() << "QWindow already created for foreign window"
+ << screenWindow;
+ return nullptr;
+ }
+
+ return new QQnxForeignWindow(window, m_screenContext, screenWindow);
+}
+
QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
{
qIntegrationDebug();
@@ -478,7 +498,7 @@ QPlatformServices * QQnxIntegration::services() const
return m_services;
}
-QWindow *QQnxIntegration::window(screen_window_t qnxWindow)
+QWindow *QQnxIntegration::window(screen_window_t qnxWindow) const
{
qIntegrationDebug();
QMutexLocker locker(&m_windowMapperMutex);
@@ -587,12 +607,11 @@ QList<screen_display_t *> QQnxIntegration::sortDisplays(screen_display_t *availa
// Move all displays with matching ID from the intermediate list
// to the beginning of the ordered list
- QMutableListIterator<screen_display_t *> iter(allDisplays);
- while (iter.hasNext()) {
- screen_display_t *display = iter.next();
+ for (auto it = allDisplays.begin(), end = allDisplays.end(); it != end; ++it) {
+ screen_display_t *display = *it;
if (getIdOfDisplay(*display) == requestedValue) {
orderedDisplays.append(display);
- iter.remove();
+ allDisplays.erase(it);
break;
}
}
@@ -706,6 +725,11 @@ screen_context_t QQnxIntegration::screenContext()
return m_screenContext;
}
+QByteArray QQnxIntegration::screenContextId()
+{
+ return m_screenContextId;
+}
+
QQnxNavigatorEventHandler *QQnxIntegration::navigatorEventHandler()
{
return m_navigatorEventHandler;
diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h
index 366556dc4b..0bf37880d1 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.h
+++ b/src/plugins/platforms/qnx/qqnxintegration.h
@@ -92,6 +92,7 @@ public:
bool hasCapability(QPlatformIntegration::Capability cap) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
@@ -123,7 +124,7 @@ public:
QPlatformServices *services() const override;
- QWindow *window(screen_window_t qnxWindow);
+ QWindow *window(screen_window_t qnxWindow) const;
QQnxScreen *screenForNative(screen_display_t qnxScreen) const;
@@ -132,6 +133,7 @@ public:
QQnxScreen *primaryDisplay() const;
Options options() const;
screen_context_t screenContext();
+ QByteArray screenContextId();
QQnxNavigatorEventHandler *navigatorEventHandler();
@@ -145,6 +147,7 @@ private:
int displayCount);
screen_context_t m_screenContext;
+ QByteArray m_screenContextId;
QQnxScreenEventThread *m_screenEventThread;
QQnxNavigatorEventHandler *m_navigatorEventHandler;
QQnxAbstractVirtualKeyboard *m_virtualKeyboard;
@@ -168,7 +171,7 @@ private:
QSimpleDrag *m_drag;
#endif
QQnxWindowMapper m_windowMapper;
- QMutex m_windowMapperMutex;
+ mutable QMutex m_windowMapperMutex;
Options m_options;
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index c2471751f5..56131dcc48 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -45,6 +45,7 @@
#include "qqnxkeytranslator.h"
#include "qqnxscreen.h"
#include "qqnxscreeneventfilter.h"
+#include "qqnxscreentraits.h"
#include <QDebug>
#include <QGuiApplication>
@@ -89,6 +90,51 @@ static QString capKeyString(int cap, int modifiers, int key)
return QString();
}
+template <typename T>
+static void finishCloseEvent(screen_event_t event)
+{
+ T t;
+ screen_get_event_property_pv(event,
+ screen_traits<T>::propertyName,
+ reinterpret_cast<void**>(&t));
+ screen_traits<T>::destroy(t);
+}
+
+static void finishCloseEvent(screen_event_t event)
+{
+ // Let libscreen know that we're finished with anything that may have been acquired.
+ int objectType = SCREEN_OBJECT_TYPE_CONTEXT;
+ screen_get_event_property_iv(event, SCREEN_PROPERTY_OBJECT_TYPE, &objectType);
+ switch (objectType) {
+ case SCREEN_OBJECT_TYPE_CONTEXT:
+ finishCloseEvent<screen_context_t>(event);
+ break;
+ case SCREEN_OBJECT_TYPE_DEVICE:
+ finishCloseEvent<screen_device_t>(event);
+ break;
+ case SCREEN_OBJECT_TYPE_DISPLAY:
+ // no screen_destroy_display
+ break;
+ case SCREEN_OBJECT_TYPE_GROUP:
+ finishCloseEvent<screen_group_t>(event);
+ break;
+ case SCREEN_OBJECT_TYPE_PIXMAP:
+ finishCloseEvent<screen_pixmap_t>(event);
+ break;
+ case SCREEN_OBJECT_TYPE_SESSION:
+ finishCloseEvent<screen_session_t>(event);
+ break;
+#if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(2, 0, 0)
+ case SCREEN_OBJECT_TYPE_STREAM:
+ finishCloseEvent<screen_stream_t>(event);
+ break;
+#endif
+ case SCREEN_OBJECT_TYPE_WINDOW:
+ finishCloseEvent<screen_window_t>(event);
+ break;
+ }
+}
+
QT_BEGIN_NAMESPACE
QQnxScreenEventHandler::QQnxScreenEventHandler(QQnxIntegration *integration)
@@ -251,6 +297,9 @@ void QQnxScreenEventHandler::processEvents()
bool handled = dispatcher && dispatcher->filterNativeEvent(QByteArrayLiteral("screen_event_t"), event, &result);
if (!handled)
handleEvent(event);
+
+ if (type == SCREEN_EVENT_CLOSE)
+ finishCloseEvent(event);
}
m_eventThread->armEventsPending(count);
diff --git a/src/plugins/platforms/qnx/qqnxscreentraits.h b/src/plugins/platforms/qnx/qqnxscreentraits.h
new file mode 100644
index 0000000000..ebd74141f2
--- /dev/null
+++ b/src/plugins/platforms/qnx/qqnxscreentraits.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+**
+** Copyright (C) 2018 QNX Software Systems. All rights reserved.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQNXSCREENTRAITS_H
+#define QQNXSCREENTRAITS_H
+
+#include <screen/screen.h>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T>
+class screen_traits
+{
+};
+
+template <>
+class screen_traits<screen_context_t>
+{
+public:
+ typedef screen_context_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_CONTEXT;
+ static int destroy(screen_context_t context) { return screen_destroy_context(context); }
+};
+
+template <>
+class screen_traits<screen_device_t>
+{
+public:
+ typedef screen_device_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_DEVICE;
+ static int destroy(screen_device_t device) { return screen_destroy_device(device); }
+};
+
+template <>
+class screen_traits<screen_display_t>
+{
+public:
+ typedef screen_display_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_DISPLAY;
+};
+
+template <>
+class screen_traits<screen_group_t>
+{
+public:
+ typedef screen_group_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_GROUP;
+ static int destroy(screen_group_t group) { return screen_destroy_group(group); }
+};
+
+template <>
+class screen_traits<screen_pixmap_t>
+{
+public:
+ typedef screen_pixmap_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_PIXMAP;
+ static int destroy(screen_pixmap_t pixmap) { return screen_destroy_pixmap(pixmap); }
+};
+
+template <>
+class screen_traits<screen_session_t>
+{
+public:
+ typedef screen_session_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_SESSION;
+ static int destroy(screen_session_t session) { return screen_destroy_session(session); }
+};
+
+#if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(2, 0, 0)
+template <>
+class screen_traits<screen_stream_t>
+{
+public:
+ typedef screen_stream_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_STREAM;
+ static int destroy(screen_stream_t stream) { return screen_destroy_stream(stream); }
+};
+#endif
+
+template <>
+class screen_traits<screen_window_t>
+{
+public:
+ typedef screen_window_t screen_type;
+ static const int propertyName = SCREEN_PROPERTY_WINDOW;
+ static int destroy(screen_window_t window) { return screen_destroy_window(window); }
+};
+
+QT_END_NAMESPACE
+
+#endif // QQNXSCREENTRAITS_H
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index 7644e28b44..1d3d609017 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -155,6 +155,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
m_parentWindow(0),
m_visible(false),
m_exposed(true),
+ m_foreign(false),
m_windowState(Qt::WindowNoState),
m_mmRendererWindow(0),
m_firstActivateHandled(false)
@@ -254,6 +255,39 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
}
}
+QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_t screenWindow)
+ : QPlatformWindow(window)
+ , m_screenContext(context)
+ , m_window(screenWindow)
+ , m_screen(0)
+ , m_parentWindow(0)
+ , m_visible(false)
+ , m_exposed(true)
+ , m_foreign(true)
+ , m_windowState(Qt::WindowNoState)
+ , m_mmRendererWindow(0)
+ , m_parentGroupName(256, 0)
+ , m_isTopLevel(false)
+{
+ qWindowDebug() << "window =" << window << ", size =" << window->size();
+
+ collectWindowGroup();
+
+ screen_get_window_property_cv(m_window,
+ SCREEN_PROPERTY_PARENT,
+ m_parentGroupName.size(),
+ m_parentGroupName.data());
+ m_parentGroupName.resize(strlen(m_parentGroupName.constData()));
+
+ // If a window group has been provided join it now. If it's an empty string that's OK too,
+ // it'll cause us not to join a group (the app will presumably join at some future time).
+ QVariant parentGroup = window->property("qnxInitialWindowGroup");
+ if (!parentGroup.isValid())
+ parentGroup = window->property("_q_platform_qnxParentGroup");
+ if (parentGroup.isValid() && parentGroup.canConvert<QByteArray>())
+ joinWindowGroup(parentGroup.toByteArray());
+}
+
QQnxWindow::~QQnxWindow()
{
qWindowDebug() << "window =" << window();
@@ -270,7 +304,11 @@ QQnxWindow::~QQnxWindow()
m_screen->updateHierarchy();
// Cleanup QNX window and its buffers
- screen_destroy_window(m_window);
+ // Foreign windows are cleaned up externally after the CLOSE event has been handled.
+ if (m_foreign)
+ removeContextPermission();
+ else
+ screen_destroy_window(m_window);
}
void QQnxWindow::setGeometry(const QRect &rect)
@@ -793,14 +831,24 @@ void QQnxWindow::initWindow()
setGeometryHelper(shouldMakeFullScreen() ? screen()->geometry() : window()->geometry());
}
-void QQnxWindow::createWindowGroup()
+void QQnxWindow::collectWindowGroup()
{
- // Generate a random window group name
- m_windowGroupName = QUuid::createUuid().toByteArray();
+ QByteArray groupName(256, 0);
+ Q_SCREEN_CHECKERROR(screen_get_window_property_cv(m_window,
+ SCREEN_PROPERTY_GROUP,
+ groupName.size(),
+ groupName.data()),
+ "Failed to retrieve window group");
+ groupName.resize(strlen(groupName.constData()));
+ m_windowGroupName = groupName;
+}
- // Create window group so child windows can be parented by container window
- Q_SCREEN_CHECKERROR(screen_create_window_group(m_window, m_windowGroupName.constData()),
+void QQnxWindow::createWindowGroup()
+{
+ Q_SCREEN_CHECKERROR(screen_create_window_group(m_window, nullptr),
"Failed to create window group");
+
+ collectWindowGroup();
}
void QQnxWindow::joinWindowGroup(const QByteArray &groupName)
@@ -809,6 +857,17 @@ void QQnxWindow::joinWindowGroup(const QByteArray &groupName)
qWindowDebug() << "group:" << groupName;
+ // screen has this annoying habit of generating a CLOSE/CREATE when the owner context of
+ // the parent group moves a foreign window to another group that it also owns. The
+ // CLOSE/CREATE changes the identity of the foreign window. Usually, this is undesirable.
+ // To prevent this CLOSE/CREATE when changing the parent group, we temporarily add a
+ // context permission for the Qt context. screen won't send a CLOSE/CREATE when the
+ // context has some permission other than the PARENT permission. If there isn't a new
+ // group (the window has no parent), this context permission is left in place.
+
+ if (m_foreign && !m_parentGroupName.isEmpty())\
+ addContextPermission();
+
if (!groupName.isEmpty()) {
if (groupName != m_parentGroupName) {
screen_join_window_group(m_window, groupName);
@@ -827,6 +886,9 @@ void QQnxWindow::joinWindowGroup(const QByteArray &groupName)
m_parentGroupName = "";
}
+ if (m_foreign && !groupName.isEmpty())
+ removeContextPermission();
+
if (changed)
screen_flush_context(m_screenContext, 0);
}
@@ -899,4 +961,26 @@ bool QQnxWindow::focusable() const
return (window()->flags() & Qt::WindowDoesNotAcceptFocus) != Qt::WindowDoesNotAcceptFocus;
}
+void QQnxWindow::addContextPermission()
+{
+ QByteArray grantString("context:");
+ grantString.append(QQnxIntegration::instance()->screenContextId());
+ grantString.append(":rw-");
+ screen_set_window_property_cv(m_window,
+ SCREEN_PROPERTY_PERMISSIONS,
+ grantString.length(),
+ grantString.data());
+}
+
+void QQnxWindow::removeContextPermission()
+{
+ QByteArray revokeString("context:");
+ revokeString.append(QQnxIntegration::instance()->screenContextId());
+ revokeString.append(":---");
+ screen_set_window_property_cv(m_window,
+ SCREEN_PROPERTY_PERMISSIONS,
+ revokeString.length(),
+ revokeString.data());
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index 20c38cb4b7..9040619c41 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -64,7 +64,8 @@ class QQnxWindow : public QPlatformWindow
{
friend class QQnxScreen;
public:
- QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow);
+ explicit QQnxWindow(QWindow *window, screen_context_t context, bool needRootWindow);
+ explicit QQnxWindow(QWindow *window, screen_context_t context, screen_window_t screenWindow);
virtual ~QQnxWindow();
void setGeometry(const QRect &rect) override;
@@ -124,6 +125,7 @@ protected:
screen_context_t m_screenContext;
private:
+ void collectWindowGroup();
void createWindowGroup();
void setGeometryHelper(const QRect &rect);
void removeFromParent();
@@ -135,6 +137,9 @@ private:
bool showWithoutActivating() const;
bool focusable() const;
+ void addContextPermission();
+ void removeContextPermission();
+
screen_window_t m_window;
QSize m_bufferSize;
@@ -144,6 +149,7 @@ private:
QScopedPointer<QQnxAbstractCover> m_cover;
bool m_visible;
bool m_exposed;
+ bool m_foreign;
QRect m_unmaximizedGeometry;
Qt::WindowStates m_windowState;
QString m_mmRendererWindowName;
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
index 2db7723ae2..ef4a6ec2b9 100644
--- a/src/plugins/platforms/wasm/qtloader.js
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -124,6 +124,8 @@
// Remove canvas at run-time. Removes the corresponding QScreen.
// resizeCanvasElement
// Signals to the application that a canvas has been resized.
+// setFontDpi
+// Sets the logical font dpi for the application.
var Module = {}
@@ -237,6 +239,8 @@ function QtLoader(config)
publicAPI.addCanvasElement = addCanvasElement;
publicAPI.removeCanvasElement = removeCanvasElement;
publicAPI.resizeCanvasElement = resizeCanvasElement;
+ publicAPI.setFontDpi = setFontDpi;
+ publicAPI.fontDpi = fontDpi;
restartCount = 0;
@@ -404,7 +408,7 @@ function QtLoader(config)
Module.preRun = Module.preRun || []
Module.preRun.push(function() {
for (var [key, value] of Object.entries(config.environment)) {
- Module.ENV[key.toUpperCase()] = value;
+ ENV[key.toUpperCase()] = value;
}
});
@@ -557,6 +561,16 @@ function QtLoader(config)
Module.qtResizeCanvasElement(element);
}
+ function setFontDpi(dpi) {
+ Module.qtFontDpi = dpi;
+ if (publicAPI.status == "Running")
+ Module.qtSetFontDpi(dpi);
+ }
+
+ function fontDpi() {
+ return Module.qtFontDpi;
+ }
+
setStatus("Created");
return publicAPI;
diff --git a/src/plugins/platforms/wasm/qtlogo.svg b/src/plugins/platforms/wasm/qtlogo.svg
index cb8989bb79..ad7c7776bf 100644
--- a/src/plugins/platforms/wasm/qtlogo.svg
+++ b/src/plugins/platforms/wasm/qtlogo.svg
@@ -5,15 +5,10 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="462pt"
height="339pt"
viewBox="0 0 462 339"
- version="1.1"
- id="svg2"
- inkscape:version="0.91 r13725"
- sodipodi:docname="TheQtCompany_logo_2.svg">
+ version="1.1">
<metadata
id="metadata20">
<rdf:RDF>
@@ -26,28 +21,6 @@
</cc:Work>
</rdf:RDF>
</metadata>
- <defs
- id="defs18" />
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1536"
- inkscape:window-height="801"
- id="namedview16"
- showgrid="false"
- inkscape:zoom="1.1138643"
- inkscape:cx="270.58047"
- inkscape:cy="174.65092"
- inkscape:window-x="-8"
- inkscape:window-y="-8"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg2" />
<path
fill="#41cd52"
d=" M 63.50 0.00 L 462.00 0.00 L 462.00 274.79 C 440.60 296.26 419.13 317.66 397.61 339.00 L 0.00 339.00 L 0.00 63.39 C 21.08 42.18 42.34 21.13 63.50 0.00 Z"
diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
index f4ca49997a..6a02a457a0 100644
--- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp
@@ -568,11 +568,8 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven
switch (eventType) {
case EMSCRIPTEN_EVENT_MOUSEDOWN:
{
- if (window2) {
- window2->raise();
- if (!window2->isActive())
- window2->requestActivate();
- }
+ if (window2)
+ window2->requestActivate();
pressedButtons.setFlag(button);
@@ -776,7 +773,7 @@ int QWasmEventTranslator::handleTouch(int eventType, const EmscriptenTouchEvent
QWindowSystemInterface::handleTouchCancelEvent(window2, getTimestamp(), touchDevice, keyModifier);
QWasmEventDispatcher::maintainTimers();
- return 0;
+ return 1;
}
quint64 QWasmEventTranslator::getTimestamp()
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
index 0c72dfddc4..dc6bb5847e 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
@@ -38,9 +38,9 @@ void QWasmFontDatabase::populateFontDatabase()
// Load font file from resources. Currently
// all fonts needs to be bundled with the nexe
// as Qt resources.
- QStringList fontFileNames = QStringList() << QStringLiteral(":/fonts/Vera.ttf")
+ QStringList fontFileNames = QStringList() << QStringLiteral(":/fonts/DejaVuSansMono.ttf")
+ << QStringLiteral(":/fonts/Vera.ttf")
<< QStringLiteral(":/fonts/DejaVuSans.ttf");
-
foreach (const QString &fontFileName, fontFileNames) {
QFile theFont(fontFileName);
if (!theFont.open(QIODevice::ReadOnly))
@@ -82,5 +82,9 @@ void QWasmFontDatabase::releaseHandle(void *handle)
QFreeTypeFontDatabase::releaseHandle(handle);
}
+QFont QWasmFontDatabase::defaultFont() const
+{
+ return QFont(QLatin1String("Bitstream Vera Sans"));
+}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h
index 891f12859e..cbd187a022 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.h
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h
@@ -44,6 +44,7 @@ public:
QChar::Script script) const override;
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName) override;
void releaseHandle(void *handle) override;
+ QFont defaultFont() const override;
};
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index e601d553f2..31b9104de1 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -48,8 +48,10 @@
#include <QtGui/qscreen.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qcoreapplication.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
#include <emscripten/bind.h>
+#include <emscripten/val.h>
// this is where EGL headers are pulled in, make sure it is last
#include "qwasmscreen.h"
@@ -80,12 +82,18 @@ static void resizeCanvasElement(emscripten::val canvas)
QWasmIntegration::get()->resizeScreen(canvasId);
}
+static void qtUpdateDpi()
+{
+ QWasmIntegration::get()->updateDpi();
+}
+
EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
{
function("qtBrowserBeforeUnload", &browserBeforeUnload);
function("qtAddCanvasElement", &addCanvasElement);
function("qtRemoveCanvasElement", &removeCanvasElement);
function("qtResizeCanvasElement", &resizeCanvasElement);
+ function("qtUpdateDpi", &qtUpdateDpi);
}
QWasmIntegration *QWasmIntegration::s_instance;
@@ -173,6 +181,18 @@ QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLCon
}
#endif
+void QWasmIntegration::initialize()
+{
+ QString icStr = QPlatformInputContextFactory::requested();
+ if (!icStr.isNull())
+ m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
+}
+
+QPlatformInputContext *QWasmIntegration::inputContext() const
+{
+ return m_inputContext.data();
+}
+
QPlatformFontDatabase *QWasmIntegration::fontDatabase() const
{
if (m_fontDb == nullptr)
@@ -245,4 +265,14 @@ void QWasmIntegration::resizeScreen(const QString &canvasId)
m_screens.value(canvasId)->updateQScreenAndCanvasRenderSize();
}
+void QWasmIntegration::updateDpi()
+{
+ emscripten::val dpi = emscripten::val::module_property("qtFontDpi");
+ if (dpi.isUndefined())
+ return;
+ qreal dpiValue = dpi.as<qreal>();
+ for (QWasmScreen *screen : m_screens)
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->screen(), dpiValue, dpiValue);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index 11d8d0f7f5..c04c0eaecc 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -34,6 +34,7 @@
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformscreen.h>
+#include <qpa/qplatforminputcontext.h>
#include <QtCore/qhash.h>
@@ -73,6 +74,9 @@ public:
QPlatformTheme *createPlatformTheme(const QString &name) const override;
QPlatformServices *services() const override;
QPlatformClipboard *clipboard() const override;
+ void initialize() override;
+ QPlatformInputContext *inputContext() const override;
+
QWasmClipboard *getWasmClipboard() { return m_clipboard; }
static QWasmIntegration *get() { return s_instance; }
@@ -81,6 +85,7 @@ public:
void addScreen(const QString &canvasId);
void removeScreen(const QString &canvasId);
void resizeScreen(const QString &canvasId);
+ void updateDpi();
private:
mutable QWasmFontDatabase *m_fontDb;
@@ -89,6 +94,8 @@ private:
QHash<QString, QWasmScreen *> m_screens;
mutable QWasmClipboard *m_clipboard;
+ qreal m_fontDpi = -1;
+ mutable QScopedPointer<QPlatformInputContext> m_inputContext;
static QWasmIntegration *s_instance;
};
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
index ae43e2ebf0..1658f32f9e 100644
--- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
@@ -37,6 +37,14 @@ QWasmOpenGLContext::QWasmOpenGLContext(const QSurfaceFormat &format)
: m_requestedFormat(format)
{
m_requestedFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+
+ // if we set one, we need to set the other as well since in webgl, these are tied together
+ if (format.depthBufferSize() < 0 && format.stencilBufferSize() > 0)
+ m_requestedFormat.setDepthBufferSize(16);
+
+ if (format.stencilBufferSize() < 0 && format.depthBufferSize() > 0)
+ m_requestedFormat.setStencilBufferSize(8);
+
}
QWasmOpenGLContext::~QWasmOpenGLContext()
@@ -91,10 +99,14 @@ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(cons
attributes.majorVersion = 2;
}
+ // WebGL doesn't allow separate attach buffers to STENCIL_ATTACHMENT and DEPTH_ATTACHMENT
+ // we need both or none
+ bool useDepthStencil = (format.depthBufferSize() > 0 || format.stencilBufferSize() > 0);
+
// WebGL offers enable/disable control but not size control for these
attributes.alpha = format.alphaBufferSize() > 0;
- attributes.depth = format.depthBufferSize() > 0;
- attributes.stencil = format.stencilBufferSize() > 0;
+ attributes.depth = useDepthStencil;
+ attributes.stencil = useDepthStencil;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId.toLocal8Bit().constData(), &attributes);
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
index a26cafa900..af50ce7440 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -31,6 +31,7 @@
#include "qwasmwindow.h"
#include "qwasmeventtranslator.h"
#include "qwasmcompositor.h"
+#include "qwasmintegration.h"
#include <emscripten/bind.h>
#include <emscripten/val.h>
@@ -100,6 +101,17 @@ QImage::Format QWasmScreen::format() const
return m_format;
}
+QDpi QWasmScreen::logicalDpi() const
+{
+ emscripten::val dpi = emscripten::val::module_property("qtFontDpi");
+ if (!dpi.isUndefined()) {
+ qreal dpiValue = dpi.as<qreal>();
+ return QDpi(dpiValue, dpiValue);
+ }
+ const qreal defaultDpi = 96;
+ return QDpi(defaultDpi, defaultDpi);
+}
+
qreal QWasmScreen::devicePixelRatio() const
{
// FIXME: The effective device pixel ratio may be different from the
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
index 82d2a83edb..8d0d15f245 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.h
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -63,6 +63,7 @@ public:
QRect geometry() const override;
int depth() const override;
QImage::Format format() const override;
+ QDpi logicalDpi() const override;
qreal devicePixelRatio() const override;
QString name() const override;
QPlatformCursor *cursor() const override;
diff --git a/src/plugins/platforms/wasm/qwasmtheme.cpp b/src/plugins/platforms/wasm/qwasmtheme.cpp
index a7f2db3bd3..978d60d686 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.cpp
+++ b/src/plugins/platforms/wasm/qwasmtheme.cpp
@@ -29,15 +29,22 @@
#include "qwasmtheme.h"
#include <QtCore/qvariant.h>
+#include <QFontDatabase>
QT_BEGIN_NAMESPACE
QWasmTheme::QWasmTheme()
{
+ QFontDatabase fdb;
+ for (auto family : fdb.families())
+ if (fdb.isFixedPitch(family))
+ fixedFont = new QFont(family);
}
QWasmTheme::~QWasmTheme()
{
+ if (fixedFont)
+ delete fixedFont;
}
QVariant QWasmTheme::themeHint(ThemeHint hint) const
@@ -47,4 +54,12 @@ QVariant QWasmTheme::themeHint(ThemeHint hint) const
return QPlatformTheme::themeHint(hint);
}
+const QFont *QWasmTheme::font(Font type) const
+{
+ if (type == QPlatformTheme::FixedFont) {
+ return fixedFont;
+ }
+ return nullptr;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h
index e4cc06e049..7123a1f3d4 100644
--- a/src/plugins/platforms/wasm/qwasmtheme.h
+++ b/src/plugins/platforms/wasm/qwasmtheme.h
@@ -31,6 +31,7 @@
#define QWASMTHEME_H
#include <qpa/qplatformtheme.h>
+#include <QtGui/QFont>
QT_BEGIN_NAMESPACE
@@ -49,6 +50,8 @@ public:
~QWasmTheme();
QVariant themeHint(ThemeHint hint) const override;
+ const QFont *font(Font type) const override;
+ QFont *fixedFont = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro
index 9b98445c68..e8728d9dba 100644
--- a/src/plugins/platforms/wasm/wasm.pro
+++ b/src/plugins/platforms/wasm/wasm.pro
@@ -39,7 +39,8 @@ HEADERS = \
wasmfonts.files = \
../../../3rdparty/wasm/Vera.ttf \
- ../../../3rdparty/wasm/DejaVuSans.ttf
+ ../../../3rdparty/wasm/DejaVuSans.ttf \
+ ../../../3rdparty/wasm/DejaVuSansMono.ttf
wasmfonts.prefix = /fonts
wasmfonts.base = ../../../3rdparty/wasm
RESOURCES += wasmfonts
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
index f7c856d63d..a118c217f3 100644
--- a/src/plugins/platforms/wasm/wasm_shell.html
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>APPNAME</title>
+ <title>@APPNAME@</title>
<style>
html, body { padding: 0; margin : 0; overflow:hidden; height: 100% }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
@@ -18,7 +18,7 @@
<figure style="overflow:visible;" id="qtspinner">
<center style="margin-top:1.5em; line-height:150%">
<img src="qtlogo.svg"; width=320; height=200; style="display:block"> </img>
- <strong>Qt for WebAssembly: APPNAME</strong>
+ <strong>Qt for WebAssembly: @APPNAME@</strong>
<div id="qtstatus"></div>
<noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
</center>
@@ -57,7 +57,7 @@
canvas.style.display = 'block';
},
});
- qtLoader.loadEmscriptenModule("APPNAME");
+ qtLoader.loadEmscriptenModule("@APPNAME@");
}
</script>
<script type="text/javascript" src="qtloader.js"></script>
diff --git a/src/plugins/platforms/windows/.prev_CMakeLists.txt b/src/plugins/platforms/windows/.prev_CMakeLists.txt
new file mode 100644
index 0000000000..b53fed4b46
--- /dev/null
+++ b/src/plugins/platforms/windows/.prev_CMakeLists.txt
@@ -0,0 +1,226 @@
+# Generated from windows.pro.
+
+#####################################################################
+## qwindows Plugin:
+#####################################################################
+
+add_qt_plugin(qwindows
+ TYPE platforms
+ SOURCES
+ main.cpp
+ qtwindowsglobal.h
+ qwin10helpers.cpp qwin10helpers.h
+ qwindowsbackingstore.cpp qwindowsbackingstore.h
+ qwindowscombase.h
+ qwindowscontext.cpp qwindowscontext.h
+ qwindowscursor.cpp qwindowscursor.h
+ qwindowsdialoghelpers.cpp qwindowsdialoghelpers.h
+ qwindowsdropdataobject.cpp qwindowsdropdataobject.h
+ qwindowsgdiintegration.cpp qwindowsgdiintegration.h
+ qwindowsgdinativeinterface.cpp qwindowsgdinativeinterface.h
+ qwindowsinputcontext.cpp qwindowsinputcontext.h
+ qwindowsintegration.cpp qwindowsintegration.h
+ qwindowsinternalmimedata.cpp qwindowsinternalmimedata.h
+ qwindowskeymapper.cpp qwindowskeymapper.h
+ qwindowsmenu.cpp qwindowsmenu.h
+ qwindowsmime.cpp qwindowsmime.h
+ qwindowsmousehandler.cpp qwindowsmousehandler.h
+ qwindowsnativeinterface.cpp qwindowsnativeinterface.h
+ qwindowsole.cpp qwindowsole.h
+ qwindowsopengltester.cpp qwindowsopengltester.h
+ qwindowspointerhandler.cpp qwindowspointerhandler.h
+ qwindowsscreen.cpp qwindowsscreen.h
+ qwindowsservices.cpp qwindowsservices.h
+ qwindowstheme.cpp qwindowstheme.h
+ qwindowsthreadpoolrunner.h
+ qwindowswindow.cpp qwindowswindow.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_FOREACH
+ INCLUDE_DIRECTORIES
+ .
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::EventDispatcherSupportPrivate
+ Qt::FontDatabaseSupportPrivate
+ Qt::GuiPrivate
+ Qt::ThemeSupportPrivate
+ advapi32
+ d3d9
+ gdi32
+ ole32
+ shell32
+ user32
+ winmm
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::EventDispatcherSupport
+ Qt::FontDatabaseSupport
+ Qt::Gui
+ Qt::ThemeSupport
+ dwmapi
+ imm32
+ oleaut32
+ shlwapi
+ winspool
+ wtsapi32
+)
+
+# Resources:
+set_source_files_properties("openglblacklists/default.json"
+ PROPERTIES alias "default.json")
+add_qt_resource(qwindows "openglblacklists" PREFIX "/qt-project.org/windows/openglblacklists" FILES
+ openglblacklists/default.json)
+
+
+#### Keys ignored in scope 1:.:.:windows.pro:<TRUE>:
+# OTHER_FILES = "windows.json"
+# PLUGIN_CLASS_NAME = "QWindowsIntegrationPlugin"
+# _LOADED = "qt_plugin"
+
+## Scopes:
+#####################################################################
+
+extend_target(qwindows CONDITION QT_FEATURE_accessibility
+ SOURCES
+ uiautomation/qwindowsuiaaccessibility.cpp uiautomation/qwindowsuiaaccessibility.h
+ uiautomation/qwindowsuiabaseprovider.cpp uiautomation/qwindowsuiabaseprovider.h
+ uiautomation/qwindowsuiagriditemprovider.cpp uiautomation/qwindowsuiagriditemprovider.h
+ uiautomation/qwindowsuiagridprovider.cpp uiautomation/qwindowsuiagridprovider.h
+ uiautomation/qwindowsuiainvokeprovider.cpp uiautomation/qwindowsuiainvokeprovider.h
+ uiautomation/qwindowsuiamainprovider.cpp uiautomation/qwindowsuiamainprovider.h
+ uiautomation/qwindowsuiaprovidercache.cpp uiautomation/qwindowsuiaprovidercache.h
+ uiautomation/qwindowsuiarangevalueprovider.cpp uiautomation/qwindowsuiarangevalueprovider.h
+ uiautomation/qwindowsuiaselectionitemprovider.cpp uiautomation/qwindowsuiaselectionitemprovider.h
+ uiautomation/qwindowsuiaselectionprovider.cpp uiautomation/qwindowsuiaselectionprovider.h
+ uiautomation/qwindowsuiatableitemprovider.cpp uiautomation/qwindowsuiatableitemprovider.h
+ uiautomation/qwindowsuiatableprovider.cpp uiautomation/qwindowsuiatableprovider.h
+ uiautomation/qwindowsuiatextprovider.cpp uiautomation/qwindowsuiatextprovider.h
+ uiautomation/qwindowsuiatextrangeprovider.cpp uiautomation/qwindowsuiatextrangeprovider.h
+ uiautomation/qwindowsuiatoggleprovider.cpp uiautomation/qwindowsuiatoggleprovider.h
+ uiautomation/qwindowsuiautils.cpp uiautomation/qwindowsuiautils.h
+ uiautomation/qwindowsuiavalueprovider.cpp uiautomation/qwindowsuiavalueprovider.h
+ uiautomation/qwindowsuiawindowprovider.cpp uiautomation/qwindowsuiawindowprovider.h
+ LIBRARIES
+ Qt::AccessibilitySupportPrivate
+ PUBLIC_LIBRARIES
+ Qt::AccessibilitySupport
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_vulkan
+ SOURCES
+ qwindowsvulkaninstance.cpp qwindowsvulkaninstance.h
+ LIBRARIES
+ Qt::VulkanSupportPrivate
+ PUBLIC_LIBRARIES
+ Qt::VulkanSupport
+)
+
+#### Keys ignored in scope 4:.:.:windows.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
+# PLUGIN_EXTENDS = "-"
+
+extend_target(qwindows CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_dynamicgl AND NOT QT_FEATURE_opengles2
+ PUBLIC_LIBRARIES
+ opengl32
+)
+
+extend_target(qwindows CONDITION mingw
+ PUBLIC_LIBRARIES
+ uuid
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_opengl
+ SOURCES
+ qwindowsopenglcontext.h
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_opengles2
+ SOURCES
+ qwindowseglcontext.cpp qwindowseglcontext.h
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_opengles2
+ SOURCES
+ qwindowsglcontext.cpp qwindowsglcontext.h
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_dynamicgl
+ SOURCES
+ qwindowseglcontext.cpp qwindowseglcontext.h
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_systemtrayicon
+ SOURCES
+ qwindowssystemtrayicon.cpp qwindowssystemtrayicon.h
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_clipboard
+ SOURCES
+ qwindowsclipboard.cpp qwindowsclipboard.h
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_clipboard AND QT_FEATURE_draganddrop
+ SOURCES
+ qwindowsdrag.cpp qwindowsdrag.h
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_tabletevent
+ SOURCES
+ qwindowstabletsupport.cpp qwindowstabletsupport.h
+ INCLUDE_DIRECTORIES
+ ${PROJECT_SOURCE_DIR}/src/3rdparty/wintab
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_sessionmanager
+ SOURCES
+ qwindowssessionmanager.cpp qwindowssessionmanager.h
+)
+
+# Resources:
+add_qt_resource(qwindows "cursors" PREFIX "/qt-project.org/windows/cursors" FILES
+ images/closedhandcursor_32.png
+ images/closedhandcursor_48.png
+ images/closedhandcursor_64.png
+ images/dragcopycursor_32.png
+ images/dragcopycursor_48.png
+ images/dragcopycursor_64.png
+ images/draglinkcursor_32.png
+ images/draglinkcursor_48.png
+ images/draglinkcursor_64.png
+ images/dragmovecursor_32.png
+ images/dragmovecursor_48.png
+ images/dragmovecursor_64.png
+ images/openhandcursor_32.png
+ images/openhandcursor_48.png
+ images/openhandcursor_64.png
+ images/splithcursor_32.png
+ images/splithcursor_48.png
+ images/splithcursor_64.png
+ images/splitvcursor_32.png
+ images/splitvcursor_48.png
+ images/splitvcursor_64.png)
+
+
+extend_target(qwindows CONDITION (QT_FEATURE_accessibility) AND (TARGET Qt::WindowsUIAutomationSupportPrivate)
+ LIBRARIES
+ Qt::WindowsUIAutomationSupportPrivate
+ PUBLIC_LIBRARIES
+ Qt::WindowsUIAutomationSupport
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_accessibility AND mingw
+ PUBLIC_LIBRARIES
+ uuid
+)
+
+extend_target(qwindows CONDITION QT_FEATURE_combined_angle_lib
+ DEFINES
+ LIBEGL_NAME=
+ LIBGLESV2_NAME=
+)
+
+extend_target(qwindows CONDITION NOT QT_FEATURE_combined_angle_lib
+ DEFINES
+ LIBEGL_NAME=
+ LIBGLESV2_NAME=
+)
diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt
index c665d75af7..8b7ba7e9be 100644
--- a/src/plugins/platforms/windows/CMakeLists.txt
+++ b/src/plugins/platforms/windows/CMakeLists.txt
@@ -37,6 +37,8 @@ add_qt_plugin(qwindows
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_FOREACH
+ INCLUDE_DIRECTORIES
+ .
LIBRARIES
Qt::CorePrivate
Qt::EventDispatcherSupportPrivate
@@ -44,15 +46,22 @@ add_qt_plugin(qwindows
Qt::GuiPrivate
Qt::ThemeSupportPrivate
advapi32
- dwmapi
+ d3d9
gdi32
- imm32
ole32
- oleaut32
shell32
- shlwapi
user32
winmm
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::EventDispatcherSupport
+ Qt::FontDatabaseSupport
+ Qt::Gui
+ Qt::ThemeSupport
+ dwmapi
+ imm32
+ oleaut32
+ shlwapi
winspool
wtsapi32
)
@@ -64,10 +73,9 @@ add_qt_resource(qwindows "openglblacklists" PREFIX "/qt-project.org/windows/open
openglblacklists/default.json)
-#### Keys ignored in scope 1:.:windows.pro:<NONE>:
+#### Keys ignored in scope 1:.:.:windows.pro:<TRUE>:
# OTHER_FILES = "windows.json"
# PLUGIN_CLASS_NAME = "QWindowsIntegrationPlugin"
-# QT_FOR_CONFIG = "gui"
# _LOADED = "qt_plugin"
## Scopes:
@@ -92,8 +100,11 @@ extend_target(qwindows CONDITION QT_FEATURE_accessibility
uiautomation/qwindowsuiatoggleprovider.cpp uiautomation/qwindowsuiatoggleprovider.h
uiautomation/qwindowsuiautils.cpp uiautomation/qwindowsuiautils.h
uiautomation/qwindowsuiavalueprovider.cpp uiautomation/qwindowsuiavalueprovider.h
+ uiautomation/qwindowsuiawindowprovider.cpp uiautomation/qwindowsuiawindowprovider.h
LIBRARIES
Qt::AccessibilitySupportPrivate
+ PUBLIC_LIBRARIES
+ Qt::AccessibilitySupport
)
extend_target(qwindows CONDITION QT_FEATURE_vulkan
@@ -101,18 +112,20 @@ extend_target(qwindows CONDITION QT_FEATURE_vulkan
qwindowsvulkaninstance.cpp qwindowsvulkaninstance.h
LIBRARIES
Qt::VulkanSupportPrivate
+ PUBLIC_LIBRARIES
+ Qt::VulkanSupport
)
-#### Keys ignored in scope 4:.:windows.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
+#### Keys ignored in scope 4:.:.:windows.pro:NOT TARGET___equals____ss_QT_DEFAULT_QPA_PLUGIN:
# PLUGIN_EXTENDS = "-"
extend_target(qwindows CONDITION QT_FEATURE_opengl AND NOT QT_FEATURE_dynamicgl AND NOT QT_FEATURE_opengles2
- LIBRARIES
+ PUBLIC_LIBRARIES
opengl32
)
extend_target(qwindows CONDITION mingw
- LIBRARIES
+ PUBLIC_LIBRARIES
uuid
)
@@ -188,13 +201,15 @@ add_qt_resource(qwindows "cursors" PREFIX "/qt-project.org/windows/cursors" FILE
images/splitvcursor_64.png)
-extend_target(qwindows CONDITION (QT_FEATURE_accessibility) AND (TARGET WindowsUIAutomationSupportPrivate)
+extend_target(qwindows CONDITION (QT_FEATURE_accessibility) AND (TARGET Qt::WindowsUIAutomationSupportPrivate)
LIBRARIES
Qt::WindowsUIAutomationSupportPrivate
+ PUBLIC_LIBRARIES
+ Qt::WindowsUIAutomationSupport
)
extend_target(qwindows CONDITION QT_FEATURE_accessibility AND mingw
- LIBRARIES
+ PUBLIC_LIBRARIES
uuid
)
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index e14a0c1984..e36a285aa2 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -210,6 +210,7 @@ void QWindowsUser32DLL::init()
if (QOperatingSystemVersion::current()
>= QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393)) {
+ adjustWindowRectExForDpi = (AdjustWindowRectExForDpi)library.resolve("AdjustWindowRectExForDpi");
enableNonClientDpiScaling = (EnableNonClientDpiScaling)library.resolve("EnableNonClientDpiScaling");
getWindowDpiAwarenessContext = (GetWindowDpiAwarenessContext)library.resolve("GetWindowDpiAwarenessContext");
getAwarenessFromDpiAwarenessContext = (GetAwarenessFromDpiAwarenessContext)library.resolve("GetAwarenessFromDpiAwarenessContext");
@@ -590,7 +591,7 @@ QString QWindowsContext::registerWindowClass(QString cname,
d->m_registeredWindowClassNames.insert(cname);
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << cname
- << " style=0x" << hex << style << dec
+ << " style=0x" << Qt::hex << style << Qt::dec
<< " brush=" << brush << " icon=" << icon << " atom=" << atom;
return cname;
}
@@ -712,7 +713,7 @@ static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned c
HWND *hwnd, QWindowsWindow **result)
{
POINT point = screenPoint;
- ScreenToClient(*hwnd, &point);
+ screenToClient(*hwnd, &point);
// Returns parent if inside & none matched.
const HWND child = ChildWindowFromPointEx(*hwnd, point, cwexFlags);
if (!child || child == *hwnd)
@@ -977,7 +978,7 @@ static inline bool resizeOnDpiChanged(const QWindow *w)
return result;
}
-static bool shouldHaveNonClientDpiScaling(const QWindow *window)
+bool QWindowsContext::shouldHaveNonClientDpiScaling(const QWindow *window)
{
return QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10
&& window->isTopLevel()
@@ -1042,7 +1043,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
// For non-client-area messages, these are screen coordinates (as expected
// in the MSG structure), otherwise they are client coordinates.
if (!(et & QtWindows::NonClientEventFlag)) {
- ClientToScreen(msg.hwnd, &msg.pt);
+ clientToScreen(msg.hwnd, &msg.pt);
}
} else {
GetCursorPos(&msg.pt);
@@ -1133,13 +1134,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::QuerySizeHints:
d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
return true;
- case QtWindows::ResizeEvent: {
- const QSize size(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) - d->m_creationContext->menuHeight);
- d->m_creationContext->obtainedGeometry.setSize(size);
- }
+ case QtWindows::ResizeEvent:
+ d->m_creationContext->obtainedSize = QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return true;
case QtWindows::MoveEvent:
- d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ d->m_creationContext->obtainedPos = QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return true;
case QtWindows::NonClientCreate:
if (shouldHaveNonClientDpiScaling(d->m_creationContext->window))
@@ -1321,15 +1320,24 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
#endif
} break;
case QtWindows::DpiChangedEvent: {
- if (!resizeOnDpiChanged(platformWindow->window()))
- return false;
- platformWindow->setFlag(QWindowsWindow::WithinDpiChanged);
- const RECT *prcNewWindow = reinterpret_cast<RECT *>(lParam);
- SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
- prcNewWindow->right - prcNewWindow->left,
- prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
- platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged);
- return true;
+ // Try to apply the suggested size first and then notify ScreenChanged
+ // so that the resize event sent from QGuiApplication incorporates it
+ // WM_DPICHANGED is sent with a size that avoids resize loops (by
+ // snapping back to the previous screen, see QTBUG-65580).
+ const bool doResize = resizeOnDpiChanged(platformWindow->window());
+ if (doResize) {
+ platformWindow->setFlag(QWindowsWindow::WithinDpiChanged);
+ platformWindow->updateFullFrameMargins();
+ const auto prcNewWindow = reinterpret_cast<RECT *>(lParam);
+ qCDebug(lcQpaWindows) << __FUNCTION__ << "WM_DPICHANGED"
+ << platformWindow->window() << *prcNewWindow;
+ SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
+ prcNewWindow->right - prcNewWindow->left,
+ prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ platformWindow->clearFlag(QWindowsWindow::WithinDpiChanged);
+ }
+ platformWindow->checkForScreenChanged(QWindowsWindow::FromDpiChange);
+ return doResize;
}
#if QT_CONFIG(sessionmanager)
case QtWindows::QueryEndSessionApplicationEvent: {
@@ -1478,6 +1486,10 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
keyboardModifiers);
}
}
+ if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
+ d->m_pointerHandler.clearEvents();
+ else
+ d->m_mouseHandler.clearEvents();
}
bool QWindowsContext::asyncExpose() const
@@ -1570,7 +1582,7 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR
if (QWindowsContext::verbose > 1 && lcQpaEvents().isDebugEnabled()) {
if (const char *eventName = QWindowsGuiEventDispatcher::windowsMessageName(message)) {
qCDebug(lcQpaEvents).nospace() << "EVENT: hwd=" << hwnd << ' ' << eventName
- << " msg=0x" << hex << message << " et=0x" << et << dec << " wp="
+ << " msg=0x" << Qt::hex << message << " et=0x" << et << Qt::dec << " wp="
<< int(wParam) << " at " << GET_X_LPARAM(lParam) << ','
<< GET_Y_LPARAM(lParam) << " handled=" << handled;
}
@@ -1587,6 +1599,7 @@ extern "C" LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND hwnd, UINT message, WPAR
marginsFromRects(ncCalcSizeFrame, rectFromNcCalcSize(message, wParam, lParam, 0));
if (margins.left() >= 0) {
if (platformWindow) {
+ qCDebug(lcQpaWindows) << __FUNCTION__ << "WM_NCCALCSIZE for" << hwnd << margins;
platformWindow->setFullFrameMargins(margins);
} else {
const QSharedPointer<QWindowCreationContext> ctx = QWindowsContext::instance()->windowCreationContext();
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index fd6c72668c..4908f14629 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -102,6 +102,7 @@ struct QWindowsUser32DLL
typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND);
typedef BOOL (WINAPI *GetDisplayAutoRotationPreferences)(DWORD *);
typedef BOOL (WINAPI *SetDisplayAutoRotationPreferences)(DWORD);
+ typedef BOOL (WINAPI *AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
typedef BOOL (WINAPI *EnableNonClientDpiScaling)(HWND);
typedef int (WINAPI *GetWindowDpiAwarenessContext)(HWND);
typedef int (WINAPI *GetAwarenessFromDpiAwarenessContext)(int);
@@ -131,6 +132,7 @@ struct QWindowsUser32DLL
GetDisplayAutoRotationPreferences getDisplayAutoRotationPreferences = nullptr;
SetDisplayAutoRotationPreferences setDisplayAutoRotationPreferences = nullptr;
+ AdjustWindowRectExForDpi adjustWindowRectExForDpi = nullptr;
EnableNonClientDpiScaling enableNonClientDpiScaling = nullptr;
GetWindowDpiAwarenessContext getWindowDpiAwarenessContext = nullptr;
GetAwarenessFromDpiAwarenessContext getAwarenessFromDpiAwarenessContext = nullptr;
@@ -201,6 +203,8 @@ public:
QWindowsWindow *findPlatformWindowAt(HWND parent, const QPoint &screenPoint,
unsigned cwex_flags) const;
+ static bool shouldHaveNonClientDpiScaling(const QWindow *window);
+
QWindow *windowUnderMouse() const;
void clearWindowUnderMouse();
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 00d011ccec..20a8117304 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -184,9 +184,11 @@ static HCURSOR createBitmapCursor(const QCursor &cursor, qreal scaleFactor = 1)
return createBitmapCursor(bbits, mbits, cursor.hotSpot(), invb, invm);
}
-static QSize systemCursorSize(const QPlatformScreen *screen = nullptr)
+static QSize systemCursorSize() { return QSize(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)); }
+
+static QSize screenCursorSize(const QPlatformScreen *screen = nullptr)
{
- const QSize primaryScreenCursorSize(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR));
+ const QSize primaryScreenCursorSize = systemCursorSize();
if (screen) {
// Correct the size if the DPI value of the screen differs from
// that of the primary screen.
@@ -212,7 +214,7 @@ static inline QSize standardCursorSize() { return QSize(32, 32); }
// createBitmapCursor() only work for standard sizes (32,48,64...), which does
// not work when scaling the 16x16 openhand cursor bitmaps to 150% (resulting
// in a non-standard 24x24 size).
-static QWindowsCursor::PixmapCursor createPixmapCursorFromData(const QSize &systemCursorSize,
+static QWindowsCursor::PixmapCursor createPixmapCursorFromData(const QSize &screenCursorSize,
// The cursor size the bitmap is targeted for
const QSize &bitmapTargetCursorSize,
// The actual size of the bitmap data
@@ -222,7 +224,7 @@ static QWindowsCursor::PixmapCursor createPixmapCursorFromData(const QSize &syst
QPixmap rawImage = QPixmap::fromImage(QBitmap::fromData(QSize(bitmapSize, bitmapSize), bits).toImage());
rawImage.setMask(QBitmap::fromData(QSize(bitmapSize, bitmapSize), maskBits));
- const qreal factor = qreal(systemCursorSize.width()) / qreal(bitmapTargetCursorSize.width());
+ const qreal factor = qreal(screenCursorSize.width()) / qreal(bitmapTargetCursorSize.width());
// Scale images if the cursor size is significantly different, starting with 150% where the system cursor
// size is 48.
if (qAbs(factor - 1.0) > 0.4) {
@@ -402,13 +404,13 @@ QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursor
switch (cursorShape) {
case Qt::SplitVCursor:
- return createPixmapCursorFromData(systemCursorSize(screen), standardCursorSize(), 32, vsplit_bits, vsplitm_bits);
+ return createPixmapCursorFromData(screenCursorSize(screen), standardCursorSize(), 32, vsplit_bits, vsplitm_bits);
case Qt::SplitHCursor:
- return createPixmapCursorFromData(systemCursorSize(screen), standardCursorSize(), 32, hsplit_bits, hsplitm_bits);
+ return createPixmapCursorFromData(screenCursorSize(screen), standardCursorSize(), 32, hsplit_bits, hsplitm_bits);
case Qt::OpenHandCursor:
- return createPixmapCursorFromData(systemCursorSize(screen), standardCursorSize(), 16, openhand_bits, openhandm_bits);
+ return createPixmapCursorFromData(screenCursorSize(screen), standardCursorSize(), 16, openhand_bits, openhandm_bits);
case Qt::ClosedHandCursor:
- return createPixmapCursorFromData(systemCursorSize(screen), standardCursorSize(), 16, closedhand_bits, closedhandm_bits);
+ return createPixmapCursorFromData(screenCursorSize(screen), standardCursorSize(), 16, closedhand_bits, closedhandm_bits);
case Qt::DragCopyCursor:
return QWindowsCursor::PixmapCursor(QPixmap(copyDragCursorXpmC), QPoint(0, 0));
case Qt::DragMoveCursor:
@@ -454,7 +456,7 @@ QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursor
{ Qt::DragLinkCursor, 64, "draglinkcursor_64.png", 0, 0 }
};
- const QSize cursorSize = systemCursorSize(screen);
+ const QSize cursorSize = screenCursorSize(screen);
const QWindowsCustomPngCursor *sEnd = pngCursors + sizeof(pngCursors) / sizeof(pngCursors[0]);
const QWindowsCustomPngCursor *bestFit = nullptr;
int sizeDelta = INT_MAX;
@@ -507,7 +509,7 @@ HCURSOR QWindowsCursor::createCursorFromShape(Qt::CursorShape cursorShape, const
switch (cursorShape) {
case Qt::BlankCursor: {
- QImage blank = QImage(systemCursorSize(screen), QImage::Format_Mono);
+ QImage blank = QImage(systemCursorSize(), QImage::Format_Mono);
blank.fill(0); // ignore color table
return createBitmapCursor(blank, blank);
}
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 9de3268fc8..e0bd38c951 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -736,7 +736,7 @@ QString QWindowsShellItem::libraryItemDefaultSaveFolder(IShellItem *item)
#ifndef QT_NO_DEBUG_STREAM
void QWindowsShellItem::format(QDebug &d) const
{
- d << "attributes=0x" << hex << attributes() << dec;
+ d << "attributes=0x" << Qt::hex << attributes() << Qt::dec;
if (isFileSystem())
d << " [filesys]";
if (isDir())
@@ -972,7 +972,7 @@ void QWindowsNativeFileDialogBase::doExec(HWND owner)
// gets a WM_CLOSE or the parent window is destroyed.
const HRESULT hr = m_fileDialog->Show(owner);
QWindowsDialogs::eatMouseMove();
- qCDebug(lcQpaDialogs) << '<' << __FUNCTION__ << " returns " << hex << hr;
+ qCDebug(lcQpaDialogs) << '<' << __FUNCTION__ << " returns " << Qt::hex << hr;
// Emit accepted() only if there is a result as otherwise UI hangs occur.
// For example, typing in invalid URLs results in empty result lists.
if (hr == S_OK && !m_data.selectedFiles().isEmpty()) {
@@ -1013,7 +1013,7 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode,
}
qCDebug(lcQpaDialogs) << __FUNCTION__ << "mode=" << mode
<< "acceptMode=" << acceptMode << "options=" << options
- << "results in" << showbase << hex << flags;
+ << "results in" << Qt::showbase << Qt::hex << flags;
if (FAILED(m_fileDialog->SetOptions(flags)))
qErrnoWarning("%s: SetOptions() failed", __FUNCTION__);
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 322865b0f3..502c92ef59 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -428,7 +428,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
if (QWindowsContext::verbose > 1 || result != S_OK) {
qCDebug(lcQpaMime) << __FUNCTION__ << "fEscapePressed=" << fEscapePressed
<< "grfKeyState=" << grfKeyState << "buttons" << m_currentButtons
- << "returns 0x" << hex << int(result) << dec;
+ << "returns 0x" << Qt::hex << int(result) << Qt::dec;
}
return ResultFromScode(result);
}
@@ -710,7 +710,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
const Qt::DropActions possibleActions = drag->supportedActions();
const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x"
- << hex << int(possibleActions) << "effects=0x" << allowedEffects << dec;
+ << Qt::hex << int(possibleActions) << "effects=0x" << allowedEffects << Qt::dec;
// Indicate message handlers we are in DoDragDrop() event loop.
QWindowsDrag::m_dragging = true;
const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
@@ -734,9 +734,9 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
dropDataObject->releaseQt();
dropDataObject->Release(); // Will delete obj if refcount becomes 0
windowDropSource->Release(); // Will delete src if refcount becomes 0
- qCDebug(lcQpaMime) << '<' << __FUNCTION__ << hex << "allowedEffects=0x" << allowedEffects
+ qCDebug(lcQpaMime) << '<' << __FUNCTION__ << Qt::hex << "allowedEffects=0x" << allowedEffects
<< "reportedPerformedEffect=0x" << reportedPerformedEffect
- << " resultEffect=0x" << resultEffect << "hr=0x" << int(r) << dec << "dropAction=" << dragResult;
+ << " resultEffect=0x" << resultEffect << "hr=0x" << int(r) << Qt::dec << "dropAction=" << dragResult;
return dragResult;
}
diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
index 229ff92894..e1a41c0ede 100644
--- a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
@@ -41,6 +41,7 @@
#include <QtCore/qurl.h>
#include <QtCore/qmimedata.h>
+#include "qwindowsmime.h"
QT_BEGIN_NAMESPACE
@@ -48,8 +49,9 @@ QT_BEGIN_NAMESPACE
\class QWindowsDropDataObject
\brief QWindowsOleDataObject subclass specialized for handling Drag&Drop.
- Only allows "text/uri-list" data to be exported as CF_HDROP, to allow dropped
- files to be attached to Office applications (instead of adding an URL link).
+ Prevents "text/uri-list" data for local files from being exported as text
+ or URLs, to allow dropped files to be attached to Office applications
+ (instead of creating local hyperlinks).
\internal
\ingroup qt-lighthouse-win
@@ -80,14 +82,22 @@ QWindowsDropDataObject::QueryGetData(LPFORMATETC pformatetc)
return QWindowsOleDataObject::QueryGetData(pformatetc);
}
-// If the data is text/uri-list for local files, tell we can only export it as CF_HDROP.
+// If the data is "text/uri-list" only, and all URIs are for local files,
+// we prevent it from being exported as text or URLs, to make target applications
+// like MS Office attach or open the files instead of creating local hyperlinks.
bool QWindowsDropDataObject::shouldIgnore(LPFORMATETC pformatetc) const
{
QMimeData *dropData = mimeData();
- if (dropData && dropData->hasFormat(QStringLiteral("text/uri-list")) && (pformatetc->cfFormat != CF_HDROP)) {
- QList<QUrl> urls = dropData->urls();
- return std::any_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); });
+ if (dropData && dropData->formats().size() == 1 && dropData->hasUrls()) {
+ QString formatName = QWindowsMimeConverter::clipboardFormatName(pformatetc->cfFormat);
+ if (pformatetc->cfFormat == CF_UNICODETEXT
+ || pformatetc->cfFormat == CF_TEXT
+ || formatName == QStringLiteral("UniformResourceLocator")
+ || formatName == QStringLiteral("UniformResourceLocatorW")) {
+ QList<QUrl> urls = dropData->urls();
+ return std::all_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); });
+ }
}
return false;
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index e95eaef420..d534ce87cd 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -243,7 +243,7 @@ QDebug operator<<(QDebug d, const PIXELFORMATDESCRIPTOR &pd)
QDebugStateSaver saver(d);
d.nospace();
d << "PIXELFORMATDESCRIPTOR "
- << "dwFlags=" << hex << showbase << pd.dwFlags << dec << noshowbase;
+ << "dwFlags=" << Qt::hex << Qt::showbase << pd.dwFlags << Qt::dec << Qt::noshowbase;
if (pd.dwFlags & PFD_DRAW_TO_WINDOW) d << " PFD_DRAW_TO_WINDOW";
if (pd.dwFlags & PFD_DRAW_TO_BITMAP) d << " PFD_DRAW_TO_BITMAP";
if (pd.dwFlags & PFD_SUPPORT_GDI) d << " PFD_SUPPORT_GDI";
@@ -631,10 +631,10 @@ static int choosePixelFormat(HDC hdc,
nsp << __FUNCTION__;
if (sampleBuffersRequested)
nsp << " samples=" << iAttributes[samplesValuePosition];
- nsp << " Attributes: " << hex << showbase;
+ nsp << " Attributes: " << Qt::hex << Qt::showbase;
for (int ii = 0; ii < i; ++ii)
nsp << iAttributes[ii] << ',';
- nsp << noshowbase << dec << "\n obtained px #" << pixelFormat
+ nsp << Qt::noshowbase << Qt::dec << "\n obtained px #" << pixelFormat
<< " of " << numFormats << "\n " << *obtainedPfd;
qCDebug(lcQpaGl) << message;
} // Debug
@@ -784,7 +784,7 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext,
if (!result) {
QString message;
QDebug(&message).nospace() << __FUNCTION__ << ": wglCreateContextAttribsARB() failed (GL error code: 0x"
- << hex << staticContext.opengl32.glGetError() << dec << ") for format: " << format << ", shared context: " << shared;
+ << Qt::hex << staticContext.opengl32.glGetError() << Qt::dec << ") for format: " << format << ", shared context: " << shared;
qErrnoWarning("%s", qPrintable(message));
}
return result;
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 878f55e56b..71ed33f85b 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -657,9 +657,9 @@ void QWindowsInputContext::handleInputLanguageChanged(WPARAM wparam, LPARAM lpar
m_locale = qt_localeFromLCID(m_languageId);
emitLocaleChanged();
- qCDebug(lcQpaInputMethods) << __FUNCTION__ << hex << showbase
+ qCDebug(lcQpaInputMethods) << __FUNCTION__ << Qt::hex << Qt::showbase
<< oldLanguageId << "->" << newLanguageId << "Character set:"
- << DWORD(wparam) << dec << noshowbase << m_locale;
+ << DWORD(wparam) << Qt::dec << Qt::noshowbase << m_locale;
}
/*!
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 2c90b0484e..8dd3810463 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -217,6 +217,8 @@ static inline unsigned parseOptions(const QStringList &paramList,
options |= QWindowsIntegration::NoNativeMenus;
} else if (param == QLatin1String("nowmpointer")) {
options |= QWindowsIntegration::DontUseWMPointer;
+ } else if (param == QLatin1String("reverse")) {
+ options |= QWindowsIntegration::RtlEnabled;
} else {
qWarning() << "Unknown option" << param;
}
@@ -324,7 +326,7 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
if (window->type() == Qt::Desktop) {
QWindowsDesktopWindow *result = new QWindowsDesktopWindow(window);
qCDebug(lcQpaWindows) << "Desktop window:" << window
- << showbase << hex << result->winId() << noshowbase << dec << result->geometry();
+ << Qt::showbase << Qt::hex << result->winId() << Qt::noshowbase << Qt::dec << result->geometry();
return result;
}
@@ -353,6 +355,9 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
QWindowsWindow *result = createPlatformWindowHelper(window, obtained);
Q_ASSERT(result);
+ if (window->isTopLevel() && !QWindowsContext::shouldHaveNonClientDpiScaling(window))
+ result->setFlag(QWindowsWindow::DisableNonClientScaling);
+
if (QWindowsMenuBar *menuBarToBeInstalled = QWindowsMenuBar::menuBarOf(window))
menuBarToBeInstalled->install(result);
@@ -373,8 +378,8 @@ QPlatformWindow *QWindowsIntegration::createForeignWindow(QWindow *window, WId n
screen = pScreen->screen();
if (screen && screen != window->screen())
window->setScreen(screen);
- qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex
- << result->winId() << noshowbase << dec << obtainedGeometry << screen;
+ qCDebug(lcQpaWindows) << "Foreign window:" << window << Qt::showbase << Qt::hex
+ << result->winId() << Qt::noshowbase << Qt::dec << obtainedGeometry << screen;
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index e28b2c2fb3..015cf79b6c 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -69,7 +69,8 @@ public:
AlwaysUseNativeMenus = 0x100,
NoNativeMenus = 0x200,
DontUseWMPointer = 0x400,
- DetectAltGrModifier = 0x800
+ DetectAltGrModifier = 0x800,
+ RtlEnabled = 0x1000
};
explicit QWindowsIntegration(const QStringList &paramList);
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index c050369801..44668cde78 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -554,7 +554,7 @@ QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
if (const quint32 qtKey = k.qtKey[i]) {
d << '[' << i << ' ';
QtDebugUtils::formatQFlags(d, ModsTbl[i]);
- d << ' ' << hex << showbase << qtKey << dec << noshowbase << ' ';
+ d << ' ' << Qt::hex << Qt::showbase << qtKey << Qt::dec << Qt::noshowbase << ' ';
QtDebugUtils::formatQEnum(d, Qt::Key(qtKey));
if (qtKey >= 32 && qtKey < 128)
d << " '" << char(qtKey) << '\'';
@@ -776,7 +776,7 @@ void QWindowsKeyMapper::updatePossibleKeyCodes(unsigned char *kbdBuffer, quint32
::ToAscii(vk_key, scancode, kbdBuffer, reinterpret_cast<LPWORD>(&buffer), 0);
}
qCDebug(lcQpaEvents) << __FUNCTION__ << "for virtual key="
- << hex << showbase << vk_key << dec << noshowbase << keyLayout[vk_key];
+ << Qt::hex << Qt::showbase << vk_key << Qt::dec << Qt::noshowbase << keyLayout[vk_key];
}
static inline QString messageKeyText(const MSG &msg)
@@ -879,21 +879,16 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
#if defined(WM_APPCOMMAND)
const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam);
// QTBUG-57198, do not send mouse-synthesized commands as key events in addition
+ bool skipPressRelease = false;
switch (GET_DEVICE_LPARAM(msg.lParam)) {
case FAPPCOMMAND_MOUSE:
return false;
case FAPPCOMMAND_KEY:
- // QTBUG-62838, swallow WM_KEYDOWN, WM_KEYUP for commands that are
- // reflected in VK(s) like VK_MEDIA_NEXT_TRACK. Don't do that for
- // APPCOMMAND_BROWSER_HOME as that one does not trigger two events
- if (cmd != APPCOMMAND_BROWSER_HOME) {
- MSG peekedMsg;
- if (PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_NOREMOVE)
- && peekedMsg.message == WM_KEYDOWN) {
- PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE);
- PeekMessage(&peekedMsg, msg.hwnd, 0, 0, PM_REMOVE);
- }
- }
+ // QTBUG-62838, use WM_KEYDOWN/WM_KEYUP for commands that are reflected
+ // in VK(s) like VK_MEDIA_NEXT_TRACK, to get correct codes and autorepeat.
+ // Don't do that for APPCOMMAND_BROWSER_HOME as that one does not trigger two events.
+ if (cmd != APPCOMMAND_BROWSER_HOME)
+ skipPressRelease = true;
break;
}
@@ -908,7 +903,8 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
return false;
const int qtKey = int(CmdTbl[cmd]);
- sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
+ if (!skipPressRelease)
+ sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
// QTBUG-43343: Make sure to return false if Qt does not handle the key, otherwise,
// the keys are not passed to the active media player.
# if QT_CONFIG(shortcut)
@@ -1388,7 +1384,7 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
}
}
qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey="
- << showbase << hex << e->nativeVirtualKey() << dec << noshowbase
+ << Qt::showbase << Qt::hex << e->nativeVirtualKey() << Qt::dec << Qt::noshowbase
<< e->modifiers() << kbItem << "\n returns" << formatKeys(result);
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp
index 17a1b94101..e55e283fe1 100644
--- a/src/plugins/platforms/windows/qwindowsmenu.cpp
+++ b/src/plugins/platforms/windows/qwindowsmenu.cpp
@@ -896,8 +896,8 @@ void QWindowsMenuItem::formatDebug(QDebug &d) const
d << ", parentMenu=" << static_cast<const void *>(m_parentMenu);
if (m_subMenu)
d << ", subMenu=" << static_cast<const void *>(m_subMenu);
- d << ", tag=" << showbase << hex
- << tag() << noshowbase << dec << ", id=" << m_id;
+ d << ", tag=" << Qt::showbase << Qt::hex
+ << tag() << Qt::noshowbase << Qt::dec << ", id=" << m_id;
#if QT_CONFIG(shortcut)
if (!m_shortcut.isEmpty())
d << ", shortcut=" << m_shortcut;
@@ -933,7 +933,7 @@ void QWindowsMenu::formatDebug(QDebug &d) const
if (m_parentMenu != nullptr)
d << " [on menu]";
if (tag())
- d << ", tag=" << showbase << hex << tag() << noshowbase << dec;
+ d << ", tag=" << Qt::showbase << Qt::hex << tag() << Qt::noshowbase << Qt::dec;
if (m_visible)
d << " [visible]";
if (m_enabled)
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 96e34fb44c..030d8d1e0f 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -1087,7 +1087,10 @@ bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMi
const QImage image = qvariant_cast<QImage>(mimeData->imageData());
if (image.isNull())
return false;
- return cf == CF_DIBV5 || (cf == CF_DIB) || cf == int(CF_PNG);
+ // QTBUG-64322: Use PNG only for transparent images as otherwise MS PowerPoint
+ // cannot handle it.
+ return cf == CF_DIBV5 || cf == CF_DIB
+ || (cf == int(CF_PNG) && image.hasAlphaChannel());
}
bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index 737fd1d2a9..97e1319e8d 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -106,7 +106,7 @@ static inline void compressMouseMove(MSG *msg)
// Extract the x,y coordinates from the lParam as we do in the WndProc
msg->pt.x = GET_X_LPARAM(mouseMsg.lParam);
msg->pt.y = GET_Y_LPARAM(mouseMsg.lParam);
- ClientToScreen(msg->hwnd, &(msg->pt));
+ clientToScreen(msg->hwnd, &(msg->pt));
// Remove the mouse move message
PeekMessage(&mouseMsg, msg->hwnd, WM_MOUSEMOVE,
WM_MOUSEMOVE, PM_REMOVE);
@@ -124,8 +124,8 @@ static inline QTouchDevice *createTouchDevice()
return nullptr;
const int tabletPc = GetSystemMetrics(SM_TABLETPC);
const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
- qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY)
- << "Ready:" << (digitizers & NID_READY) << dec << noshowbase
+ qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY)
+ << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
<< "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
QTouchDevice *result = new QTouchDevice;
result->setType(digitizers & NID_INTEGRATED_TOUCH
@@ -157,6 +157,12 @@ QTouchDevice *QWindowsMouseHandler::ensureTouchDevice()
return m_touchDevice;
}
+void QWindowsMouseHandler::clearEvents()
+{
+ m_lastEventType = QEvent::None;
+ m_lastEventButton = Qt::NoButton;
+}
+
Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons()
{
Qt::MouseButtons result = nullptr;
@@ -262,7 +268,13 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
if (et == QtWindows::MouseWheelEvent)
return translateMouseWheelEvent(window, hwnd, msg, result);
- const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) {
+ RECT clientArea;
+ GetClientRect(hwnd, &clientArea);
+ winEventPosition.setX(clientArea.right - winEventPosition.x());
+ }
+
QPoint clientPosition;
QPoint globalPosition;
if (et & QtWindows::NonClientEventFlag) {
@@ -287,8 +299,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
- const MouseEvent mouseEvent = eventFromMsg(msg);
-
// Check for events synthesized from touch. Lower byte is touch index, 0 means pen.
static const bool passSynthesizedMouseEvents =
!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch);
@@ -305,13 +315,40 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
}
+ const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const MouseEvent mouseEvent = eventFromMsg(msg);
+ Qt::MouseButtons buttons;
+
+ if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick)
+ buttons = queryMouseButtons();
+ else
+ buttons = keyStateToMouseButtons(msg.wParam);
+
+ // When the left/right mouse buttons are pressed over the window title bar
+ // WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN messages are received. But no UP
+ // messages are received on release, only WM_NCMOUSEMOVE/WM_MOUSEMOVE.
+ // We detect it and generate the missing release events here. (QTBUG-75678)
+ // The last event vars are cleared on QWindowsContext::handleExitSizeMove()
+ // to avoid generating duplicated release events.
+ if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
+ && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
+ && (m_lastEventButton & buttons) == 0) {
+ if (mouseEvent.type == QEvent::NonClientAreaMouseMove) {
+ QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, globalPosition, buttons, m_lastEventButton,
+ QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source);
+ } else {
+ QWindowSystemInterface::handleMouseEvent(window, clientPosition, globalPosition, buttons, m_lastEventButton,
+ QEvent::MouseButtonRelease, keyModifiers, source);
+ }
+ }
+ m_lastEventType = mouseEvent.type;
+ m_lastEventButton = mouseEvent.button;
+
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
- const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons();
QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition,
globalPosition, buttons,
mouseEvent.button, mouseEvent.type,
- QWindowsKeyMapper::queryKeyboardModifiers(),
- source);
+ keyModifiers, source);
return false; // Allow further event processing (dragging of windows).
}
@@ -334,7 +371,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
- const Qt::MouseButtons buttons = keyStateToMouseButtons(int(msg.wParam));
// If the window was recently resized via mouse doubleclick on the frame or title bar,
// we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click,
@@ -461,8 +497,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
if (!discardEvent && mouseEvent.type != QEvent::None) {
QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons,
mouseEvent.button, mouseEvent.type,
- QWindowsKeyMapper::queryKeyboardModifiers(),
- source);
+ keyModifiers, source);
}
m_previousCaptureWindow = hasCapture ? window : nullptr;
// QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h
index 480662c9bf..5fe4b09c1e 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.h
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.h
@@ -45,6 +45,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qhash.h>
+#include <QtGui/qevent.h>
QT_BEGIN_NAMESPACE
@@ -72,13 +73,14 @@ public:
bool translateScrollEvent(QWindow *window, HWND hwnd,
MSG msg, LRESULT *result);
- static inline Qt::MouseButtons keyStateToMouseButtons(int);
+ static inline Qt::MouseButtons keyStateToMouseButtons(WPARAM);
static inline Qt::KeyboardModifiers keyStateToModifiers(int);
static inline int mouseButtonsToKeyState(Qt::MouseButtons);
static Qt::MouseButtons queryMouseButtons();
QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); }
void clearWindowUnderMouse() { m_windowUnderMouse = 0; }
+ void clearEvents();
private:
inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd,
@@ -91,9 +93,11 @@ private:
QTouchDevice *m_touchDevice = nullptr;
bool m_leftButtonDown = false;
QWindow *m_previousCaptureWindow = nullptr;
+ QEvent::Type m_lastEventType = QEvent::None;
+ Qt::MouseButton m_lastEventButton = Qt::NoButton;
};
-Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam)
+Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(WPARAM wParam)
{
Qt::MouseButtons mb(Qt::NoButton);
if (wParam & MK_LBUTTON)
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
index b8ab7f8779..e581b30ced 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp
@@ -40,6 +40,7 @@
#include "qwindowsnativeinterface.h"
#include "qwindowsclipboard.h"
#include "qwindowswindow.h"
+#include "qwindowsscreen.h"
#include "qwindowscontext.h"
#include "qwindowscursor.h"
#include "qwindowsopenglcontext.h"
@@ -124,6 +125,21 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc
return nullptr;
}
+void *QWindowsNativeInterface::nativeResourceForScreen(const QByteArray &resource, QScreen *screen)
+{
+ if (!screen || !screen->handle()) {
+ qWarning("%s: '%s' requested for null screen or screen without handle.", __FUNCTION__, resource.constData());
+ return nullptr;
+ }
+ QWindowsScreen *bs = static_cast<QWindowsScreen *>(screen->handle());
+ int type = resourceType(resource);
+ if (type == HandleType)
+ return bs->handle();
+
+ qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData());
+ return nullptr;
+}
+
#ifndef QT_NO_CURSOR
void *QWindowsNativeInterface::nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor)
{
diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.h b/src/plugins/platforms/windows/qwindowsnativeinterface.h
index e6f8aae8fb..ce395dc5a4 100644
--- a/src/plugins/platforms/windows/qwindowsnativeinterface.h
+++ b/src/plugins/platforms/windows/qwindowsnativeinterface.h
@@ -74,6 +74,7 @@ public:
void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) override;
#endif
void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) override;
+ void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) override;
#ifndef QT_NO_CURSOR
void *nativeResourceForCursor(const QByteArray &resource, const QCursor &cursor) override;
#endif
diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp
index e9c3f2cbf6..fb6a74581a 100644
--- a/src/plugins/platforms/windows/qwindowsole.cpp
+++ b/src/plugins/platforms/windows/qwindowsole.cpp
@@ -110,7 +110,7 @@ QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
}
if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled())
- qCDebug(lcQpaMime) <<__FUNCTION__ << *pformatetc << "returns" << hex << showbase << quint64(hr);
+ qCDebug(lcQpaMime) <<__FUNCTION__ << *pformatetc << "returns" << Qt::hex << Qt::showbase << quint64(hr);
return hr;
}
@@ -135,7 +135,7 @@ QWindowsOleDataObject::QueryGetData(LPFORMATETC pformatetc)
ResultFromScode(S_OK) : ResultFromScode(S_FALSE);
}
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << hex << int(hr);
+ qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << Qt::hex << int(hr);
return hr;
}
@@ -163,7 +163,7 @@ QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL
hr = ResultFromScode(S_OK);
}
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << hex << int(hr);
+ qCDebug(lcQpaMime) << __FUNCTION__ << " returns 0x" << Qt::hex << int(hr);
return hr;
}
diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp
index 840a3a11c4..35418a18e7 100644
--- a/src/plugins/platforms/windows/qwindowsopengltester.cpp
+++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp
@@ -188,9 +188,9 @@ QDebug operator<<(QDebug d, const GpuDescription &gd)
{
QDebugStateSaver s(d);
d.nospace();
- d << hex << showbase << "GpuDescription(vendorId=" << gd.vendorId
+ d << Qt::hex << Qt::showbase << "GpuDescription(vendorId=" << gd.vendorId
<< ", deviceId=" << gd.deviceId << ", subSysId=" << gd.subSysId
- << dec << noshowbase << ", revision=" << gd.revision
+ << Qt::dec << Qt::noshowbase << ", revision=" << gd.revision
<< ", driver: " << gd.driverName
<< ", version=" << gd.driverVersion << ", " << gd.description
<< gd.gpuSuitableScreen << ')';
@@ -207,11 +207,11 @@ QString GpuDescription::toString() const
<< "\n Driver Name : " << driverName
<< "\n Driver Version : " << driverVersion.toString()
<< "\n Vendor ID : 0x" << qSetPadChar(QLatin1Char('0'))
- << uppercasedigits << hex << qSetFieldWidth(4) << vendorId
+ << Qt::uppercasedigits << Qt::hex << qSetFieldWidth(4) << vendorId
<< "\n Device ID : 0x" << qSetFieldWidth(4) << deviceId
<< "\n SubSys ID : 0x" << qSetFieldWidth(8) << subSysId
<< "\n Revision ID : 0x" << qSetFieldWidth(4) << revision
- << dec;
+ << Qt::dec;
if (!gpuSuitableScreen.isEmpty())
str << "\nGL windows forced to screen: " << gpuSuitableScreen;
return result;
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index f1960f1585..778170d563 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -250,6 +250,23 @@ static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState)
return result;
}
+static Qt::MouseButtons queryMouseButtons()
+{
+ Qt::MouseButtons result = Qt::NoButton;
+ const bool mouseSwapped = GetSystemMetrics(SM_SWAPBUTTON);
+ if (GetAsyncKeyState(VK_LBUTTON) < 0)
+ result |= mouseSwapped ? Qt::RightButton: Qt::LeftButton;
+ if (GetAsyncKeyState(VK_RBUTTON) < 0)
+ result |= mouseSwapped ? Qt::LeftButton : Qt::RightButton;
+ if (GetAsyncKeyState(VK_MBUTTON) < 0)
+ result |= Qt::MidButton;
+ if (GetAsyncKeyState(VK_XBUTTON1) < 0)
+ result |= Qt::XButton1;
+ if (GetAsyncKeyState(VK_XBUTTON2) < 0)
+ result |= Qt::XButton2;
+ return result;
+}
+
static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos)
{
QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT);
@@ -298,8 +315,8 @@ static QTouchDevice *createTouchDevice()
return nullptr;
const int tabletPc = GetSystemMetrics(SM_TABLETPC);
const int maxTouchPoints = GetSystemMetrics(SM_MAXIMUMTOUCHES);
- qCDebug(lcQpaEvents) << "Digitizers:" << hex << showbase << (digitizers & ~NID_READY)
- << "Ready:" << (digitizers & NID_READY) << dec << noshowbase
+ qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY)
+ << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase
<< "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints;
QTouchDevice *result = new QTouchDevice;
result->setType(digitizers & NID_INTEGRATED_TOUCH
@@ -319,6 +336,12 @@ QTouchDevice *QWindowsPointerHandler::ensureTouchDevice()
return m_touchDevice;
}
+void QWindowsPointerHandler::clearEvents()
+{
+ m_lastEventType = QEvent::None;
+ m_lastEventButton = Qt::NoButton;
+}
+
void QWindowsPointerHandler::handleCaptureRelease(QWindow *window,
QWindow *currentWindowUnderPointer,
HWND hwnd,
@@ -452,19 +475,19 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
QList<QWindowSystemInterface::TouchPoint> touchPoints;
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaEvents).noquote().nospace() << showbase
+ qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
<< __FUNCTION__
- << " message=" << hex << msg.message
- << " count=" << dec << count;
+ << " message=" << Qt::hex << msg.message
+ << " count=" << Qt::dec << count;
Qt::TouchPointStates allStates = 0;
for (quint32 i = 0; i < count; ++i) {
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaEvents).noquote().nospace() << showbase
+ qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
<< " TouchPoint id=" << touchInfo[i].pointerInfo.pointerId
<< " frame=" << touchInfo[i].pointerInfo.frameId
- << " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags;
+ << " flags=" << Qt::hex << touchInfo[i].pointerInfo.pointerFlags;
QWindowSystemInterface::TouchPoint touchPoint;
const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
@@ -531,7 +554,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect))
return false;
- const quint32 pointerId = penInfo->pointerInfo.pointerId;
+ const qint64 sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice;
const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y);
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left)
@@ -546,11 +569,11 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
const int z = 0;
if (QWindowsContext::verbose > 1)
- qCDebug(lcQpaEvents).noquote().nospace() << showbase
- << __FUNCTION__ << " pointerId=" << pointerId
+ qCDebug(lcQpaEvents).noquote().nospace() << Qt::showbase
+ << __FUNCTION__ << " sourceDevice=" << sourceDevice
<< " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos
- << " message=" << hex << msg.message
- << " flags=" << hex << penInfo->pointerInfo.pointerFlags;
+ << " message=" << Qt::hex << msg.message
+ << " flags=" << Qt::hex << penInfo->pointerInfo.pointerFlags;
const QTabletEvent::TabletDevice device = QTabletEvent::Stylus;
QTabletEvent::PointerType type;
@@ -570,7 +593,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
switch (msg.message) {
case WM_POINTERENTER: {
- QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, pointerId);
+ QWindowSystemInterface::handleTabletEnterProximityEvent(device, type, sourceDevice);
m_windowUnderPointer = window;
// The local coordinates may fall outside the window.
// Wait until the next update to send the enter event.
@@ -583,12 +606,12 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
m_windowUnderPointer = nullptr;
m_currentWindow = nullptr;
}
- QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, pointerId);
+ QWindowSystemInterface::handleTabletLeaveProximityEvent(device, type, sourceDevice);
break;
case WM_POINTERDOWN:
case WM_POINTERUP:
case WM_POINTERUPDATE: {
- QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(pointerId).target; // Pass to window that grabbed it.
+ QWindow *target = QGuiApplicationPrivate::tabletDevicePoint(sourceDevice).target; // Pass to window that grabbed it.
if (!target && m_windowUnderPointer)
target = m_windowUnderPointer;
if (!target)
@@ -597,6 +620,9 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
if (m_needsEnterOnPointerUpdate) {
m_needsEnterOnPointerUpdate = false;
if (window != m_currentWindow) {
+ // make sure we subscribe to leave events for this window
+ trackLeave(hwnd);
+
QWindowSystemInterface::handleEnterEvent(window, localPos, globalPos);
m_currentWindow = window;
if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(target))
@@ -607,7 +633,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure, rotation, z,
- pointerId, keyModifiers);
+ sourceDevice, keyModifiers);
return false; // Allow mouse messages to be generated.
}
}
@@ -668,7 +694,13 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
{
*result = 0;
- const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
+ if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) {
+ RECT clientArea;
+ GetClientRect(hwnd, &clientArea);
+ eventPos.setX(clientArea.right - eventPos.x());
+ }
+
QPoint localPos;
QPoint globalPos;
@@ -681,7 +713,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
}
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
- const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam);
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
if (et == QtWindows::MouseWheelEvent)
@@ -707,6 +738,32 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
}
const MouseEvent mouseEvent = eventFromMsg(msg);
+ Qt::MouseButtons mouseButtons;
+
+ if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick)
+ mouseButtons = queryMouseButtons();
+ else
+ mouseButtons = mouseButtonsFromKeyState(msg.wParam);
+
+ // When the left/right mouse buttons are pressed over the window title bar
+ // WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN messages are received. But no UP
+ // messages are received on release, only WM_NCMOUSEMOVE/WM_MOUSEMOVE.
+ // We detect it and generate the missing release events here. (QTBUG-75678)
+ // The last event vars are cleared on QWindowsContext::handleExitSizeMove()
+ // to avoid generating duplicated release events.
+ if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
+ && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
+ && (m_lastEventButton & mouseButtons) == 0) {
+ if (mouseEvent.type == QEvent::NonClientAreaMouseMove) {
+ QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, m_lastEventButton,
+ QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source);
+ } else {
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, m_lastEventButton,
+ QEvent::MouseButtonRelease, keyModifiers, source);
+ }
+ }
+ m_lastEventType = mouseEvent.type;
+ m_lastEventButton = mouseEvent.button;
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons,
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h
index aebef062bc..ccbb1d3939 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.h
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.h
@@ -46,7 +46,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qhash.h>
-#include <qpa/qwindowsysteminterface.h>
+#include <QtGui/qevent.h>
QT_BEGIN_NAMESPACE
@@ -64,6 +64,7 @@ public:
QTouchDevice *ensureTouchDevice();
QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); }
void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
+ void clearEvents();
private:
bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count);
@@ -79,6 +80,8 @@ private:
QPointer<QWindow> m_currentWindow;
QWindow *m_previousCaptureWindow = nullptr;
bool m_needsEnterOnPointerUpdate = false;
+ QEvent::Type m_lastEventType = QEvent::None;
+ Qt::MouseButton m_lastEventButton = Qt::NoButton;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index 0520f88935..2f8850cbe0 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -240,7 +240,8 @@ QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const
QWindow *result = nullptr;
if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE))
result = QWindowsWindow::topLevelOf(child);
- qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result;
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result;
return result;
}
@@ -250,7 +251,8 @@ QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags)
if (QPlatformWindow *bw = QWindowsContext::instance()->
findPlatformWindowAt(GetDesktopWindow(), screenPoint, flags))
result = bw->window();
- qCDebug(lcQpaWindows) <<__FUNCTION__ << screenPoint << " returns " << result;
+ if (QWindowsContext::verbose > 1)
+ qCDebug(lcQpaWindows) <<__FUNCTION__ << screenPoint << " returns " << result;
return result;
}
@@ -321,6 +323,11 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData)
}
}
+HMONITOR QWindowsScreen::handle() const
+{
+ return m_data.hMonitor;
+}
+
QRect QWindowsScreen::virtualGeometry(const QPlatformScreen *screen) // cf QScreen::virtualGeometry()
{
QRect result;
@@ -433,6 +440,12 @@ QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTy
QWindowsScreenManager::QWindowsScreenManager() = default;
+
+bool QWindowsScreenManager::isSingleScreen()
+{
+ return QWindowsContext::instance()->screenManager().screens().size() < 2;
+}
+
/*!
\brief Triggers synchronization of screens (WM_DISPLAYCHANGE).
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index 824bcb1ad6..3eb2d35b27 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -104,6 +104,8 @@ public:
inline void handleChanges(const QWindowsScreenData &newData);
+ HMONITOR handle() const;
+
#ifndef QT_NO_CURSOR
QPlatformCursor *cursor() const override { return m_cursor.data(); }
const CursorPtr &cursorPtr() const { return m_cursor; }
@@ -138,6 +140,8 @@ public:
const QWindowsScreen *screenAtDp(const QPoint &p) const;
const QWindowsScreen *screenForHwnd(HWND hwnd) const;
+ static bool isSingleScreen();
+
private:
void removeScreen(int index);
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index fa209f09c4..cd5a78abb6 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -146,13 +146,13 @@ QDebug operator<<(QDebug d, const LOGCONTEXT &lc)
QDebugStateSaver saver(d);
d.nospace();
d << "LOGCONTEXT(\"" << QString::fromWCharArray(lc.lcName) << "\", options=0x"
- << hex << lc.lcOptions << dec;
+ << Qt::hex << lc.lcOptions << Qt::dec;
formatOptions(d, lc.lcOptions);
- d << ", status=0x" << hex << lc.lcStatus << ", device=0x" << lc.lcDevice
- << dec << ", PktRate=" << lc.lcPktRate
+ d << ", status=0x" << Qt::hex << lc.lcStatus << ", device=0x" << lc.lcDevice
+ << Qt::dec << ", PktRate=" << lc.lcPktRate
<< ", PktData=" << lc.lcPktData << ", PktMode=" << lc.lcPktMode
- << ", MoveMask=0x" << hex << lc.lcMoveMask << ", BtnDnMask=0x" << lc.lcBtnDnMask
- << ", BtnUpMask=0x" << lc.lcBtnUpMask << dec << ", SysMode=" << lc.lcSysMode
+ << ", MoveMask=0x" << Qt::hex << lc.lcMoveMask << ", BtnDnMask=0x" << lc.lcBtnDnMask
+ << ", BtnUpMask=0x" << lc.lcBtnUpMask << Qt::dec << ", SysMode=" << lc.lcSysMode
<< ", InOrg=(" << lc.lcInOrgX << ", " << lc.lcInOrgY << ", " << lc.lcInOrgZ
<< "), InExt=(" << lc.lcInExtX << ", " << lc.lcInExtY << ", " << lc.lcInExtZ
<< ") OutOrg=(" << lc.lcOutOrgX << ", " << lc.lcOutOrgY << ", "
@@ -305,7 +305,7 @@ QString QWindowsTabletSupport::description() const
<< '.' << (specificationVersion & 0xFF) << " implementation: v"
<< (implementationVersion >> 8) << '.' << (implementationVersion & 0xFF)
<< ' ' << devices << " device(s), " << cursors << " cursor(s), "
- << extensions << " extensions" << ", options: 0x" << hex << opts << dec;
+ << extensions << " extensions" << ", options: 0x" << Qt::hex << opts << Qt::dec;
formatOptions(str, opts);
if (m_tiltSupport)
str << " tilt";
@@ -435,6 +435,27 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L
m_currentDevice = m_devices.size();
m_devices.push_back(tabletInit(uniqueId, cursorType));
}
+
+ /**
+ * We should check button map for changes on every proximity event, not
+ * only during initialization phase.
+ *
+ * WARNING: in 2016 there were some Wacom table drivers, which could mess up
+ * button mapping if the remapped button was pressed, while the
+ * application **didn't have input focus**. This bug is somehow
+ * related to the fact that Wacom drivers allow user to configure
+ * per-application button-mappings. If the bug shows up again,
+ * just move this button-map fetching into initialization block.
+ *
+ * See https://bugs.kde.org/show_bug.cgi?id=359561
+ */
+ BYTE logicalButtons[32];
+ memset(logicalButtons, 0, 32);
+ m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_SYSBTNMAP, &logicalButtons);
+ m_devices[m_currentDevice].buttonsMap[0x1] = logicalButtons[0];
+ m_devices[m_currentDevice].buttonsMap[0x2] = logicalButtons[1];
+ m_devices[m_currentDevice].buttonsMap[0x4] = logicalButtons[2];
+
m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor);
m_state = PenProximity;
qCDebug(lcQpaTablet) << "enter proximity for device #"
@@ -446,6 +467,52 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L
return true;
}
+Qt::MouseButton buttonValueToEnum(DWORD button,
+ const QWindowsTabletDeviceData &tdd) {
+
+ enum : unsigned {
+ leftButtonValue = 0x1,
+ middleButtonValue = 0x2,
+ rightButtonValue = 0x4,
+ doubleClickButtonValue = 0x7
+ };
+
+ button = tdd.buttonsMap.value(button);
+
+ return button == leftButtonValue ? Qt::LeftButton :
+ button == rightButtonValue ? Qt::RightButton :
+ button == doubleClickButtonValue ? Qt::MiddleButton :
+ button == middleButtonValue ? Qt::MiddleButton :
+ button ? Qt::LeftButton /* fallback item */ :
+ Qt::NoButton;
+}
+
+Qt::MouseButtons convertTabletButtons(DWORD btnNew,
+ const QWindowsTabletDeviceData &tdd) {
+
+ Qt::MouseButtons buttons = Qt::NoButton;
+ for (unsigned int i = 0; i < 3; i++) {
+ unsigned int btn = 0x1 << i;
+
+ if (btn & btnNew) {
+ Qt::MouseButton convertedButton =
+ buttonValueToEnum(btn, tdd);
+
+ buttons |= convertedButton;
+
+ /**
+ * If a button that is present in hardware input is
+ * mapped to a Qt::NoButton, it means that it is going
+ * to be eaten by the driver, for example by its
+ * "Pan/Scroll" feature. Therefore we shouldn't handle
+ * any of the events associated to it. We'll just return
+ * Qt::NoButtons here.
+ */
+ }
+ }
+ return buttons;
+}
+
bool QWindowsTabletSupport::translateTabletPacketEvent()
{
static PACKET localPacketBuf[TabletPacketQSize]; // our own tablet packet queue.
@@ -552,9 +619,12 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
<< tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation;
}
+ Qt::MouseButtons buttons =
+ convertTabletButtons(packet.pkButtons, m_devices.at(m_currentDevice));
+
QWindowSystemInterface::handleTabletEvent(target, packet.pkTime, QPointF(localPos), globalPosF,
currentDevice, currentPointer,
- static_cast<Qt::MouseButtons>(packet.pkButtons),
+ buttons,
pressureNew, tiltX, tiltY,
tangentialPressure, rotation, z,
uniqueId,
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h
index d91701d6a5..8f97982308 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.h
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.h
@@ -45,6 +45,7 @@
#include <QtCore/qvector.h>
#include <QtCore/qpoint.h>
+#include <QtCore/qhash.h>
#include <wintab.h>
@@ -100,6 +101,7 @@ struct QWindowsTabletDeviceData
qint64 uniqueId = 0;
int currentDevice = 0;
int currentPointerType = 0;
+ QHash<quint8, quint8> buttonsMap;
};
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index a6b9781252..b75c64c40e 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -170,15 +170,9 @@ public:
if (m_params) {
const QString fileName = m_params->fileName;
SHFILEINFO info;
-#ifndef Q_OS_WINCE
- const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
-#endif
const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(fileName.utf16()),
m_params->attributes, &info, sizeof(SHFILEINFO),
m_params->flags);
-#ifndef Q_OS_WINCE
- SetErrorMode(oldErrorMode);
-#endif
m_doneMutex.lock();
if (!m_cancelled.load()) {
*m_params->result = result;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 338e594c7b..e700e6cff4 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -134,6 +134,10 @@ static QByteArray debugWinExStyle(DWORD exStyle)
rc += " WS_EX_LAYERED";
if (exStyle & WS_EX_DLGMODALFRAME)
rc += " WS_EX_DLGMODALFRAME";
+ if (exStyle & WS_EX_LAYOUTRTL)
+ rc += " WS_EX_LAYOUTRTL";
+ if (exStyle & WS_EX_NOINHERITLAYOUT)
+ rc += " WS_EX_NOINHERITLAYOUT";
return rc;
}
@@ -184,6 +188,7 @@ static inline RECT RECTfromQRect(const QRect &rect)
return result;
}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug d, const RECT &r)
{
@@ -238,7 +243,7 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp)
QDebugStateSaver saver(d);
d.nospace();
d.noquote();
- d << "WINDOWPLACEMENT(flags=0x" << hex << wp.flags << dec << ", showCmd="
+ d << "WINDOWPLACEMENT(flags=0x" << Qt::hex << wp.flags << Qt::dec << ", showCmd="
<< wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition
<< ", rcNormalPosition=" << wp.rcNormalPosition;
return d;
@@ -248,7 +253,7 @@ QDebug operator<<(QDebug d, const GUID &guid)
{
QDebugStateSaver saver(d);
d.nospace();
- d << '{' << hex << uppercasedigits << qSetPadChar(QLatin1Char('0'))
+ d << '{' << Qt::hex << Qt::uppercasedigits << qSetPadChar(QLatin1Char('0'))
<< qSetFieldWidth(8) << guid.Data1
<< qSetFieldWidth(0) << '-' << qSetFieldWidth(4)
<< guid.Data2 << qSetFieldWidth(0) << '-' << qSetFieldWidth(4)
@@ -262,6 +267,16 @@ QDebug operator<<(QDebug d, const GUID &guid)
}
#endif // !QT_NO_DEBUG_STREAM
+static void formatBriefRectangle(QDebug &d, const QRect &r)
+{
+ d << r.width() << 'x' << r.height() << forcesign << r.x() << r.y() << noforcesign;
+}
+
+static void formatBriefMargins(QDebug &d, const QMargins &m)
+{
+ d << m.left() << ", " << m.top() << ", " << m.right() << ", " << m.bottom();
+}
+
// QTBUG-43872, for windows that do not have WS_EX_TOOLWINDOW set, WINDOWPLACEMENT
// is in workspace/available area coordinates.
static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point)
@@ -296,7 +311,7 @@ static inline QRect frameGeometry(HWND hwnd, bool topLevel)
const int width = rect.right - rect.left;
const int height = rect.bottom - rect.top;
POINT leftTop = { rect.left, rect.top };
- ScreenToClient(parent, &leftTop);
+ screenToClient(parent, &leftTop);
rect.left = leftTop.x;
rect.top = leftTop.y;
rect.right = leftTop.x + width;
@@ -656,6 +671,17 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
if ((flags & Qt::MSWindowsFixedSizeDialogHint))
dialog = true;
+ // This causes the title bar to drawn RTL and the close button
+ // to be left. Note that this causes:
+ // - All DCs created on the Window to have RTL layout (see SetLayout)
+ // - ClientToScreen() and ScreenToClient() to work in reverse as well.
+ // - Mouse event coordinates to be mirrored.
+ // - Positioning of child Windows.
+ if (QGuiApplication::layoutDirection() == Qt::RightToLeft
+ && (QWindowsIntegration::instance()->options() & QWindowsIntegration::RtlEnabled) != 0) {
+ exStyle |= WS_EX_LAYOUTRTL | WS_EX_NOINHERITLAYOUT;
+ }
+
// Parent: Use transient parent for top levels.
if (popup) {
flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent.
@@ -761,6 +787,16 @@ QWindowsWindowData
QPoint pos = calcPosition(w, context, invMargins);
+ // Mirror the position when creating on a parent in RTL mode, ditto for the obtained geometry.
+ int mirrorParentWidth = 0;
+ if (!w->isTopLevel() && QWindowsBaseWindow::isRtlLayout(parentHandle)) {
+ RECT rect;
+ GetClientRect(parentHandle, &rect);
+ mirrorParentWidth = rect.right;
+ }
+ if (mirrorParentWidth != 0 && pos.x() != CW_USEDEFAULT && context->frameWidth != CW_USEDEFAULT)
+ pos.setX(mirrorParentWidth - context->frameWidth - pos.x());
+
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
style,
pos.x(), pos.y(),
@@ -768,14 +804,21 @@ QWindowsWindowData
parentHandle, nullptr, appinst, nullptr);
qCDebug(lcQpaWindows).nospace()
<< "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
- << context->obtainedGeometry << ' ' << context->margins;
+ << context->obtainedPos << context->obtainedSize << ' ' << context->margins;
if (!result.hwnd) {
qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
return result;
}
- result.geometry = context->obtainedGeometry;
+ if (mirrorParentWidth != 0) {
+ context->obtainedPos.setX(mirrorParentWidth - context->obtainedSize.width()
+ - context->obtainedPos.x());
+ }
+
+ QRect obtainedGeometry(context->obtainedPos, context->obtainedSize);
+
+ result.geometry = obtainedGeometry;
result.fullFrameMargins = context->margins;
result.embedded = embedded;
result.hasFrame = hasFrame;
@@ -859,35 +902,78 @@ static QSize toNativeSizeConstrained(QSize dip, const QWindow *w)
\ingroup qt-lighthouse-win
*/
-QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) :
- minimumSize(toNativeSizeConstrained(w->minimumSize(), w)),
- maximumSize(toNativeSizeConstrained(w->maximumSize(), w)),
- customMargins(cm)
+QMargins QWindowsGeometryHint::frameOnPrimaryScreen(DWORD style, DWORD exStyle)
{
+ RECT rect = {0,0,0,0};
+ style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
+ if (AdjustWindowRectEx(&rect, style, FALSE, exStyle) == FALSE)
+ qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
+ const QMargins result(qAbs(rect.left), qAbs(rect.top),
+ qAbs(rect.right), qAbs(rect.bottom));
+ qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style="
+ << showbase << hex << style << " exStyle=" << exStyle << dec << noshowbase
+ << ' ' << rect << ' ' << result;
+ return result;
}
-bool QWindowsGeometryHint::validSize(const QSize &s) const
+QMargins QWindowsGeometryHint::frameOnPrimaryScreen(HWND hwnd)
{
- const int width = s.width();
- const int height = s.height();
- return width >= minimumSize.width() && width <= maximumSize.width()
- && height >= minimumSize.height() && height <= maximumSize.height();
+ return frameOnPrimaryScreen(DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
+ DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
}
-QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
+QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle, qreal dpi)
{
+ if (QWindowsContext::user32dll.adjustWindowRectExForDpi == nullptr)
+ return frameOnPrimaryScreen(style, exStyle);
RECT rect = {0,0,0,0};
- style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
- if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
- qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
+ style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
+ if (QWindowsContext::user32dll.adjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
+ unsigned(qRound(dpi))) == FALSE) {
+ qErrnoWarning("%s: AdjustWindowRectExForDpi failed", __FUNCTION__);
+ }
const QMargins result(qAbs(rect.left), qAbs(rect.top),
qAbs(rect.right), qAbs(rect.bottom));
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style="
- << showbase << hex << style << " exStyle=" << exStyle << dec << noshowbase
+ << Qt::showbase << Qt::hex << style << " exStyle=" << exStyle << Qt::dec << Qt::noshowbase
+ << " dpi=" << dpi
<< ' ' << rect << ' ' << result;
return result;
}
+QMargins QWindowsGeometryHint::frame(HWND hwnd, DWORD style, DWORD exStyle)
+{
+ if (QWindowsScreenManager::isSingleScreen())
+ return frameOnPrimaryScreen(style, exStyle);
+ auto screenManager = QWindowsContext::instance()->screenManager();
+ auto screen = screenManager.screenForHwnd(hwnd);
+ if (!screen)
+ screen = screenManager.screens().value(0);
+ const auto dpi = screen ? screen->logicalDpi().first : qreal(96);
+ return frame(style, exStyle, dpi);
+}
+
+// For newly created windows.
+QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry,
+ DWORD style, DWORD exStyle)
+{
+ if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
+ return {};
+ if (!QWindowsContext::user32dll.adjustWindowRectExForDpi
+ || QWindowsScreenManager::isSingleScreen()
+ || !QWindowsContext::shouldHaveNonClientDpiScaling(w)) {
+ return frameOnPrimaryScreen(style, exStyle);
+ }
+ qreal dpi = 96;
+ auto screenManager = QWindowsContext::instance()->screenManager();
+ auto screen = screenManager.screenAtDp(geometry.center());
+ if (!screen)
+ screen = screenManager.screens().value(0);
+ if (screen)
+ dpi = screen->logicalDpi().first;
+ return QWindowsGeometryHint::frame(style, exStyle, dpi);
+}
+
bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
{
// NCCALCSIZE_PARAMS structure if wParam==TRUE
@@ -907,36 +993,50 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co
return true;
}
-void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
+void QWindowsGeometryHint::frameSizeConstraints(const QWindow *w, const QMargins &margins,
+ QSize *minimumSize, QSize *maximumSize)
{
- return applyToMinMaxInfo(DWORD(GetWindowLong(hwnd, GWL_STYLE)),
- DWORD(GetWindowLong(hwnd, GWL_EXSTYLE)), mmi);
+ *minimumSize = toNativeSizeConstrained(w->minimumSize(), w);
+ *maximumSize = toNativeSizeConstrained(w->maximumSize(), w);
+
+ const int maximumWidth = qMax(maximumSize->width(), minimumSize->width());
+ const int maximumHeight = qMax(maximumSize->height(), minimumSize->height());
+ const int frameWidth = margins.left() + margins.right();
+ const int frameHeight = margins.top() + margins.bottom();
+
+ if (minimumSize->width() > 0)
+ minimumSize->rwidth() += frameWidth;
+ if (minimumSize->height() > 0)
+ minimumSize->rheight() += frameHeight;
+ if (maximumWidth < QWINDOWSIZE_MAX)
+ maximumSize->setWidth(maximumWidth + frameWidth);
+ if (maximumHeight < QWINDOWSIZE_MAX)
+ maximumSize->setHeight(maximumHeight + frameHeight);
}
-void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
+void QWindowsGeometryHint::applyToMinMaxInfo(const QWindow *w,
+ const QMargins &margins,
+ MINMAXINFO *mmi)
{
+ QSize minimumSize;
+ QSize maximumSize;
+ frameSizeConstraints(w, margins, &minimumSize, &maximumSize);
qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min="
<< minimumSize.width() << ',' << minimumSize.height()
<< " max=" << maximumSize.width() << ',' << maximumSize.height()
+ << " margins=" << margins
<< " in " << *mmi;
- const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
- const int frameWidth = margins.left() + margins.right() + customMargins.left() + customMargins.right();
- const int frameHeight = margins.top() + margins.bottom() + customMargins.top() + customMargins.bottom();
if (minimumSize.width() > 0)
- mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
+ mmi->ptMinTrackSize.x = minimumSize.width();
if (minimumSize.height() > 0)
- mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight;
+ mmi->ptMinTrackSize.y = minimumSize.height();
- const int maximumWidth = qMax(maximumSize.width(), minimumSize.width());
- const int maximumHeight = qMax(maximumSize.height(), minimumSize.height());
- if (maximumWidth < QWINDOWSIZE_MAX)
- mmi->ptMaxTrackSize.x = maximumWidth + frameWidth;
- if (maximumHeight < QWINDOWSIZE_MAX)
- mmi->ptMaxTrackSize.y = maximumHeight + frameHeight;
- qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__
- << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
- << " out " << *mmi;
+ if (maximumSize.width() < QWINDOWSIZE_MAX)
+ mmi->ptMaxTrackSize.x = maximumSize.width();
+ if (maximumSize.height() < QWINDOWSIZE_MAX)
+ mmi->ptMaxTrackSize.y = maximumSize.height();
+ qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__ << " out " << *mmi;
}
bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
@@ -963,6 +1063,11 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
\ingroup qt-lighthouse-win
*/
+bool QWindowsBaseWindow::isRtlLayout(HWND hwnd)
+{
+ return (GetWindowLongPtrW(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0;
+}
+
QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w)
{
if (w) {
@@ -996,7 +1101,7 @@ QRect QWindowsBaseWindow::geometry_sys() const
QMargins QWindowsBaseWindow::frameMargins_sys() const
{
- return QWindowsGeometryHint::frame(style(), exStyle());
+ return QWindowsGeometryHint::frame(handle(), style(), exStyle());
}
void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows.
@@ -1122,11 +1227,14 @@ void QWindowsForeignWindow::setVisible(bool visible)
QWindowCreationContext::QWindowCreationContext(const QWindow *w,
const QRect &geometryIn, const QRect &geometry,
const QMargins &cm,
- DWORD style_, DWORD exStyle_) :
- geometryHint(w, cm), window(w), style(style_), exStyle(exStyle_),
+ DWORD style, DWORD exStyle) :
+ window(w),
requestedGeometryIn(geometryIn),
- requestedGeometry(geometry), obtainedGeometry(geometry),
- margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm)
+ requestedGeometry(geometry),
+ obtainedPos(geometryIn.topLeft()),
+ obtainedSize(geometryIn.size()),
+ margins(QWindowsGeometryHint::frame(w, geometry, style, exStyle)),
+ customMargins(cm)
{
// Geometry of toplevels does not consider window frames.
// TODO: No concept of WA_wasMoved yet that would indicate a
@@ -1155,8 +1263,12 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
<< " pos incl. frame=" << QWindowsGeometryHint::positionIncludesFrame(w)
<< " frame=" << frameWidth << 'x' << frameHeight << '+'
<< frameX << '+' << frameY
- << " min=" << geometryHint.minimumSize << " max=" << geometryHint.maximumSize
- << " custom margins=" << customMargins;
+ << " margins=" << margins << " custom margins=" << customMargins;
+}
+
+void QWindowCreationContext::applyToMinMaxInfo(MINMAXINFO *mmi) const
+{
+ QWindowsGeometryHint::applyToMinMaxInfo(window, margins + customMargins, mmi);
}
/*!
@@ -1248,11 +1360,12 @@ void QWindowsWindow::initialize()
// will send the message) and screen change signals of QWindow.
if (w->type() != Qt::Desktop) {
const Qt::WindowState state = w->windowState();
+ const QRect obtainedGeometry(creationContext->obtainedPos, creationContext->obtainedSize);
if (state != Qt::WindowMaximized && state != Qt::WindowFullScreen
- && creationContext->requestedGeometryIn != creationContext->obtainedGeometry) {
- QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, creationContext->obtainedGeometry);
+ && creationContext->requestedGeometryIn != obtainedGeometry) {
+ QWindowSystemInterface::handleGeometryChange<QWindowSystemInterface::SynchronousDelivery>(w, obtainedGeometry);
}
- QPlatformScreen *obtainedScreen = screenForGeometry(creationContext->obtainedGeometry);
+ QPlatformScreen *obtainedScreen = screenForGeometry(obtainedGeometry);
if (obtainedScreen && screen() != obtainedScreen)
QWindowSystemInterface::handleWindowScreenChanged<QWindowSystemInterface::SynchronousDelivery>(w, obtainedScreen->screen());
}
@@ -1672,10 +1785,57 @@ QRect QWindowsWindow::normalGeometry() const
const bool fakeFullScreen =
m_savedFrameGeometry.isValid() && (window()->windowStates() & Qt::WindowFullScreen);
const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd);
- const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : fullFrameMargins();
+ const QMargins margins = fakeFullScreen
+ ? QWindowsGeometryHint::frame(handle(), m_savedStyle, 0)
+ : fullFrameMargins();
return frame.isValid() ? frame.marginsRemoved(margins) : frame;
}
+static QString msgUnableToSetGeometry(const QWindowsWindow *platformWindow,
+ const QRect &requestedRect,
+ const QRect &obtainedRect,
+ const QMargins &fullMargins,
+ const QMargins &customMargins)
+{
+ QString result;
+ QDebug debug(&result);
+ debug.nospace();
+ debug.noquote();
+ const auto window = platformWindow->window();
+ debug << "Unable to set geometry ";
+ formatBriefRectangle(debug, requestedRect);
+ debug << " (frame: ";
+ formatBriefRectangle(debug, requestedRect + fullMargins);
+ debug << ") on " << window->metaObject()->className() << "/\""
+ << window->objectName() << "\" on \"" << window->screen()->name()
+ << "\". Resulting geometry: ";
+ formatBriefRectangle(debug, obtainedRect);
+ debug << " (frame: ";
+ formatBriefRectangle(debug, obtainedRect + fullMargins);
+ debug << ") margins: ";
+ formatBriefMargins(debug, fullMargins);
+ if (!customMargins.isNull()) {
+ debug << " custom margin: ";
+ formatBriefMargins(debug, customMargins);
+ }
+ const auto minimumSize = window->minimumSize();
+ const bool hasMinimumSize = !minimumSize.isEmpty();
+ if (hasMinimumSize)
+ debug << " minimum size: " << minimumSize.width() << 'x' << minimumSize.height();
+ const auto maximumSize = window->maximumSize();
+ const bool hasMaximumSize = maximumSize.width() != QWINDOWSIZE_MAX || maximumSize.height() != QWINDOWSIZE_MAX;
+ if (hasMaximumSize)
+ debug << " maximum size: " << maximumSize.width() << 'x' << maximumSize.height();
+ if (hasMinimumSize || hasMaximumSize) {
+ MINMAXINFO minmaxInfo;
+ memset(&minmaxInfo, 0, sizeof(minmaxInfo));
+ platformWindow->getSizeHints(&minmaxInfo);
+ debug << ' ' << minmaxInfo;
+ }
+ debug << ')';
+ return result;
+}
+
void QWindowsWindow::setGeometry(const QRect &rectIn)
{
QRect rect = rectIn;
@@ -1695,21 +1855,10 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
setGeometry_sys(rect);
clearFlag(WithinSetGeometry);
if (m_data.geometry != rect && (isVisible() || QLibraryInfo::isDebugBuild())) {
- qWarning("%s: Unable to set geometry %dx%d+%d+%d on %s/'%s'."
- " Resulting geometry: %dx%d+%d+%d "
- "(frame: %d, %d, %d, %d, custom margin: %d, %d, %d, %d"
- ", minimum size: %dx%d, maximum size: %dx%d).",
- __FUNCTION__,
- rect.width(), rect.height(), rect.x(), rect.y(),
- window()->metaObject()->className(), qPrintable(window()->objectName()),
- m_data.geometry.width(), m_data.geometry.height(),
- m_data.geometry.x(), m_data.geometry.y(),
- m_data.fullFrameMargins.left(), m_data.fullFrameMargins.top(),
- m_data.fullFrameMargins.right(), m_data.fullFrameMargins.bottom(),
- m_data.customMargins.left(), m_data.customMargins.top(),
- m_data.customMargins.right(), m_data.customMargins.bottom(),
- window()->minimumWidth(), window()->minimumHeight(),
- window()->maximumWidth(), window()->maximumHeight());
+ const auto warning =
+ msgUnableToSetGeometry(this, rectIn, m_data.geometry,
+ m_data.fullFrameMargins, m_data.customMargins);
+ qWarning("%s: %s", __FUNCTION__, qPrintable(warning));
}
} else {
QPlatformWindow::setGeometry(rect);
@@ -1753,27 +1902,41 @@ void QWindowsWindow::handleResized(int wParam)
}
}
-void QWindowsWindow::checkForScreenChanged()
+static inline bool equalDpi(const QDpi &d1, const QDpi &d2)
+{
+ return qFuzzyCompare(d1.first, d2.first) && qFuzzyCompare(d1.second, d2.second);
+}
+
+void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode)
{
- if (parent())
+ if (parent() || QWindowsScreenManager::isSingleScreen())
return;
QPlatformScreen *currentScreen = screen();
- const auto &screenManager = QWindowsContext::instance()->screenManager();
- const QWindowsScreen *newScreen = screenManager.screenForHwnd(m_data.hwnd);
- if (newScreen != nullptr && newScreen != currentScreen) {
- qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__
- << ' ' << window() << " \"" << currentScreen->name()
- << "\"->\"" << newScreen->name() << '"';
- setFlag(SynchronousGeometryChangeEvent);
- QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
+ const QWindowsScreen *newScreen =
+ QWindowsContext::instance()->screenManager().screenForHwnd(m_data.hwnd);
+ if (newScreen == nullptr || newScreen == currentScreen)
+ return;
+ // For screens with different DPI: postpone until WM_DPICHANGE
+ if (mode == FromGeometryChange
+ && !equalDpi(currentScreen->logicalDpi(), newScreen->logicalDpi())) {
+ return;
}
+ qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__
+ << ' ' << window() << " \"" << currentScreen->name()
+ << "\"->\"" << newScreen->name() << '"';
+ if (mode == FromGeometryChange)
+ setFlag(SynchronousGeometryChangeEvent);
+ updateFullFrameMargins();
+ QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
}
void QWindowsWindow::handleGeometryChange()
{
const QRect previousGeometry = m_data.geometry;
m_data.geometry = geometry_sys();
+ if (testFlag(WithinDpiChanged))
+ return; // QGuiApplication will send resize
QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
// QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive
// expose events when shrinking, synthesize.
@@ -1819,7 +1982,16 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE;
result = SetWindowPlacement(hwnd, &windowPlacement);
} else {
- result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(),
+ int x = frameGeometry.x();
+ if (!window()->isTopLevel()) {
+ const HWND parentHandle = GetParent(hwnd);
+ if (isRtlLayout(parentHandle)) {
+ RECT rect;
+ GetClientRect(parentHandle, &rect);
+ x = rect.right - frameGeometry.width() - x;
+ }
+ }
+ result = MoveWindow(hwnd, x, frameGeometry.y(),
frameGeometry.width(), frameGeometry.height(), true);
}
qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window()
@@ -1835,8 +2007,11 @@ void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
HDC QWindowsWindow::getDC()
{
- if (!m_hdc)
+ if (!m_hdc) {
m_hdc = GetDC(handle());
+ if (QGuiApplication::layoutDirection() == Qt::RightToLeft)
+ SetLayout(m_hdc, 0); // Clear RTL layout
+ }
return m_hdc;
}
@@ -1876,6 +2051,9 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
{
if (message == WM_ERASEBKGND) // Backing store - ignored.
return true;
+ // QTBUG-75455: Suppress WM_PAINT sent to invisible windows when setting WS_EX_LAYERED
+ if (!window()->isVisible() && (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) != 0)
+ return false;
// Ignore invalid update bounding rectangles
RECT updateRect;
if (!GetUpdateRect(m_data.hwnd, &updateRect, FALSE))
@@ -2233,6 +2411,15 @@ void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
}
}
+void QWindowsWindow::updateFullFrameMargins()
+{
+ // Normally obtained from WM_NCCALCSIZE
+ const auto systemMargins = testFlag(DisableNonClientScaling)
+ ? QWindowsGeometryHint::frameOnPrimaryScreen(m_data.hwnd)
+ : frameMargins_sys();
+ setFullFrameMargins(systemMargins + m_data.customMargins);
+}
+
QMargins QWindowsWindow::frameMargins() const
{
QMargins result = fullFrameMargins();
@@ -2443,10 +2630,8 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{
// We don't apply the min/max size hint as we change the dpi, because we did not adjust the
// QScreen of the window yet so we don't have the min/max with the right ratio
- if (!testFlag(QWindowsWindow::WithinDpiChanged)) {
- const QWindowsGeometryHint hint(window(), m_data.customMargins);
- hint.applyToMinMaxInfo(m_data.hwnd, mmi);
- }
+ if (!testFlag(QWindowsWindow::WithinDpiChanged))
+ QWindowsGeometryHint::applyToMinMaxInfo(window(), fullFrameMargins(), mmi);
// This block fixes QTBUG-8361, QTBUG-4362: Frameless/title-less windows shouldn't cover the
// taskbar when maximized
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 0d8096ddfa..1abe1e3531 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -59,24 +59,23 @@ class QDebug;
struct QWindowsGeometryHint
{
- QWindowsGeometryHint() = default;
- explicit QWindowsGeometryHint(const QWindow *w, const QMargins &customMargins);
- static QMargins frame(DWORD style, DWORD exStyle);
+ static QMargins frameOnPrimaryScreen(DWORD style, DWORD exStyle);
+ static QMargins frameOnPrimaryScreen(HWND hwnd);
+ static QMargins frame(DWORD style, DWORD exStyle, qreal dpi);
+ static QMargins frame(HWND hwnd, DWORD style, DWORD exStyle);
+ static QMargins frame(const QWindow *w, const QRect &geometry,
+ DWORD style, DWORD exStyle);
static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
- void applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const;
- void applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const;
- bool validSize(const QSize &s) const;
-
+ static void applyToMinMaxInfo(const QWindow *w, const QMargins &margins,
+ MINMAXINFO *mmi);
+ static void frameSizeConstraints(const QWindow *w, const QMargins &margins,
+ QSize *minimumSize, QSize *maximumSize);
static inline QPoint mapToGlobal(HWND hwnd, const QPoint &);
static inline QPoint mapToGlobal(const QWindow *w, const QPoint &);
static inline QPoint mapFromGlobal(const HWND hwnd, const QPoint &);
static inline QPoint mapFromGlobal(const QWindow *w, const QPoint &);
static bool positionIncludesFrame(const QWindow *w);
-
- QSize minimumSize;
- QSize maximumSize;
- QMargins customMargins;
};
struct QWindowCreationContext
@@ -85,16 +84,13 @@ struct QWindowCreationContext
const QRect &geometryIn, const QRect &geometry,
const QMargins &customMargins,
DWORD style, DWORD exStyle);
- void applyToMinMaxInfo(MINMAXINFO *mmi) const
- { geometryHint.applyToMinMaxInfo(style, exStyle, mmi); }
+ void applyToMinMaxInfo(MINMAXINFO *mmi) const;
- QWindowsGeometryHint geometryHint;
const QWindow *window;
- DWORD style;
- DWORD exStyle;
QRect requestedGeometryIn; // QWindow scaled
QRect requestedGeometry; // after QPlatformWindow::initialGeometry()
- QRect obtainedGeometry;
+ QPoint obtainedPos;
+ QSize obtainedSize;
QMargins margins;
QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE
int frameX = CW_USEDEFAULT; // Passed on to CreateWindowEx(), including frame.
@@ -139,6 +135,7 @@ public:
unsigned style() const { return GetWindowLongPtr(handle(), GWL_STYLE); }
unsigned exStyle() const { return GetWindowLongPtr(handle(), GWL_EXSTYLE); }
+ static bool isRtlLayout(HWND hwnd);
static QWindowsBaseWindow *baseWindowOf(const QWindow *w);
static HWND handleOf(const QWindow *w);
@@ -221,7 +218,8 @@ public:
HasBorderInFullScreen = 0x200000,
WithinDpiChanged = 0x400000,
VulkanSurface = 0x800000,
- ResizeMoveActive = 0x1000000
+ ResizeMoveActive = 0x1000000,
+ DisableNonClientScaling = 0x2000000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
@@ -262,6 +260,7 @@ public:
QMargins frameMargins() const override;
QMargins fullFrameMargins() const override;
void setFullFrameMargins(const QMargins &newMargins);
+ void updateFullFrameMargins();
void setOpacity(qreal level) override;
void setMask(const QRegion &region) override;
@@ -337,7 +336,8 @@ public:
void alertWindow(int durationMs = 0);
void stopAlertWindow();
- void checkForScreenChanged();
+ enum ScreenChangeMode { FromGeometryChange, FromDpiChange };
+ void checkForScreenChanged(ScreenChangeMode mode = FromGeometryChange);
static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes);
void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch);
@@ -401,18 +401,38 @@ QDebug operator<<(QDebug d, const WINDOWPOS &);
QDebug operator<<(QDebug d, const GUID &guid);
#endif // !QT_NO_DEBUG_STREAM
+static inline void clientToScreen(HWND hwnd, POINT *wP)
+{
+ if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
+ RECT clientArea;
+ GetClientRect(hwnd, &clientArea);
+ wP->x = clientArea.right - wP->x;
+ }
+ ClientToScreen(hwnd, wP);
+}
+
+static inline void screenToClient(HWND hwnd, POINT *wP)
+{
+ ScreenToClient(hwnd, wP);
+ if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
+ RECT clientArea;
+ GetClientRect(hwnd, &clientArea);
+ wP->x = clientArea.right - wP->x;
+ }
+}
+
// ---------- QWindowsGeometryHint inline functions.
QPoint QWindowsGeometryHint::mapToGlobal(HWND hwnd, const QPoint &qp)
{
POINT p = { qp.x(), qp.y() };
- ClientToScreen(hwnd, &p);
+ clientToScreen(hwnd, &p);
return QPoint(p.x, p.y);
}
QPoint QWindowsGeometryHint::mapFromGlobal(const HWND hwnd, const QPoint &qp)
{
POINT p = { qp.x(), qp.y() };
- ScreenToClient(hwnd, &p);
+ screenToClient(hwnd, &p);
return QPoint(p.x, p.y);
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
index 85a931e015..c7c0deab3f 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
@@ -113,6 +113,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
case QAccessible::ValueChanged:
QWindowsUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event));
break;
+ case QAccessible::SelectionAdd:
+ QWindowsUiaMainProvider::notifySelectionChange(event);
+ break;
case QAccessible::TextAttributeChanged:
case QAccessible::TextColumnChanged:
case QAccessible::TextInserted:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index fad83fb165..a427e553f0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -52,6 +52,7 @@
#include "qwindowsuiatableitemprovider.h"
#include "qwindowsuiagridprovider.h"
#include "qwindowsuiagriditemprovider.h"
+#include "qwindowsuiawindowprovider.h"
#include "qwindowscombase.h"
#include "qwindowscontext.h"
#include "qwindowsuiautils.h"
@@ -146,9 +147,33 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
- if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
- // Notifies changes in values of controls supporting the value interface.
+ if (accessible->role() == QAccessible::ComboBox && accessible->childCount() > 0) {
+ QAccessibleInterface *listacc = accessible->child(0);
+ if (listacc && listacc->role() == QAccessible::List) {
+ int count = listacc->childCount();
+ for (int i = 0; i < count; ++i) {
+ QAccessibleInterface *item = listacc->child(i);
+ if (item && item->text(QAccessible::Name) == event->value()) {
+ if (!item->state().selected) {
+ if (QAccessibleActionInterface *actionInterface = item->actionInterface())
+ actionInterface->doAction(QAccessibleActionInterface::toggleAction());
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (event->value().type() == QVariant::String) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
+ // Notifies changes in string values.
+ VARIANT oldVal, newVal;
+ clearVariant(&oldVal);
+ setVariantString(event->value().toString(), &newVal);
+ QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
+ }
+ } else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
+ if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
+ // Notifies changes in values of controls supporting the value interface.
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantDouble(valueInterface->currentValue().toDouble(), &newVal);
@@ -158,6 +183,15 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
}
}
+void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event)
+{
+ if (QAccessibleInterface *accessible = event->accessibleInterface()) {
+ if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
+ QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
+ }
+ }
+}
+
// Notifies changes in text content and selection state of text controls.
void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
{
@@ -230,6 +264,11 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
return UIA_E_ELEMENTNOTAVAILABLE;
switch (idPattern) {
+ case UIA_WindowPatternId:
+ if (accessible->parent() && (accessible->parent()->role() == QAccessible::Application)) {
+ *pRetVal = new QWindowsUiaWindowProvider(id());
+ }
+ break;
case UIA_TextPatternId:
case UIA_TextPattern2Id:
// All text controls.
@@ -319,8 +358,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
- bool clientTopLevel = (accessible->role() == QAccessible::Client)
- && accessible->parent() && (accessible->parent()->role() == QAccessible::Application);
+ bool topLevelWindow = accessible->parent() && (accessible->parent()->role() == QAccessible::Application);
switch (idProp) {
case UIA_ProcessIdPropertyId:
@@ -346,7 +384,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
setVariantString(QStringLiteral("Qt"), pRetVal);
break;
case UIA_ControlTypePropertyId:
- if (clientTopLevel) {
+ if (topLevelWindow) {
// Reports a top-level widget as a window, instead of "custom".
setVariantI4(UIA_WindowControlTypeId, pRetVal);
} else {
@@ -358,10 +396,20 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
setVariantString(accessible->text(QAccessible::Help), pRetVal);
break;
case UIA_HasKeyboardFocusPropertyId:
- setVariantBool(accessible->state().focused, pRetVal);
+ if (topLevelWindow) {
+ // Windows set the active state to true when they are focused
+ setVariantBool(accessible->state().active, pRetVal);
+ } else {
+ setVariantBool(accessible->state().focused, pRetVal);
+ }
break;
case UIA_IsKeyboardFocusablePropertyId:
- setVariantBool(accessible->state().focusable, pRetVal);
+ if (topLevelWindow) {
+ // Windows should always be focusable
+ setVariantBool(true, pRetVal);
+ } else {
+ setVariantBool(accessible->state().focusable, pRetVal);
+ }
break;
case UIA_IsOffscreenPropertyId:
setVariantBool(accessible->state().offscreen, pRetVal);
@@ -391,7 +439,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
break;
case UIA_NamePropertyId: {
QString name = accessible->text(QAccessible::Name);
- if (name.isEmpty() && clientTopLevel)
+ if (name.isEmpty() && topLevelWindow)
name = QCoreApplication::applicationName();
setVariantString(name, pRetVal);
break;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
index 325d5b3de4..df0d60f9c9 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
@@ -68,6 +68,7 @@ public:
static void notifyFocusChange(QAccessibleEvent *event);
static void notifyStateChange(QAccessibleStateChangeEvent *event);
static void notifyValueChange(QAccessibleValueChangeEvent *event);
+ static void notifySelectionChange(QAccessibleEvent *event);
static void notifyTextChange(QAccessibleEvent *event);
// IUnknown
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp
new file mode 100644
index 0000000000..3738aa72ff
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwindowsuiawindowprovider.h"
+#include "qwindowsuiautils.h"
+#include "qwindowscontext.h"
+
+#include <QtGui/qaccessible.h>
+#include <QtGui/private/qwindow_p.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QWindowsUiAutomation;
+
+
+QWindowsUiaWindowProvider::QWindowsUiaWindowProvider(QAccessible::Id id) :
+ QWindowsUiaBaseProvider(id)
+{
+}
+
+QWindowsUiaWindowProvider::~QWindowsUiaWindowProvider()
+{
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::SetVisualState(WindowVisualState state) {
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible || !accessible->window())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ auto window = accessible->window();
+ switch (state) {
+ case WindowVisualState_Normal:
+ window->showNormal();
+ break;
+ case WindowVisualState_Maximized:
+ window->showMaximized();
+ break;
+ case WindowVisualState_Minimized:
+ window->showMinimized();
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::Close() {
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible || !accessible->window())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ accessible->window()->close();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::WaitForInputIdle(int milliseconds, __RPC__out BOOL *pRetVal) {
+ Q_UNUSED(milliseconds);
+ Q_UNUSED(pRetVal);
+ return UIA_E_NOTSUPPORTED;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_CanMaximize(__RPC__out BOOL *pRetVal) {
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible || !accessible->window())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ auto window = accessible->window();
+ auto flags = window->flags();
+
+ *pRetVal = (!(flags & Qt::MSWindowsFixedSizeDialogHint)
+ && (flags & Qt::WindowMaximizeButtonHint)
+ && ((flags & Qt::CustomizeWindowHint)
+ || window->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)));
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_CanMinimize(__RPC__out BOOL *pRetVal) {
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible || !accessible->window())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ *pRetVal = accessible->window()->flags() & Qt::WindowMinimizeButtonHint;
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_IsModal(__RPC__out BOOL *pRetVal) {
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible || !accessible->window())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ *pRetVal = accessible->window()->isModal();
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_WindowVisualState(__RPC__out enum WindowVisualState *pRetVal) {
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible || !accessible->window())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ auto visibility = accessible->window()->visibility();
+ switch (visibility) {
+ case QWindow::FullScreen:
+ case QWindow::Maximized:
+ *pRetVal = WindowVisualState_Maximized;
+ break;
+ case QWindow::Minimized:
+ *pRetVal = WindowVisualState_Minimized;
+ break;
+ default:
+ *pRetVal = WindowVisualState_Normal;
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_WindowInteractionState(__RPC__out enum WindowInteractionState *pRetVal) {
+ Q_UNUSED(pRetVal);
+ return UIA_E_NOTSUPPORTED;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_IsTopmost(__RPC__out BOOL *pRetVal) {
+ Q_UNUSED(pRetVal);
+ return UIA_E_NOTSUPPORTED;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
new file mode 100644
index 0000000000..343fb275f7
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSUIAWINDOWPROVIDER_H
+#define QWINDOWSUIAWINDOWPROVIDER_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwindowsuiabaseprovider.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsUiaWindowProvider : public QWindowsUiaBaseProvider,
+ public QWindowsComBase<IWindowProvider>
+{
+ Q_DISABLE_COPY(QWindowsUiaWindowProvider)
+public:
+ explicit QWindowsUiaWindowProvider(QAccessible::Id id);
+ ~QWindowsUiaWindowProvider() override;
+
+ HRESULT STDMETHODCALLTYPE SetVisualState(WindowVisualState state) override;
+ HRESULT STDMETHODCALLTYPE Close( void) override;
+ HRESULT STDMETHODCALLTYPE WaitForInputIdle(int milliseconds, __RPC__out BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_CanMaximize(__RPC__out BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_CanMinimize(__RPC__out BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_IsModal(__RPC__out BOOL *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_WindowVisualState(__RPC__out WindowVisualState *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_WindowInteractionState(__RPC__out WindowInteractionState *pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_IsTopmost(__RPC__out BOOL *pRetVal) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINDOWSUIAWINDOWPROVIDER_H
diff --git a/src/plugins/platforms/windows/uiautomation/uiautomation.pri b/src/plugins/platforms/windows/uiautomation/uiautomation.pri
index e3071766d9..ee9332e7ea 100644
--- a/src/plugins/platforms/windows/uiautomation/uiautomation.pri
+++ b/src/plugins/platforms/windows/uiautomation/uiautomation.pri
@@ -18,6 +18,7 @@ SOURCES += \
$$PWD/qwindowsuiatableitemprovider.cpp \
$$PWD/qwindowsuiagridprovider.cpp \
$$PWD/qwindowsuiagriditemprovider.cpp \
+ $$PWD/qwindowsuiawindowprovider.cpp \
$$PWD/qwindowsuiautils.cpp
HEADERS += \
@@ -37,7 +38,7 @@ HEADERS += \
$$PWD/qwindowsuiatableitemprovider.h \
$$PWD/qwindowsuiagridprovider.h \
$$PWD/qwindowsuiagriditemprovider.h \
+ $$PWD/qwindowsuiawindowprovider.h \
$$PWD/qwindowsuiautils.h
-mingw: LIBS *= -luuid
-
+mingw: QMAKE_USE *= uuid
diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri
index 7004d7e854..95ba961df1 100644
--- a/src/plugins/platforms/windows/windows.pri
+++ b/src/plugins/platforms/windows/windows.pri
@@ -1,15 +1,21 @@
# Note: OpenGL32 must precede Gdi32 as it overwrites some functions.
-LIBS += -lole32 -luser32 -lwinspool -limm32 -lwinmm -loleaut32
+LIBS += -lwinspool -limm32 -loleaut32
QT_FOR_CONFIG += gui
qtConfig(opengl):!qtConfig(opengles2):!qtConfig(dynamicgl): LIBS *= -lopengl32
-mingw: LIBS *= -luuid
+mingw: QMAKE_USE *= uuid
# For the dialog helpers:
-LIBS += -lshlwapi -lshell32 -ladvapi32 -lwtsapi32
-
-QMAKE_USE_PRIVATE += d3d9/nolink
+LIBS += -lshlwapi -lwtsapi32
+
+QMAKE_USE_PRIVATE += \
+ advapi32 \
+ d3d9/nolink \
+ ole32 \
+ shell32 \
+ user32 \
+ winmm
DEFINES *= QT_NO_CAST_FROM_ASCII QT_NO_FOREACH
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index 174bc7b609..50a3bb41a9 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -8,7 +8,8 @@ QT += \
qtConfig(accessibility): QT += accessibility_support-private
qtConfig(vulkan): QT += vulkan_support-private
-LIBS += -lgdi32 -ldwmapi
+LIBS += -ldwmapi
+QMAKE_USE_PRIVATE += gdi32
include(windows.pri)
diff --git a/src/plugins/platforms/winrt/qwinrttheme.cpp b/src/plugins/platforms/winrt/qwinrttheme.cpp
index 283825a880..0e1504b1c1 100644
--- a/src/plugins/platforms/winrt/qwinrttheme.cpp
+++ b/src/plugins/platforms/winrt/qwinrttheme.cpp
@@ -44,6 +44,8 @@
#include <QtCore/qfunctions_winrt.h>
#include <QtGui/QPalette>
+#include <QtFontDatabaseSupport/private/qwinrtfontdatabase_p.h>
+
#include <wrl.h>
#include <windows.ui.h>
#include <windows.ui.viewmanagement.h>
@@ -96,7 +98,13 @@ static IUISettings *uiSettings()
class QWinRTThemePrivate
{
public:
+ QWinRTThemePrivate()
+ : monospaceFont(QWinRTFontDatabase::familyForStyleHint(QFont::Monospace))
+ {
+ }
+
QPalette palette;
+ QFont monospaceFont;
};
static inline QColor fromColor(const Color &color)
@@ -321,4 +329,14 @@ const QPalette *QWinRTTheme::palette(Palette type) const
return QPlatformTheme::palette(type);
}
+const QFont *QWinRTTheme::font(QPlatformTheme::Font type) const
+{
+ Q_D(const QWinRTTheme);
+ qCDebug(lcQpaTheme) << __FUNCTION__ << type;
+ if (type == QPlatformTheme::FixedFont)
+ return &d->monospaceFont;
+
+ return QPlatformTheme::font(type);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/winrt/qwinrttheme.h b/src/plugins/platforms/winrt/qwinrttheme.h
index cc5fc851e7..acf5a54a94 100644
--- a/src/plugins/platforms/winrt/qwinrttheme.h
+++ b/src/plugins/platforms/winrt/qwinrttheme.h
@@ -58,6 +58,7 @@ public:
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
const QPalette *palette(Palette type = SystemPalette) const override;
+ const QFont *font(Font type = SystemFont) const override;
static QVariant styleHint(QPlatformIntegration::StyleHint hint);
QVariant themeHint(ThemeHint hint) const override;
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 43132a1a76..43dc8f074c 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -8,8 +8,7 @@ QT += \
DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__
-LIBS += -lws2_32
-QMAKE_USE_PRIVATE += d3d11
+QMAKE_USE_PRIVATE += d3d11 ws2_32
SOURCES = \
main.cpp \
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
index 476de6d1e5..4adf662152 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
@@ -270,7 +270,9 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
// ES does not support any format option
m_format.setOptions(QSurfaceFormat::FormatOptions());
}
-
+ // Robustness must match that of the shared context.
+ if (share && share->format().testOption(QSurfaceFormat::ResetNotification))
+ m_format.setOption(QSurfaceFormat::ResetNotification);
Q_ASSERT(glVersions.count() > 0);
for (int i = 0; !m_context && i < glVersions.count(); i++) {
diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
index b1ce39f363..f86bedbdcd 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
@@ -2017,7 +2017,7 @@ QImage QX11PlatformPixmap::toImage(const QXImageWrapper &xiWrapper, const QRect
}
} else if (xi->bits_per_pixel == d) { // compatible depth
char *xidata = xi->data; // copy each scanline
- int bpl = qMin(image.bytesPerLine(),xi->bytes_per_line);
+ int bpl = qMin(int(image.bytesPerLine()),xi->bytes_per_line);
for (int y=0; y<xi->height; y++) {
memcpy(image.scanLine(y), xidata, bpl);
xidata += xi->bytes_per_line;
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index e4da207b00..bc09fe2f91 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -240,6 +240,10 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting)
} else if (name.contains("uc-logic") && isTablet) {
tabletData.pointerType = QTabletEvent::Pen;
dbgType = QLatin1String("pen");
+ } else if (name.contains("ugee")) {
+ isTablet = true;
+ tabletData.pointerType = QTabletEvent::Pen;
+ dbgType = QLatin1String("pen");
} else {
isTablet = false;
}
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index aa329d8cb7..1ce947165d 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -202,7 +202,7 @@ void QXcbDrag::startDrag()
if (connection()->mouseGrabber() == nullptr)
shapedPixmapWindow()->setMouseGrabEnabled(true);
- auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), initiatorWindow);
+ auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), initiatorWindow.data());
move(nativePixelPos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
}
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index a70c7db923..95ca40fc95 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -550,6 +550,7 @@ void QXcbIntegration::beep() const
return;
xcb_connection_t *connection = static_cast<QXcbScreen *>(screen)->xcb_connection();
xcb_bell(connection, 0);
+ xcb_flush(connection);
}
bool QXcbIntegration::nativePaintingEnabled() const
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index 899081e752..81b889a80f 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -636,13 +636,13 @@ static void dumpNativeWindowsRecursion(const QXcbConnection *connection, xcb_win
const QChar oldPadChar =str.padChar();
str.setFieldWidth(8);
str.setPadChar(QLatin1Char('0'));
- str << hex << window;
+ str << Qt::hex << window;
str.setFieldWidth(oldFieldWidth);
str.setPadChar(oldPadChar);
- str << dec << " \""
+ str << Qt::dec << " \""
<< QXcbWindow::windowTitle(connection, window) << "\" "
- << geom.width() << 'x' << geom.height() << forcesign << geom.x() << geom.y()
- << noforcesign << '\n';
+ << geom.width() << 'x' << geom.height() << Qt::forcesign << geom.x() << geom.y()
+ << Qt::noforcesign << '\n';
auto reply = Q_XCB_REPLY(xcb_query_tree, conn, window);
if (reply) {
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 0fa0e8cd7b..bfc105a040 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -915,7 +915,7 @@ QByteArray QXcbScreen::getEdid() const
static inline void formatRect(QDebug &debug, const QRect r)
{
debug << r.width() << 'x' << r.height()
- << forcesign << r.x() << r.y() << noforcesign;
+ << Qt::forcesign << r.x() << r.y() << Qt::noforcesign;
}
static inline void formatSizeF(QDebug &debug, const QSizeF s)
@@ -929,7 +929,7 @@ QDebug operator<<(QDebug debug, const QXcbScreen *screen)
debug.nospace();
debug << "QXcbScreen(" << (const void *)screen;
if (screen) {
- debug << fixed << qSetRealNumberPrecision(1);
+ debug << Qt::fixed << qSetRealNumberPrecision(1);
debug << ", name=" << screen->name();
debug << ", geometry=";
formatRect(debug, screen->geometry());
@@ -947,7 +947,7 @@ QDebug operator<<(QDebug debug, const QXcbScreen *screen)
debug << "), orientation=" << screen->orientation();
debug << ", depth=" << screen->depth();
debug << ", refreshRate=" << screen->refreshRate();
- debug << ", root=" << hex << screen->root();
+ debug << ", root=" << Qt::hex << screen->root();
debug << ", windowManagerName=" << screen->windowManagerName();
}
debug << ')';
diff --git a/src/plugins/printsupport/windows/windows.pro b/src/plugins/printsupport/windows/windows.pro
index 06694fb7fe..6ca601b2a4 100644
--- a/src/plugins/printsupport/windows/windows.pro
+++ b/src/plugins/printsupport/windows/windows.pro
@@ -18,7 +18,8 @@ HEADERS += \
OTHER_FILES += windows.json
-LIBS += -lwinspool -lcomdlg32 -lgdi32 -luser32
+LIBS += -lwinspool -lcomdlg32
+QMAKE_USE_PRIVATE += user32 gdi32
PLUGIN_TYPE = printsupport
PLUGIN_CLASS_NAME = QWindowsPrinterSupportPlugin
diff --git a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp
index 390f05c7aa..b7bcd044ab 100644
--- a/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp
+++ b/src/plugins/sqldrivers/sqlite2/qsql_sqlite2.cpp
@@ -43,7 +43,6 @@
#include <qvariant.h>
#include <qdatetime.h>
#include <qfile.h>
-#include <qregexp.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
diff --git a/src/plugins/sqldrivers/sqlite2/smain.cpp b/src/plugins/sqldrivers/sqlite2/smain.cpp
index 3a5734f8c9..7d971d6e5a 100644
--- a/src/plugins/sqldrivers/sqlite2/smain.cpp
+++ b/src/plugins/sqldrivers/sqlite2/smain.cpp
@@ -43,6 +43,7 @@
QT_BEGIN_NAMESPACE
+// ### Qt6: remove, obsolete since 5.14
class QSQLite2DriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
diff --git a/src/plugins/sqldrivers/tds/main.cpp b/src/plugins/sqldrivers/tds/main.cpp
index 4aa1444608..18efb22ea4 100644
--- a/src/plugins/sqldrivers/tds/main.cpp
+++ b/src/plugins/sqldrivers/tds/main.cpp
@@ -50,6 +50,7 @@
QT_BEGIN_NAMESPACE
+// ### Qt6: remove, obsolete since 4.7
class QTDSDriverPlugin : public QSqlDriverPlugin
{
Q_OBJECT
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index d0e05c1e20..392368a40b 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -150,6 +150,16 @@ static QWindow *qt_getWindow(const QWidget *widget)
QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
@implementation NotificationReceiver
+{
+ QMacStylePrivate *privateStyle;
+}
+
+- (instancetype)initWithPrivateStyle:(QMacStylePrivate *)style
+{
+ if (self = [super init])
+ privateStyle = style;
+ return self;
+}
- (void)scrollBarStyleDidChange:(NSNotification *)notification
{
@@ -162,6 +172,23 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
for (const auto &o : QMacStylePrivate::scrollBars)
QCoreApplication::sendEvent(o, &event);
}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
+ change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context
+{
+ Q_UNUSED(keyPath);
+ Q_UNUSED(object);
+ Q_UNUSED(change);
+ Q_UNUSED(context);
+
+ Q_ASSERT([keyPath isEqualToString:@"effectiveAppearance"]);
+ Q_ASSERT(object == NSApp);
+
+ for (NSView *b : privateStyle->cocoaControls)
+ [b release];
+ privateStyle->cocoaControls.clear();
+}
+
@end
@interface QT_MANGLE_NAMESPACE(QIndeterminateProgressIndicator) : NSProgressIndicator
@@ -447,6 +474,42 @@ static const int toolButtonArrowMargin = 2;
static const qreal focusRingWidth = 3.5;
+// An application can force 'Aqua' theme while the system theme is one of
+// the 'Dark' variants. Since in Qt we sometimes use NSControls and even
+// NSCells directly without attaching them to any view hierarchy, we have
+// to set NSAppearance.currentAppearance to 'Aqua' manually, to make sure
+// the correct rendering path is triggered. Apple recommends us to un-set
+// the current appearance back after we finished with drawing. This is what
+// AppearanceSync is for.
+
+class AppearanceSync {
+public:
+ AppearanceSync()
+ {
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
+ && !qt_mac_applicationIsInDarkMode()) {
+ auto requiredAppearanceName = NSApplication.sharedApplication.effectiveAppearance.name;
+ if (![NSAppearance.currentAppearance.name isEqualToString:requiredAppearanceName]) {
+ previous = NSAppearance.currentAppearance;
+ NSAppearance.currentAppearance = [NSAppearance appearanceNamed:requiredAppearanceName];
+ }
+ }
+#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+ }
+
+ ~AppearanceSync()
+ {
+ if (previous)
+ NSAppearance.currentAppearance = previous;
+ }
+
+private:
+ NSAppearance *previous = nil;
+
+ Q_DISABLE_COPY(AppearanceSync)
+};
+
static bool setupScroller(NSScroller *scroller, const QStyleOptionSlider *sb)
{
const qreal length = sb->maximum - sb->minimum + sb->pageStep;
@@ -1156,66 +1219,6 @@ static QStyleHelper::WidgetSizePolicy qt_aqua_guess_size(const QWidget *widg, QS
}
#endif
-static NSColor *qt_convertColorForContext(CGContextRef context, NSColor *color)
-{
- Q_ASSERT(color);
- Q_ASSERT(context);
-
- CGColorSpaceRef targetCGColorSpace = CGBitmapContextGetColorSpace(context);
- NSColorSpace *targetNSColorSpace = [[NSColorSpace alloc] initWithCGColorSpace:targetCGColorSpace];
- NSColor *adjusted = [color colorUsingColorSpace:targetNSColorSpace];
- [targetNSColorSpace release];
-
- return adjusted;
-}
-
-static NSColor *qt_colorForContext(CGContextRef context, const CGFloat (&rgba)[4])
-{
- Q_ASSERT(context);
-
- auto colorSpace = CGBitmapContextGetColorSpace(context);
- if (!colorSpace)
- return nil;
-
- return qt_convertColorForContext(context, [NSColor colorWithSRGBRed:rgba[0] green:rgba[1] blue:rgba[2] alpha:rgba[3]]);
-}
-
-static void qt_drawDisclosureButton(CGContextRef context, NSInteger state, bool selected, CGRect rect)
-{
- Q_ASSERT(context);
-
- static const CGFloat gray[] = {0.55, 0.55, 0.55, 0.97};
- static const CGFloat white[] = {1.0, 1.0, 1.0, 0.9};
-
- NSColor *fillColor = qt_colorForContext(context, selected ? white : gray);
- [fillColor setFill];
-
- if (state == NSOffState) {
- static NSBezierPath *triangle = [[NSBezierPath alloc] init];
- [triangle removeAllPoints];
- // In off state, a disclosure button is an equilateral triangle
- // ('pointing' to the right) with a bound rect that can be described
- // as NSMakeRect(0, 0, 8, 9). Inside the 'rect' it's translated by
- // (2, 4).
- [triangle moveToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4)];
- [triangle lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4 + 9)];
- [triangle lineToPoint:NSMakePoint(rect.origin.x + 2 + 8, rect.origin.y + 4 + 4.5)];
- [triangle closePath];
- [triangle fill];
- } else {
- static NSBezierPath *openTriangle = [[NSBezierPath alloc] init];
- [openTriangle removeAllPoints];
- // In 'on' state, the button is an equilateral triangle (looking down)
- // with the bounding rect NSMakeRect(0, 0, 9, 8). Inside the 'rect'
- // it's translated by (1, 4).
- [openTriangle moveToPoint:NSMakePoint(rect.origin.x + 1, rect.origin.y + 4 + 8)];
- [openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 9, rect.origin.y + 4 + 8)];
- [openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 4.5, rect.origin.y + 4)];
- [openTriangle closePath];
- [openTriangle fill];
- }
-}
-
void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const
{
QPainterPath focusRingPath;
@@ -2092,11 +2095,17 @@ QMacStyle::QMacStyle()
Q_D(QMacStyle);
QMacAutoReleasePool pool;
- d->receiver = [[NotificationReceiver alloc] init];
+ d->receiver = [[NotificationReceiver alloc] initWithPrivateStyle:d];
[[NSNotificationCenter defaultCenter] addObserver:d->receiver
selector:@selector(scrollBarStyleDidChange:)
name:NSPreferredScrollerStyleDidChangeNotification
object:nil];
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
+ [NSApplication.sharedApplication addObserver:d->receiver forKeyPath:@"effectiveAppearance"
+ options:NSKeyValueObservingOptionNew context:nullptr];
+ }
+#endif
}
QMacStyle::~QMacStyle()
@@ -2105,6 +2114,10 @@ QMacStyle::~QMacStyle()
QMacAutoReleasePool pool;
[[NSNotificationCenter defaultCenter] removeObserver:d->receiver];
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
+ [NSApplication.sharedApplication removeObserver:d->receiver forKeyPath:@"effectiveAppearance"];
+#endif
[d->receiver release];
}
@@ -2978,6 +2991,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
const QWidget *w) const
{
Q_D(const QMacStyle);
+ const AppearanceSync appSync;
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
@@ -3301,15 +3315,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
CGContextScaleCTM(cg, 1, -1);
CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave && !qt_mac_applicationIsInDarkMode()) {
- // When the real system theme is one of the 'Dark' themes, and an application forces the 'Aqua' theme,
- // under some conditions (see QTBUG-74515 for more details) NSButtonCell seems to select the 'Dark'
- // code path and is becoming transparent, thus 'invisible' on the white background. To workaround this,
- // we draw the disclose triangle manually:
- qt_drawDisclosureButton(cg, triangleCell.state, (opt->state & State_Selected) && viewHasFocus, rect);
- } else {
- [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
- }
+ [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
+
d->restoreNSGraphicsContext(cg);
break; }
@@ -3510,6 +3517,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
const QWidget *w) const
{
Q_D(const QMacStyle);
+ const AppearanceSync sync;
QMacCGContext cg(p);
QWindow *window = w && w->window() ? w->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
@@ -4319,12 +4327,15 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
alpha:pc.alphaF()];
s = qt_mac_removeMnemonics(s);
- const auto textRect = CGRectMake(xpos, yPos, mi->rect.width() - xm - tabwidth + 1, mi->rect.height());
QMacCGContext cgCtx(p);
d->setupNSGraphicsContext(cgCtx, YES);
- [s.toNSString() drawInRect:textRect
+ // Draw at point instead of in rect, as the rect we've computed for the menu item
+ // is based on the font metrics we got from HarfBuzz, so we may risk having CoreText
+ // line-break the string if it doesn't fit the given rect. It's better to draw outside
+ // the rect and possibly overlap something than to have part of the text disappear.
+ [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
@@ -5100,6 +5111,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const QWidget *widget) const
{
Q_D(const QMacStyle);
+ const AppearanceSync sync;
QMacCGContext cg(p);
QWindow *window = widget && widget->window() ? widget->window()->windowHandle() : nullptr;
d->resolveCurrentNSView(window);
@@ -6154,8 +6166,9 @@ QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt,
switch (ct) {
#if QT_CONFIG(spinbox)
case CT_SpinBox:
- if (qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
- const int buttonWidth = 20; // FIXME Use subControlRect()
+ if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ const bool hasButtons = (vopt->buttonSymbols != QAbstractSpinBox::NoButtons);
+ const int buttonWidth = hasButtons ? proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp, widget).width() : 0;
sz += QSize(buttonWidth, 0);
}
break;
diff --git a/src/plugins/styles/windowsvista/windowsvista.pro b/src/plugins/styles/windowsvista/windowsvista.pro
index f82bcfc91b..c08db7f533 100644
--- a/src/plugins/styles/windowsvista/windowsvista.pro
+++ b/src/plugins/styles/windowsvista/windowsvista.pro
@@ -10,7 +10,7 @@ SOURCES += qwindowsvistastyle.cpp
HEADERS += qwindowsxpstyle_p.h qwindowsxpstyle_p_p.h
SOURCES += qwindowsxpstyle.cpp
-LIBS_PRIVATE += -lgdi32 -luser32
+QMAKE_USE_PRIVATE += user32 gdi32
# DEFINES/LIBS needed for qwizard_win.cpp and the styles
include(../../../widgets/kernel/win.pri)