Merge remote-tracking branch 'origin/5.13' into dev
Conflicts: src/corelib/global/qfloat16.cpp src/corelib/global/qfloat16.h src/plugins/platforms/windows/qwindowswindow.cpp Change-Id: I0938aaa6a9771f55e48c95ed29f6f5291431b947
This commit is contained in:
commit
c0359bd3c3
@ -69,11 +69,11 @@ int main(int argc, char *argv[])
|
||||
QSurfaceFormat fmt;
|
||||
fmt.setDepthBufferSize(24);
|
||||
|
||||
// Request OpenGL 3.3 compatibility or OpenGL ES 3.0.
|
||||
// Request OpenGL 3.3 core or OpenGL ES 3.0.
|
||||
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) {
|
||||
qDebug("Requesting 3.3 compatibility context");
|
||||
qDebug("Requesting 3.3 core context");
|
||||
fmt.setVersion(3, 3);
|
||||
fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
|
||||
fmt.setProfile(QSurfaceFormat::CoreProfile);
|
||||
} else {
|
||||
qDebug("Requesting 3.0 context");
|
||||
fmt.setVersion(3, 0);
|
||||
|
@ -211,10 +211,10 @@ CMAKE_INTERFACE_QT5_MODULE_DEPS = $$join(aux_lib_deps, ";")
|
||||
|
||||
mac {
|
||||
!isEmpty(CMAKE_STATIC_TYPE) {
|
||||
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.a
|
||||
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}.a
|
||||
CMAKE_LIB_FILE_LOCATION_RELEASE = lib$${CMAKE_QT_STEM}.a
|
||||
|
||||
CMAKE_PRL_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.prl
|
||||
CMAKE_PRL_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}.prl
|
||||
CMAKE_PRL_FILE_LOCATION_RELEASE = lib$${CMAKE_QT_STEM}.prl
|
||||
} else {
|
||||
qt_framework {
|
||||
@ -222,7 +222,7 @@ mac {
|
||||
CMAKE_LIB_FILE_LOCATION_RELEASE = $${CMAKE_QT_STEM}.framework/$${CMAKE_QT_STEM}
|
||||
CMAKE_BUILD_IS_FRAMEWORK = "true"
|
||||
} else {
|
||||
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.$$eval(QT.$${MODULE}.VERSION).dylib
|
||||
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}.$$eval(QT.$${MODULE}.VERSION).dylib
|
||||
CMAKE_LIB_FILE_LOCATION_RELEASE = lib$${CMAKE_QT_STEM}.$$eval(QT.$${MODULE}.VERSION).dylib
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ breakpad {
|
||||
}
|
||||
|
||||
c++17: CONFIG += c++1z
|
||||
c++latest: CONFIG *= c++2a c++1z c++14 c++11
|
||||
|
||||
!c++11:!c++14:!c++1z:!c++2a {
|
||||
# Qt requires C++11 since 5.7, check if we need to force a compiler option
|
||||
|
@ -977,6 +977,9 @@
|
||||
\row \li c++2a \li C++2a support is enabled. This option has no effect if
|
||||
the compiler does not support C++2a, or can't select the C++ standard.
|
||||
By default, support is disabled.
|
||||
\row \li c++latest \li Support for the latest C++ language standard is
|
||||
enabled that is supported by the compiler. By default, this option is
|
||||
disabled.
|
||||
\row \li strict_c++ \li Disables support for C++ compiler extensions.
|
||||
By default, they are enabled.
|
||||
\row \li depend_includepath \li Appending the value of INCLUDEPATH to
|
||||
|
@ -49,6 +49,7 @@ on big endian machines, or a byte-by-byte read if the endianess is unknown.
|
||||
|
||||
|
||||
#include "PMurHash.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* I used ugly type names in the header to avoid potential conflicts with
|
||||
* application or system typedefs & defines. Since I'm not including any more
|
||||
@ -208,7 +209,7 @@ void PMurHash32_Process(uint32_t *ph1, uint32_t *pcarry, const void *key, int le
|
||||
/* This CPU does not handle unaligned word access */
|
||||
|
||||
/* Consume enough so that the next data byte is word aligned */
|
||||
int i = -(long)ptr & 3;
|
||||
int i = -(intptr_t)ptr & 3;
|
||||
if(i && i <= len) {
|
||||
DOBYTES(i, h1, c, n, ptr, len);
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ package org.qtproject.qt5.android;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -73,7 +74,7 @@ public class EditContextView extends LinearLayout implements View.OnClickListene
|
||||
m_buttonId = stringId;
|
||||
setText(stringId);
|
||||
setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
|
||||
setGravity(Gravity.CENTER);
|
||||
setTextColor(getResources().getColor(R.color.widget_edittext_dark));
|
||||
EditContextView.this.setBackground(getResources().getDrawable(R.drawable.editbox_background_normal));
|
||||
@ -81,6 +82,8 @@ public class EditContextView extends LinearLayout implements View.OnClickListene
|
||||
int hPadding = (int)(16 * scale + 0.5f);
|
||||
int vPadding = (int)(8 * scale + 0.5f);
|
||||
setPadding(hPadding, vPadding, hPadding, vPadding);
|
||||
setSingleLine();
|
||||
setEllipsize(TextUtils.TruncateAt.END);
|
||||
setOnClickListener(EditContextView.this);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
From e7ff4aa4ef2221aa02d39bdead7f35008016994e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin@martin.st>
|
||||
Date: Fri, 26 Apr 2019 14:57:01 +0300
|
||||
Subject: [PATCH] ANGLE: Backport fix for compilation on mingw/64bit with clang
|
||||
|
||||
This backports the following upstream fix from angle:
|
||||
https://github.com/google/angle/commit/63cc351fbad06c6241d1c7372fe76f74e1d09a10
|
||||
---
|
||||
.../angle/src/common/third_party/smhasher/src/PMurHash.cpp | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp b/src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp
|
||||
index 071bc31539..93b48713cd 100644
|
||||
--- a/src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp
|
||||
+++ b/src/3rdparty/angle/src/common/third_party/smhasher/src/PMurHash.cpp
|
||||
@@ -49,6 +49,7 @@ on big endian machines, or a byte-by-byte read if the endianess is unknown.
|
||||
|
||||
|
||||
#include "PMurHash.h"
|
||||
+#include <stdint.h>
|
||||
|
||||
/* I used ugly type names in the header to avoid potential conflicts with
|
||||
* application or system typedefs & defines. Since I'm not including any more
|
||||
@@ -208,7 +209,7 @@ void PMurHash32_Process(uint32_t *ph1, uint32_t *pcarry, const void *key, int le
|
||||
/* This CPU does not handle unaligned word access */
|
||||
|
||||
/* Consume enough so that the next data byte is word aligned */
|
||||
- int i = -(long)ptr & 3;
|
||||
+ int i = -(intptr_t)ptr & 3;
|
||||
if(i && i <= len) {
|
||||
DOBYTES(i, h1, c, n, ptr, len);
|
||||
}
|
||||
--
|
||||
2.20.1 (Apple Git-117)
|
||||
|
@ -66,6 +66,19 @@ QT_BEGIN_NAMESPACE
|
||||
\since 5.9
|
||||
*/
|
||||
|
||||
/*!
|
||||
\macro QT_NO_FLOAT16_OPERATORS
|
||||
\relates <QFloat16>
|
||||
\since 5.12.4
|
||||
|
||||
Defining this macro disables the arithmetic operators for qfloat16.
|
||||
|
||||
This is only necessary on Visual Studio 2017 (and earlier) when including
|
||||
\c {<QFloat16>} and \c{<bitset>} in the same translation unit, which would
|
||||
otherwise cause a compilation error due to a toolchain bug (see
|
||||
[QTBUG-72073]).
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn bool qIsInf(qfloat16 f)
|
||||
\relates <QFloat16>
|
||||
|
@ -106,7 +106,9 @@ private:
|
||||
Q_CORE_EXPORT static const quint32 shifttable[];
|
||||
|
||||
friend bool qIsNull(qfloat16 f) noexcept;
|
||||
#if !defined(QT_NO_FLOAT16_OPERATORS)
|
||||
friend qfloat16 operator-(qfloat16 a) noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(qfloat16, Q_PRIMITIVE_TYPE);
|
||||
@ -191,6 +193,7 @@ inline qfloat16::operator float() const noexcept
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(QT_NO_FLOAT16_OPERATORS)
|
||||
inline qfloat16 operator-(qfloat16 a) noexcept
|
||||
{
|
||||
qfloat16 f;
|
||||
@ -272,6 +275,7 @@ QF16_MAKE_BOOL_OP_INT(!=)
|
||||
#undef QF16_MAKE_BOOL_OP_INT
|
||||
|
||||
QT_WARNING_POP
|
||||
#endif // QT_NO_FLOAT16_OPERATORS
|
||||
|
||||
/*!
|
||||
\internal
|
||||
|
@ -628,7 +628,7 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename PointerToMemberFunction> QMetaObject::Connection QTimer::callOnTimeout(const QObject *receiver, PointerToMemberFunction slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
|
||||
\fn template <typename MemberFunction> QMetaObject::Connection QTimer::callOnTimeout(const QObject *receiver, MemberFunction *slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
|
||||
\since 5.12
|
||||
\overload callOnTimeout()
|
||||
|
||||
|
@ -100,8 +100,8 @@ public:
|
||||
QMetaObject::Connection callOnTimeout(Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
|
||||
template <typename Functor>
|
||||
QMetaObject::Connection callOnTimeout(const QObject *context, Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
|
||||
template <typename PointerToMemberFunction>
|
||||
QMetaObject::Connection callOnTimeout(const QObject *receiver, PointerToMemberFunction slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
|
||||
template <typename MemberFunction>
|
||||
QMetaObject::Connection callOnTimeout(const QObject *receiver, MemberFunction *slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
|
||||
#else
|
||||
// singleShot to a QObject slot
|
||||
template <typename Duration, typename Func1>
|
||||
|
@ -58,7 +58,6 @@ static inline uchar hexdig(uint u)
|
||||
|
||||
static QByteArray escapedString(const QString &s)
|
||||
{
|
||||
const uchar replacement = '?';
|
||||
QByteArray ba(s.length(), Qt::Uninitialized);
|
||||
|
||||
uchar *cursor = reinterpret_cast<uchar *>(const_cast<char *>(ba.constData()));
|
||||
@ -111,9 +110,14 @@ static QByteArray escapedString(const QString &s)
|
||||
} else {
|
||||
*cursor++ = (uchar)u;
|
||||
}
|
||||
} else {
|
||||
if (QUtf8Functions::toUtf8<QUtf8BaseTraits>(u, cursor, src, end) < 0)
|
||||
*cursor++ = replacement;
|
||||
} else if (QUtf8Functions::toUtf8<QUtf8BaseTraits>(u, cursor, src, end) < 0) {
|
||||
// failed to get valid utf8 use JSON escape sequence
|
||||
*cursor++ = '\\';
|
||||
*cursor++ = 'u';
|
||||
*cursor++ = hexdig(u>>12 & 0x0f);
|
||||
*cursor++ = hexdig(u>>8 & 0x0f);
|
||||
*cursor++ = hexdig(u>>4 & 0x0f);
|
||||
*cursor++ = hexdig(u & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,14 +65,19 @@
|
||||
|
||||
\section1 Thread-Safety
|
||||
|
||||
QSharedPointer and QWeakPointer are thread-safe and operate
|
||||
atomically on the pointer value. Different threads can also access
|
||||
the QSharedPointer or QWeakPointer pointing to the same object at
|
||||
the same time without need for locking mechanisms.
|
||||
QSharedPointer and QWeakPointer are reentrant classes. This means that, in
|
||||
general, a given QSharedPointer or QWeakPointer object \b{cannot} be
|
||||
accessed by multiple threads at the same time without synchronization.
|
||||
|
||||
It should be noted that, while the pointer value can be accessed
|
||||
in this manner, QSharedPointer and QWeakPointer provide no
|
||||
guarantee about the object being pointed to. Thread-safety and
|
||||
Different QSharedPointer and QWeakPointer objects can safely be accessed
|
||||
by multiple threads at the same time. This includes the case where they
|
||||
hold pointers to the same object; the reference counting mechanism
|
||||
is atomic, and no manual synchronization is required.
|
||||
|
||||
It should be noted that, while the pointer value can be accessed in this
|
||||
manner (that is, by multiple threads at the same time, without
|
||||
synchronization), QSharedPointer and QWeakPointer provide no guarantee
|
||||
about the object being pointed to. The specific thread-safety and
|
||||
reentrancy rules for that object still apply.
|
||||
|
||||
\section1 Other Pointer Classes
|
||||
|
@ -29,7 +29,7 @@
|
||||
world's languages, with the largest and most extensive standard repository of locale data
|
||||
available.",
|
||||
"Homepage": "http://cldr.unicode.org/",
|
||||
"Version": "v34",
|
||||
"Version": "v35.1",
|
||||
"License": "// as specified in https://spdx.org/licenses/Unicode-DFS-2016.html",
|
||||
"License": "Unicode License Agreement - Data Files and Software (2016)",
|
||||
"LicenseId": "Unicode-DFS-2016",
|
||||
|
@ -41,7 +41,9 @@
|
||||
#include "qguiapplication.h"
|
||||
#include "qscreen.h"
|
||||
#include "qplatformintegration.h"
|
||||
#include "qplatformwindow.h"
|
||||
#include "private/qscreen_p.h"
|
||||
#include <private/qguiapplication_p.h>
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
@ -376,6 +378,46 @@ QPoint QHighDpiScaling::mapPositionFromNative(const QPoint &pos, const QPlatform
|
||||
return (pos - topLeft) / scaleFactor + topLeft;
|
||||
}
|
||||
|
||||
QPoint QHighDpiScaling::mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window)
|
||||
{
|
||||
QPoint globalPosCandidate = pos + windowGlobalPosition;
|
||||
if (QGuiApplicationPrivate::screen_list.size() <= 1)
|
||||
return globalPosCandidate;
|
||||
|
||||
// The global position may be outside device independent screen geometry
|
||||
// in cases where a window spans screens. Detect this case and map via
|
||||
// native coordinates to the correct screen.
|
||||
auto currentScreen = window->screen();
|
||||
if (currentScreen && !currentScreen->geometry().contains(globalPosCandidate)) {
|
||||
auto nativeGlobalPos = QHighDpi::toNativePixels(globalPosCandidate, currentScreen);
|
||||
if (auto actualPlatformScreen = currentScreen->handle()->screenForPosition(nativeGlobalPos))
|
||||
return QHighDpi::fromNativePixels(nativeGlobalPos, actualPlatformScreen->screen());
|
||||
}
|
||||
|
||||
return globalPosCandidate;
|
||||
}
|
||||
|
||||
QPoint QHighDpiScaling::mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window)
|
||||
{
|
||||
QPoint windowPosCandidate = pos - windowGlobalPosition;
|
||||
if (QGuiApplicationPrivate::screen_list.size() <= 1)
|
||||
return windowPosCandidate;
|
||||
|
||||
// Device independent global (screen) space may discontiguous when high-dpi scaling
|
||||
// is active. This means that the normal subtracting of the window global position from the
|
||||
// position-to-be-mapped may not work in cases where a window spans multiple screens.
|
||||
// Map both positions to native global space (using the correct screens), subtract there,
|
||||
// and then map the difference back using the scale factor for the window.
|
||||
QScreen *posScreen = QGuiApplication::screenAt(pos);
|
||||
if (posScreen && posScreen != window->screen()) {
|
||||
QPoint nativePos = QHighDpi::toNativePixels(pos, posScreen);
|
||||
QPoint windowNativePos = window->handle()->geometry().topLeft();
|
||||
return QHighDpi::fromNativeLocalPosition(nativePos - windowNativePos, window);
|
||||
}
|
||||
|
||||
return windowPosCandidate;
|
||||
}
|
||||
|
||||
qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen)
|
||||
{
|
||||
qreal factor = qreal(1.0);
|
||||
|
@ -83,8 +83,10 @@ public:
|
||||
static qreal factor(const QPlatformScreen *platformScreen);
|
||||
static QPoint origin(const QScreen *screen);
|
||||
static QPoint origin(const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen);
|
||||
static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
|
||||
static QPoint mapPositionFromGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window);
|
||||
static QDpi logicalDpi();
|
||||
|
||||
private:
|
||||
|
@ -1682,9 +1682,9 @@ void QWindow::setGeometry(const QRect &rect)
|
||||
chicken and egg problem here: we cannot convert to native coordinates
|
||||
before we know which screen we are on.
|
||||
*/
|
||||
QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry)
|
||||
QScreen *QWindowPrivate::screenForGeometry(const QRect &newGeometry) const
|
||||
{
|
||||
Q_Q(QWindow);
|
||||
Q_Q(const QWindow);
|
||||
QScreen *currentScreen = q->screen();
|
||||
QScreen *fallback = currentScreen;
|
||||
QPoint center = newGeometry.center();
|
||||
@ -2559,6 +2559,10 @@ QPoint QWindow::mapToGlobal(const QPoint &pos) const
|
||||
&& (d->platformWindow->isForeignWindow() || d->platformWindow->isEmbedded())) {
|
||||
return QHighDpi::fromNativeLocalPosition(d->platformWindow->mapToGlobal(QHighDpi::toNativeLocalPosition(pos, this)), this);
|
||||
}
|
||||
|
||||
if (QHighDpiScaling::isActive())
|
||||
return QHighDpiScaling::mapPositionToGlobal(pos, d->globalPosition(), this);
|
||||
|
||||
return pos + d->globalPosition();
|
||||
}
|
||||
|
||||
@ -2579,6 +2583,10 @@ QPoint QWindow::mapFromGlobal(const QPoint &pos) const
|
||||
&& (d->platformWindow->isForeignWindow() || d->platformWindow->isEmbedded())) {
|
||||
return QHighDpi::fromNativeLocalPosition(d->platformWindow->mapFromGlobal(QHighDpi::toNativeLocalPosition(pos, this)), this);
|
||||
}
|
||||
|
||||
if (QHighDpiScaling::isActive())
|
||||
return QHighDpiScaling::mapPositionFromGlobal(pos, d->globalPosition(), this);
|
||||
|
||||
return pos - d->globalPosition();
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ public:
|
||||
void connectToScreen(QScreen *topLevelScreen);
|
||||
void disconnectFromScreen();
|
||||
void emitScreenChangedRecursion(QScreen *newScreen);
|
||||
QScreen *screenForGeometry(const QRect &rect);
|
||||
QScreen *screenForGeometry(const QRect &rect) const;
|
||||
void setTransientParent(QWindow *parent);
|
||||
|
||||
virtual void clearFocusObject();
|
||||
|
@ -156,6 +156,17 @@ template<bool RGBA, bool RGBx>
|
||||
static inline void convertARGBFromARGB32PM_sse4(uint *buffer, const uint *src, int count)
|
||||
{
|
||||
int i = 0;
|
||||
if ((_MM_GET_EXCEPTION_MASK() & _MM_MASK_INVALID) == 0) {
|
||||
for (; i < count; ++i) {
|
||||
uint v = qUnpremultiply(src[i]);
|
||||
if (RGBx)
|
||||
v = 0xff000000 | v;
|
||||
if (RGBA)
|
||||
v = ARGB2RGBA(v);
|
||||
buffer[i] = v;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const __m128i alphaMask = _mm_set1_epi32(0xff000000);
|
||||
const __m128i rgbaMask = _mm_setr_epi8(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
|
||||
const __m128i zero = _mm_setzero_si128();
|
||||
@ -223,6 +234,13 @@ template<bool RGBA>
|
||||
static inline void convertARGBFromRGBA64PM_sse4(uint *buffer, const QRgba64 *src, int count)
|
||||
{
|
||||
int i = 0;
|
||||
if ((_MM_GET_EXCEPTION_MASK() & _MM_MASK_INVALID) == 0) {
|
||||
for (; i < count; ++i) {
|
||||
const QRgba64 v = src[i].unpremultiplied();
|
||||
buffer[i] = RGBA ? toRgba8888(v) : toArgb32(v);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const __m128i alphaMask = _mm_set1_epi64x(qint64(Q_UINT64_C(0xffff) << 48));
|
||||
const __m128i alphaMask32 = _mm_set1_epi32(0xff000000);
|
||||
const __m128i rgbaMask = _mm_setr_epi8(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
|
||||
|
@ -6,7 +6,7 @@ CONFIG += static internal_module
|
||||
|
||||
DEFINES += QT_NO_CAST_FROM_ASCII
|
||||
|
||||
HEADERS +=
|
||||
HEADERS += \
|
||||
qkmsdevice_p.h
|
||||
|
||||
SOURCES += \
|
||||
|
@ -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);
|
||||
|
@ -81,6 +81,7 @@ public:
|
||||
QPlatformTextureList *textures, bool translucentBackground) override;
|
||||
#endif
|
||||
|
||||
QImage toImage() const override;
|
||||
QPlatformGraphicsBuffer *graphicsBuffer() const override;
|
||||
|
||||
private:
|
||||
|
@ -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)
|
||||
{
|
||||
@ -534,6 +522,21 @@ void QCALayerBackingStore::composeAndFlush(QWindow *window, const QRegion ®io
|
||||
}
|
||||
#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
|
||||
{
|
||||
return m_buffers.back().get();
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -207,9 +207,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList)
|
||||
// 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) {
|
||||
|
@ -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
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include "qcocoawindow.h"
|
||||
#include "qcocoahelpers.h"
|
||||
#include "qcocoaintegration.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtGui/private/qcoregraphics_p.h>
|
||||
@ -53,18 +54,99 @@
|
||||
|
||||
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");
|
||||
|
||||
QCocoaScreen::QCocoaScreen(int screenIndex)
|
||||
: QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0)
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void QCocoaScreen::cleanupScreens()
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
QCocoaScreen::~QCocoaScreen()
|
||||
{
|
||||
Q_ASSERT_X(!screen(), "QCocoaScreen", "QScreen should be deleted first");
|
||||
|
||||
delete m_cursor;
|
||||
|
||||
CVDisplayLinkRelease(m_displayLink);
|
||||
@ -72,17 +154,6 @@ QCocoaScreen::~QCocoaScreen()
|
||||
dispatch_release(m_displayLinkSource);
|
||||
}
|
||||
|
||||
NSScreen *QCocoaScreen::nativeScreen() const
|
||||
{
|
||||
NSArray<NSScreen *> *screens = [NSScreen screens];
|
||||
|
||||
// Stale reference, screen configuration has changed
|
||||
if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count])
|
||||
return nil;
|
||||
|
||||
return [screens objectAtIndex:m_screenIndex];
|
||||
}
|
||||
|
||||
static QString displayName(CGDirectDisplayID displayID)
|
||||
{
|
||||
QIOType<io_iterator_t> iterator;
|
||||
@ -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_format = QImage::Format_RGB32;
|
||||
m_depth = NSBitsPerPixelFromDepth([nsScreen depth]);
|
||||
m_devicePixelRatio = nsScreen.backingScaleFactor;
|
||||
|
||||
CGDirectDisplayID dpy = nsScreen.qt_displayId;
|
||||
CGSize size = CGDisplayScreenSize(dpy);
|
||||
m_format = QImage::Format_RGB32;
|
||||
m_depth = NSBitsPerPixelFromDepth(nsScreen.depth);
|
||||
|
||||
CGSize size = CGDisplayScreenSize(m_displayId);
|
||||
m_physicalSize = QSizeF(size.width, size.height);
|
||||
m_logicalDpi.first = 72;
|
||||
m_logicalDpi.second = 72;
|
||||
CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(dpy);
|
||||
float refresh = CGDisplayModeGetRefreshRate(displayMode);
|
||||
CGDisplayModeRelease(displayMode);
|
||||
if (refresh > 0)
|
||||
m_refreshRate = refresh;
|
||||
|
||||
m_name = displayName(dpy);
|
||||
QCFType<CGDisplayModeRef> displayMode = CGDisplayCopyDisplayMode(m_displayId);
|
||||
float refresh = CGDisplayModeGetRefreshRate(displayMode);
|
||||
m_refreshRate = refresh > 0 ? refresh : 60.0;
|
||||
|
||||
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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
@ -1209,17 +1211,17 @@ void QCocoaWindow::windowDidChangeScreen()
|
||||
return;
|
||||
|
||||
// Note: When a window is resized to 0x0 Cocoa will report the window's screen as nil
|
||||
auto *currentScreen = QCocoaIntegration::instance()->screenForNSScreen(m_view.window.screen);
|
||||
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
|
||||
// the screen was just reconfigured, which still results in AppKit sending an
|
||||
// NSWindowDidChangeScreenNotification, because the previous screen was removed,
|
||||
// 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 because we've delivered the
|
||||
// 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
|
||||
|
@ -189,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)
|
||||
|
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <QtCore/qcoreapplication.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 +81,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;
|
||||
@ -245,4 +252,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
|
||||
|
@ -81,6 +81,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 +90,7 @@ private:
|
||||
|
||||
QHash<QString, QWasmScreen *> m_screens;
|
||||
mutable QWasmClipboard *m_clipboard;
|
||||
qreal m_fontDpi = -1;
|
||||
static QWasmIntegration *s_instance;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
@ -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()
|
||||
@ -1321,15 +1322,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: {
|
||||
@ -1587,6 +1597,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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -353,6 +353,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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -438,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).
|
||||
|
||||
|
@ -140,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);
|
||||
|
||||
|
@ -184,6 +184,7 @@ static inline RECT RECTfromQRect(const QRect &rect)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug d, const RECT &r)
|
||||
{
|
||||
@ -262,6 +263,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)
|
||||
@ -859,35 +870,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)
|
||||
{
|
||||
}
|
||||
|
||||
bool QWindowsGeometryHint::validSize(const QSize &s) const
|
||||
{
|
||||
const int width = s.width();
|
||||
const int height = s.height();
|
||||
return width >= minimumSize.width() && width <= maximumSize.width()
|
||||
&& height >= minimumSize.height() && height <= maximumSize.height();
|
||||
}
|
||||
|
||||
QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
|
||||
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(DWORD style, DWORD exStyle)
|
||||
{
|
||||
RECT rect = {0,0,0,0};
|
||||
style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
|
||||
if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
|
||||
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="
|
||||
<< Qt::showbase << Qt::hex << style << " exStyle=" << exStyle << Qt::dec << Qt::noshowbase
|
||||
<< showbase << hex << style << " exStyle=" << exStyle << dec << noshowbase
|
||||
<< ' ' << rect << ' ' << result;
|
||||
return result;
|
||||
}
|
||||
|
||||
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(HWND hwnd)
|
||||
{
|
||||
return frameOnPrimaryScreen(DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
|
||||
DWORD(GetWindowLongPtr(hwnd, GWL_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 &= ~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="
|
||||
<< 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 +961,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)
|
||||
@ -996,7 +1064,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 +1190,12 @@ 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)
|
||||
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 +1224,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);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1672,10 +1745,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 +1815,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 +1862,41 @@ void QWindowsWindow::handleResized(int wParam)
|
||||
}
|
||||
}
|
||||
|
||||
void QWindowsWindow::checkForScreenChanged()
|
||||
static inline bool equalDpi(const QDpi &d1, const QDpi &d2)
|
||||
{
|
||||
if (parent())
|
||||
return qFuzzyCompare(d1.first, d2.first) && qFuzzyCompare(d1.second, d2.second);
|
||||
}
|
||||
|
||||
void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode)
|
||||
{
|
||||
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.
|
||||
@ -2236,6 +2359,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();
|
||||
@ -2446,10 +2578,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
|
||||
|
@ -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,13 +84,9 @@ 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;
|
||||
@ -221,7 +216,8 @@ public:
|
||||
HasBorderInFullScreen = 0x200000,
|
||||
WithinDpiChanged = 0x400000,
|
||||
VulkanSurface = 0x800000,
|
||||
ResizeMoveActive = 0x1000000
|
||||
ResizeMoveActive = 0x1000000,
|
||||
DisableNonClientScaling = 0x2000000
|
||||
};
|
||||
|
||||
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
|
||||
@ -262,6 +258,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 ®ion) override;
|
||||
@ -337,7 +334,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);
|
||||
|
@ -4290,12 +4290,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]}];
|
||||
|
||||
|
@ -241,7 +241,8 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
|
||||
if (!*data || *data != '.') {
|
||||
token = INTEGER_LITERAL;
|
||||
if (data - lexem == 1 &&
|
||||
(*data == 'x' || *data == 'X')
|
||||
(*data == 'x' || *data == 'X'
|
||||
|| *data == 'b' || *data == 'B')
|
||||
&& *lexem == '0') {
|
||||
++data;
|
||||
while (is_hex_char(*data) || *data == '\'')
|
||||
|
@ -897,11 +897,15 @@ QHeaderView *QAccessibleTableCell::verticalHeader() const
|
||||
|
||||
int QAccessibleTableCell::columnIndex() const
|
||||
{
|
||||
if (!isValid())
|
||||
return -1;
|
||||
return m_index.column();
|
||||
}
|
||||
|
||||
int QAccessibleTableCell::rowIndex() const
|
||||
{
|
||||
if (!isValid())
|
||||
return -1;
|
||||
#if QT_CONFIG(treeview)
|
||||
if (role() == QAccessible::TreeItem) {
|
||||
const QTreeView *treeView = qobject_cast<const QTreeView*>(view);
|
||||
@ -915,6 +919,8 @@ int QAccessibleTableCell::rowIndex() const
|
||||
|
||||
bool QAccessibleTableCell::isSelected() const
|
||||
{
|
||||
if (!isValid())
|
||||
return false;
|
||||
return view->selectionModel()->isSelected(m_index);
|
||||
}
|
||||
|
||||
@ -943,8 +949,10 @@ QStringList QAccessibleTableCell::keyBindingsForAction(const QString &) const
|
||||
|
||||
void QAccessibleTableCell::selectCell()
|
||||
{
|
||||
if (!isValid())
|
||||
return;
|
||||
QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
|
||||
if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection))
|
||||
if (selectionMode == QAbstractItemView::NoSelection)
|
||||
return;
|
||||
Q_ASSERT(table());
|
||||
QAccessibleTableInterface *cellTable = table()->tableInterface();
|
||||
@ -971,9 +979,10 @@ void QAccessibleTableCell::selectCell()
|
||||
|
||||
void QAccessibleTableCell::unselectCell()
|
||||
{
|
||||
|
||||
if (!isValid())
|
||||
return;
|
||||
QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
|
||||
if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection))
|
||||
if (selectionMode == QAbstractItemView::NoSelection)
|
||||
return;
|
||||
|
||||
QAccessibleTableInterface *cellTable = table()->tableInterface();
|
||||
@ -1014,7 +1023,7 @@ QAccessible::Role QAccessibleTableCell::role() const
|
||||
QAccessible::State QAccessibleTableCell::state() const
|
||||
{
|
||||
QAccessible::State st;
|
||||
if (!view)
|
||||
if (!isValid())
|
||||
return st;
|
||||
|
||||
QRect globalRect = view->rect();
|
||||
@ -1054,6 +1063,8 @@ QAccessible::State QAccessibleTableCell::state() const
|
||||
QRect QAccessibleTableCell::rect() const
|
||||
{
|
||||
QRect r;
|
||||
if (!isValid())
|
||||
return r;
|
||||
r = view->visualRect(m_index);
|
||||
|
||||
if (!r.isNull()) {
|
||||
@ -1065,8 +1076,10 @@ QRect QAccessibleTableCell::rect() const
|
||||
|
||||
QString QAccessibleTableCell::text(QAccessible::Text t) const
|
||||
{
|
||||
QAbstractItemModel *model = view->model();
|
||||
QString value;
|
||||
if (!isValid())
|
||||
return value;
|
||||
QAbstractItemModel *model = view->model();
|
||||
switch (t) {
|
||||
case QAccessible::Name:
|
||||
value = model->data(m_index, Qt::AccessibleTextRole).toString();
|
||||
@ -1084,7 +1097,7 @@ QString QAccessibleTableCell::text(QAccessible::Text t) const
|
||||
|
||||
void QAccessibleTableCell::setText(QAccessible::Text /*t*/, const QString &text)
|
||||
{
|
||||
if (!(m_index.flags() & Qt::ItemIsEditable))
|
||||
if (!isValid() || !(m_index.flags() & Qt::ItemIsEditable))
|
||||
return;
|
||||
view->model()->setData(m_index, text);
|
||||
}
|
||||
|
@ -9356,6 +9356,12 @@ bool QWidget::event(QEvent *event)
|
||||
d->renderToTextureReallyDirty = 1;
|
||||
#endif
|
||||
break;
|
||||
case QEvent::PlatformSurface: {
|
||||
auto surfaceEvent = static_cast<QPlatformSurfaceEvent*>(event);
|
||||
if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
|
||||
d->setWinId(0);
|
||||
break;
|
||||
}
|
||||
#ifndef QT_NO_PROPERTIES
|
||||
case QEvent::DynamicPropertyChange: {
|
||||
const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
|
||||
|
@ -163,7 +163,8 @@ private Q_SLOTS:
|
||||
void streamSerializationQJsonValue();
|
||||
void streamSerializationQJsonValueEmpty();
|
||||
void streamVariantSerialization();
|
||||
|
||||
void escapeSurrogateCodePoints_data();
|
||||
void escapeSurrogateCodePoints();
|
||||
private:
|
||||
QString testDataDir;
|
||||
};
|
||||
@ -3085,6 +3086,9 @@ void tst_QtJson::streamSerializationQJsonValue_data()
|
||||
QTest::newRow("string") << QJsonValue{QStringLiteral("bum")};
|
||||
QTest::newRow("array") << QJsonValue{QJsonArray{12,1,5,6,7}};
|
||||
QTest::newRow("object") << QJsonValue{QJsonObject{{"foo", 665}, {"bar", 666}}};
|
||||
// test json escape sequence
|
||||
QTest::newRow("array with 0xD800") << QJsonValue(QJsonArray{QString(0xD800)});
|
||||
QTest::newRow("array with 0xDF06,0xD834") << QJsonValue(QJsonArray{QString(0xDF06).append(0xD834)});
|
||||
}
|
||||
|
||||
void tst_QtJson::streamSerializationQJsonValue()
|
||||
@ -3173,5 +3177,26 @@ void tst_QtJson::streamVariantSerialization()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QtJson::escapeSurrogateCodePoints_data()
|
||||
{
|
||||
QTest::addColumn<QString>("str");
|
||||
QTest::addColumn<QByteArray>("escStr");
|
||||
QTest::newRow("0xD800") << QString(0xD800) << QByteArray("\\ud800");
|
||||
QTest::newRow("0xDF06,0xD834") << QString(0xDF06).append(0xD834) << QByteArray("\\udf06\\ud834");
|
||||
}
|
||||
|
||||
void tst_QtJson::escapeSurrogateCodePoints()
|
||||
{
|
||||
QFETCH(QString, str);
|
||||
QFETCH(QByteArray, escStr);
|
||||
QJsonArray array;
|
||||
array.append(str);
|
||||
QByteArray buffer;
|
||||
QDataStream save(&buffer, QIODevice::WriteOnly);
|
||||
save << array;
|
||||
// verify the buffer has escaped values
|
||||
QVERIFY(buffer.contains(escStr));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QtJson)
|
||||
#include "tst_qtjson.moc"
|
||||
|
@ -525,6 +525,7 @@ private:
|
||||
|
||||
#ifdef Q_MOC_RUN
|
||||
int xx = 11'11; // digit separator must not confuse moc (QTBUG-59351)
|
||||
int xx = 0b11'11; // digit separator in a binary literal must not confuse moc (QTBUG-75656)
|
||||
#endif
|
||||
|
||||
private slots:
|
||||
|
Loading…
x
Reference in New Issue
Block a user