diff --git a/bin/syncqt.pl b/bin/syncqt.pl index 972717efcf..7793811c9f 100755 --- a/bin/syncqt.pl +++ b/bin/syncqt.pl @@ -1111,7 +1111,7 @@ foreach my $lib (@modules_to_sync) { elsif (!$shadow) { $pri_install_pfiles.= "$pri_install_iheader ";; } - $pri_injections .= fixPaths($iheader, $out_basedir) + $pri_injections .= fixPaths($iheader, $build_basedir) .":".($no_stamp ? "^" : "").fixPaths($oheader, "$out_basedir/include/$lib") .$injection." " if ($shadow); } diff --git a/dist/changes-5.12.3 b/dist/changes-5.12.3 new file mode 100644 index 0000000000..e6636fc153 --- /dev/null +++ b/dist/changes-5.12.3 @@ -0,0 +1,82 @@ +Qt 5.12.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.2. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Third-Party Code * +**************************************************************************** + + - Changed classification of the wintab license from Public Domain to + Custom. + +**************************************************************************** +* QtCore * +**************************************************************************** + + - Event system: + * [QTBUG-72438] Fixed a possible race condition on Windows that would + cause an interrupted event loop to be stuck until more events were + posted. + + - Logging system: + * [QTBUG-74359] Fixed the compilation of qCDebug("", ...) when debug + output was disabled. + + - QCollator: + * [QTBUG-74209] Fixed a bug that caused QCompare to incorrect return a + sorting order on Windows if the Win32 API failed. + + - QDateTime / QTimeZone: + * [QTBUG-74614] Fixed handling of timezones that contain no DST + transitions. + + - QProcess: + * [QTBUG-73778] Fixed a crash when calling closeWriteChannel() on Windows. + +**************************************************************************** +* QtSql * +**************************************************************************** + + - When cross-compiling pg_config, mysql_config are not looked up in PATH + anymore. Pass -psql_config path/to/pg_config or -mysql_config + path/to/mysql_config to explicitly enable PSQL or MySQL in this setup. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + + - Android: + * Text fields with ImhNoPredictiveText set are no longer working around + keyboards that disregard this setting. To enforce the workaround, the + environment variable + QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT should be set. + + * [QTBUG-74029] Added entries in the AndroidManifest.xml for specific + portrait and landscape splash screens. If one is present for the current + orientation, it will be preferred over the generic one. + + - Linux: + * [QTBUG-74526] Changed the way we use the statx() system call to use a + fallback mechanism provided by the GNU C library. This should allow Qt + applications that are compiled with glibc >= 2.28 to run even on kernels + older than 4.11. + + - Windows: + * [QTBUG-74062] Fixed QToolTip pop-ups and QComboBox animation pop-ups + being off by a few pixels on Windows 10. + diff --git a/mkspecs/features/qt_configure.prf b/mkspecs/features/qt_configure.prf index a9b1eef589..78c666d915 100644 --- a/mkspecs/features/qt_configure.prf +++ b/mkspecs/features/qt_configure.prf @@ -519,6 +519,17 @@ defineTest(qtConfSetupLibraries) { } } +defineReplace(qtGccSysrootifiedPath) { + return($$replace(1, ^=, $$[QT_SYSROOT])) +} + +defineReplace(qtGccSysrootifiedPaths) { + sysrootified = + for (path, 1): \ + sysrootified += $$qtGccSysrootifiedPath($$path) + return($$sysrootified) +} + # libs-var, libs, in-paths, out-paths-var defineTest(qtConfResolveLibs) { ret = true @@ -535,6 +546,7 @@ defineTest(qtConfResolveLibs) { out += $$l } else: contains(l, "^-L.*") { lp = $$replace(l, "^-L", ) + gcc: lp = $$qtGccSysrootifiedPath($$lp) !exists($$lp/.) { qtLog("Library path $$val_escape(lp) is invalid.") ret = false @@ -608,6 +620,7 @@ defineTest(qtConfResolveAllLibs) { # libs-var, in-paths, libs defineTest(qtConfResolvePathLibs) { ret = true + gcc: 2 = $$qtGccSysrootifiedPaths($$2) for (libdir, 2) { !exists($$libdir/.) { qtLog("Library path $$val_escape(libdir) is invalid.") @@ -658,6 +671,7 @@ defineReplace(qtConfGetTestIncludes) { # includes-var, in-paths, test-object-var defineTest(qtConfResolvePathIncs) { ret = true + gcc: 2 = $$qtGccSysrootifiedPaths($$2) for (incdir, 2) { !exists($$incdir/.) { qtLog("Include path $$val_escape(incdir) is invalid.") diff --git a/mkspecs/features/qt_module_headers.prf b/mkspecs/features/qt_module_headers.prf index 6b4b9143fa..37b69e31c8 100644 --- a/mkspecs/features/qt_module_headers.prf +++ b/mkspecs/features/qt_module_headers.prf @@ -23,7 +23,7 @@ load(qt_build_paths) QMAKE_SYNCQT += -module $$mod QMAKE_SYNCQT += \ -version $$VERSION -outdir $$system_quote($$MODULE_BASE_OUTDIR) \ - -builddir $$system_quote($$shadowed($$MODULE_BASE_INDIR)) $$MODULE_SYNCQT_DIR + -builddir $$system_quote($$REAL_MODULE_BASE_OUTDIR) $$MODULE_SYNCQT_DIR !silent: message($$QMAKE_SYNCQT) system($$QMAKE_SYNCQT)|error("Failed to run: $$QMAKE_SYNCQT") diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index efc049e03a..b293792bd1 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -1615,6 +1615,14 @@ The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + \section1 QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + + Specifies the C compiler flags for release builds where + \c{force_debug_info} is set in \c{CONFIG}. + The value of this variable is typically handled by + qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CFLAGS_SHLIB \section1 QMAKE_CFLAGS_SHLIB @@ -1683,6 +1691,14 @@ The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO + \section1 QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO + + Specifies the C++ compiler flags for release builds where + \c{force_debug_info} is set in \c{CONFIG}. + The value of this variable is typically handled by + qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \target QMAKE_CXXFLAGS_SHLIB \section1 QMAKE_CXXFLAGS_SHLIB @@ -2063,6 +2079,12 @@ The value of this variable is typically handled by qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \section1 QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO + + Specifies the linker flags for release builds where \c{force_debug_info} is + set in \c{CONFIG}. The value of this variable is typically handled by + qmake or \l{#QMAKESPEC}{qmake.conf} and rarely needs to be modified. + \section1 QMAKE_LFLAGS_APP Specifies the linker flags for building applications. diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index 0e95766f8e..08a8c2168d 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -142,6 +142,7 @@ const char _InterfaceIdentifierFileName[] = "InterfaceIdentifierFileName"; const char _IntermediateDirectory[] = "IntermediateDirectory"; const char _KeyContainer[] = "KeyContainer"; const char _KeyFile[] = "KeyFile"; +const char _LanguageStandard[] = "LanguageStandard"; const char _LargeAddressAware[] = "LargeAddressAware"; const char _LinkDLL[] = "LinkDLL"; const char _LinkErrorReporting[] = "LinkErrorReporting"; @@ -1477,6 +1478,7 @@ void VCXProjectWriter::write(XmlOutput &xml, const VCCLCompilerTool &tool) << attrTagT(_IntrinsicFunctions, tool.EnableIntrinsicFunctions) << attrTagT(_MinimalRebuild, tool.MinimalRebuild) << attrTagT(_MultiProcessorCompilation, tool.MultiProcessorCompilation) + << attrTagS(_LanguageStandard, tool.LanguageStandard) << attrTagS(_ObjectFileName, tool.ObjectFile) << attrTagT(_OmitDefaultLibName, tool.OmitDefaultLibName) << attrTagT(_OmitFramePointers, tool.OmitFramePointers) diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index cf0b96ec9f..15c8838054 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -1146,6 +1146,14 @@ bool VCCLCompilerTool::parseOption(const char* option) ShowIncludes = _True; break; } + if (strlen(option) > 8 && second == 't' && third == 'd') { + const QString version = option + 8; + static const QStringList knownVersions = { "14", "17", "latest" }; + if (knownVersions.contains(version)) { + LanguageStandard = "stdcpp" + version; + break; + } + } found = false; break; case 'u': if (!second) diff --git a/qmake/generators/win32/msvc_objectmodel.h b/qmake/generators/win32/msvc_objectmodel.h index 33a96bf85e..b356f1bb73 100644 --- a/qmake/generators/win32/msvc_objectmodel.h +++ b/qmake/generators/win32/msvc_objectmodel.h @@ -526,6 +526,7 @@ public: triState ImproveFloatingPointConsistency; inlineExpansionOption InlineFunctionExpansion; triState KeepComments; + QString LanguageStandard; triState MinimalRebuild; QString ObjectFile; triState OmitDefaultLibName; diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp index 735b472787..0bb0bb05b1 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.cpp +++ b/src/3rdparty/angle/src/libANGLE/Display.cpp @@ -364,6 +364,23 @@ Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attri return display; } +//static +void Display::CleanupDisplays() +{ + // ~Display takes care of removing the entry from the according map + { + ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); + while (!displays->empty()) + delete displays->begin()->second; + } + + { + DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap(); + while (!displays->empty()) + delete displays->begin()->second; + } +} + Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice) : mImplementation(nullptr), mDisplayId(displayId), diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h index aa1d1c3b37..2a1c386d75 100644 --- a/src/3rdparty/angle/src/libANGLE/Display.h +++ b/src/3rdparty/angle/src/libANGLE/Display.h @@ -65,6 +65,7 @@ class Display final : angle::NonCopyable static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, const AttributeMap &attribMap); + static void CleanupDisplays(); static const ClientExtensions &GetClientExtensions(); static const std::string &GetClientExtensionString(); diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp index c5f3dfe4e1..26045bf5b2 100644 --- a/src/3rdparty/angle/src/libGLESv2/global_state.cpp +++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp @@ -13,6 +13,7 @@ #include "common/tls.h" #include "libANGLE/Thread.h" +#include "libANGLE/Display.h" namespace gl { @@ -140,6 +141,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) return static_cast(egl::DeallocateCurrentThread()); case DLL_PROCESS_DETACH: + egl::Display::CleanupDisplays(); return static_cast(egl::TerminateProcess()); } diff --git a/src/angle/patches/0013-ANGLE-clean-up-displays-on-dll-unload.patch b/src/angle/patches/0013-ANGLE-clean-up-displays-on-dll-unload.patch new file mode 100644 index 0000000000..fce3fd76b2 --- /dev/null +++ b/src/angle/patches/0013-ANGLE-clean-up-displays-on-dll-unload.patch @@ -0,0 +1,78 @@ +From d8ca4f6d0d8fffd8319f340685e03751049678ae Mon Sep 17 00:00:00 2001 +From: Oliver Wolff +Date: Tue, 16 Apr 2019 10:19:27 +0200 +Subject: [PATCH] ANGLE: clean up displays on dll unload + +If the displays are not cleaned up on dll unloading, profilers might +report memory leaks. + +Change-Id: I04cbc3c2448bfb450f7d840e216827f86856e963 +--- + src/3rdparty/angle/src/libANGLE/Display.cpp | 17 +++++++++++++++++ + src/3rdparty/angle/src/libANGLE/Display.h | 1 + + .../angle/src/libGLESv2/global_state.cpp | 2 ++ + 3 files changed, 20 insertions(+) + +diff --git a/src/3rdparty/angle/src/libANGLE/Display.cpp b/src/3rdparty/angle/src/libANGLE/Display.cpp +index 735b472787..0bb0bb05b1 100644 +--- a/src/3rdparty/angle/src/libANGLE/Display.cpp ++++ b/src/3rdparty/angle/src/libANGLE/Display.cpp +@@ -364,6 +364,23 @@ Display *Display::GetDisplayFromDevice(Device *device, const AttributeMap &attri + return display; + } + ++//static ++void Display::CleanupDisplays() ++{ ++ // ~Display takes care of removing the entry from the according map ++ { ++ ANGLEPlatformDisplayMap *displays = GetANGLEPlatformDisplayMap(); ++ while (!displays->empty()) ++ delete displays->begin()->second; ++ } ++ ++ { ++ DevicePlatformDisplayMap *displays = GetDevicePlatformDisplayMap(); ++ while (!displays->empty()) ++ delete displays->begin()->second; ++ } ++} ++ + Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice) + : mImplementation(nullptr), + mDisplayId(displayId), +diff --git a/src/3rdparty/angle/src/libANGLE/Display.h b/src/3rdparty/angle/src/libANGLE/Display.h +index aa1d1c3b37..2a1c386d75 100644 +--- a/src/3rdparty/angle/src/libANGLE/Display.h ++++ b/src/3rdparty/angle/src/libANGLE/Display.h +@@ -65,6 +65,7 @@ class Display final : angle::NonCopyable + static Display *GetDisplayFromDevice(Device *device, const AttributeMap &attribMap); + static Display *GetDisplayFromNativeDisplay(EGLNativeDisplayType nativeDisplay, + const AttributeMap &attribMap); ++ static void CleanupDisplays(); + + static const ClientExtensions &GetClientExtensions(); + static const std::string &GetClientExtensionString(); +diff --git a/src/3rdparty/angle/src/libGLESv2/global_state.cpp b/src/3rdparty/angle/src/libGLESv2/global_state.cpp +index c5f3dfe4e1..26045bf5b2 100644 +--- a/src/3rdparty/angle/src/libGLESv2/global_state.cpp ++++ b/src/3rdparty/angle/src/libGLESv2/global_state.cpp +@@ -13,6 +13,7 @@ + #include "common/tls.h" + + #include "libANGLE/Thread.h" ++#include "libANGLE/Display.h" + + namespace gl + { +@@ -140,6 +141,7 @@ extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) + return static_cast(egl::DeallocateCurrentThread()); + + case DLL_PROCESS_DETACH: ++ egl::Display::CleanupDisplays(); + return static_cast(egl::TerminateProcess()); + } + +-- +2.20.1.windows.1 + diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index 6195c324e7..90df8653a7 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -930,7 +930,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel */ /*! - \fn quint32 QRandomGenerator::bounded(int highest) + \fn int QRandomGenerator::bounded(int highest) \overload Generates one random 32-bit quantity in the range between 0 (inclusive) and @@ -957,7 +957,6 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel \snippet code/src_corelib_global_qrandom.cpp 14 - Note that this function cannot be used to obtain values in the full 32-bit range of quint32. Instead, use generate(). @@ -965,7 +964,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel */ /*! - \fn quint32 QRandomGenerator::bounded(int lowest, int highest) + \fn int QRandomGenerator::bounded(int lowest, int highest) \overload Generates one random 32-bit quantity in the range between \a lowest diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm index 53066687d3..e2497eaadb 100644 --- a/src/gui/painting/qcoregraphics.mm +++ b/src/gui/painting/qcoregraphics.mm @@ -366,40 +366,35 @@ void qt_mac_scale_region(QRegion *region, qreal scaleFactor) // ---------------------- QMacCGContext ---------------------- -QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) : context(0) +QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) { - // In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood. - QImage *image = 0; - if (paintDevice->devType() == QInternal::Image) { - image = static_cast(paintDevice); - } else if (paintDevice->devType() == QInternal::Pixmap) { - - const QPixmap *pm = static_cast(paintDevice); - QPlatformPixmap *data = const_cast(pm)->data_ptr().data(); - if (data && data->classId() == QPlatformPixmap::RasterClass) { - image = data->buffer(); - } else { - qDebug("QMacCGContext: Unsupported pixmap class"); - } - } else if (paintDevice->devType() == QInternal::Widget) { - // TODO test: image = static_cast(static_cast(paintDevice)->backingStore()->paintDevice()); - qDebug("QMacCGContext: not implemented: Widget class"); - } - - if (!image) - return; // Context type not supported. - - QCFType colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - context = CGBitmapContextCreate(image->bits(), image->width(), image->height(), 8, - image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); - - CGContextTranslateCTM(context, 0, image->height()); - const qreal devicePixelRatio = paintDevice->devicePixelRatioF(); - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - CGContextScaleCTM(context, 1, -1); + initialize(paintDevice); } -QMacCGContext::QMacCGContext(QPainter *painter) : context(0) +void QMacCGContext::initialize(QPaintDevice *paintDevice) +{ + // Find the underlying QImage of the paint device + switch (int deviceType = paintDevice->devType()) { + case QInternal::Pixmap: { + auto *platformPixmap = static_cast(paintDevice)->handle(); + if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass) + initialize(platformPixmap->buffer()); + else + qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId(); + break; + } + case QInternal::Image: + initialize(static_cast(paintDevice)); + break; + case QInternal::Widget: + qWarning() << "QMacCGContext: not implemented: Widget class"; + break; + default: + qWarning() << "QMacCGContext:: Unsupported paint device type" << deviceType; + } +} + +QMacCGContext::QMacCGContext(QPainter *painter) { QPaintEngine *paintEngine = painter->paintEngine(); @@ -414,51 +409,68 @@ QMacCGContext::QMacCGContext(QPainter *painter) : context(0) return; } - int devType = painter->device()->devType(); - if (paintEngine->type() == QPaintEngine::Raster - && (devType == QInternal::Widget || - devType == QInternal::Pixmap || - devType == QInternal::Image)) { - - const QImage *image = static_cast(paintEngine->paintDevice()); - QCFType colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); - context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8, - image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); - - // Invert y axis - CGContextTranslateCTM(context, 0, image->height()); - CGContextScaleCTM(context, 1, -1); - - const qreal devicePixelRatio = image->devicePixelRatio(); - - if (devType == QInternal::Widget) { - // Set the clip rect which is an intersection of the system clip - // and the painter clip. To make matters more interesting these - // are in device pixels and device-independent pixels, respectively. - QRegion clip = painter->paintEngine()->systemClip(); // get system clip in device pixels - QTransform native = painter->deviceTransform(); // get device transform. dx/dy is in device pixels - - if (painter->hasClipping()) { - QRegion r = painter->clipRegion(); // get painter clip, which is in device-independent pixels - qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels - r.translate(native.dx(), native.dy()); - if (clip.isEmpty()) - clip = r; - else - clip &= r; - } - qt_mac_clip_cg(context, clip, 0); // clip in device pixels - - // Scale the context so that painting happens in device-independent pixels - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio); - } else { - // Scale to paint in device-independent pixels - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - } - } else { - qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType; + if (paintEngine->type() != QPaintEngine::Raster) { + qWarning() << "QMacCGContext:: Unsupported paint engine type" << paintEngine->type(); + return; } + + // The raster paint engine always operates on a QImage + Q_ASSERT(paintEngine->paintDevice()->devType() == QInternal::Image); + + // On behalf of one of these supported painter devices + switch (int painterDeviceType = painter->device()->devType()) { + case QInternal::Pixmap: + case QInternal::Image: + case QInternal::Widget: + break; + default: + qWarning() << "QMacCGContext:: Unsupported paint device type" << painterDeviceType; + return; + } + + // Applying the clip is so entangled with the rest of the context setup + // that for simplicity we just pass in the painter. + initialize(static_cast(paintEngine->paintDevice()), painter); +} + +void QMacCGContext::initialize(const QImage *image, QPainter *painter) +{ + QCFType colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); + context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8, + image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image)); + + // Invert y axis + CGContextTranslateCTM(context, 0, image->height()); + CGContextScaleCTM(context, 1, -1); + + const qreal devicePixelRatio = image->devicePixelRatio(); + + if (painter && painter->device()->devType() == QInternal::Widget) { + // Set the clip rect which is an intersection of the system clip and the painter clip + QRegion clip = painter->paintEngine()->systemClip(); + QTransform deviceTransform = painter->deviceTransform(); + + if (painter->hasClipping()) { + // To make matters more interesting the painter clip is in device-independent pixels, + // so we need to scale it to match the device-pixels of the system clip. + QRegion painterClip = painter->clipRegion(); + qt_mac_scale_region(&painterClip, devicePixelRatio); + + painterClip.translate(deviceTransform.dx(), deviceTransform.dy()); + + if (clip.isEmpty()) + clip = painterClip; + else + clip &= painterClip; + } + + qt_mac_clip_cg(context, clip, 0); + + CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy()); + } + + // Scale the context so that painting happens in device-independent pixels + CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); } QT_END_NAMESPACE diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h index 868c2b08b5..ba2cde8325 100644 --- a/src/gui/painting/qcoregraphics_p.h +++ b/src/gui/painting/qcoregraphics_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include + #include #include #include @@ -89,38 +91,16 @@ Q_GUI_EXPORT QBrush qt_mac_toQBrush(CGColorRef color); class Q_GUI_EXPORT QMacCGContext { public: - inline QMacCGContext() { context = 0; } + QMacCGContext() = default; QMacCGContext(QPaintDevice *pdev); QMacCGContext(QPainter *p); - inline QMacCGContext(CGContextRef cg, bool takeOwnership = false) { - context = cg; - if (!takeOwnership) - CGContextRetain(context); - } - inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; } - inline ~QMacCGContext() { - if (context) - CGContextRelease(context); - } - inline bool isNull() const { return context; } - inline operator CGContextRef() { return context; } - inline QMacCGContext &operator=(const QMacCGContext ©) { - if (context) - CGContextRelease(context); - context = copy.context; - CGContextRetain(context); - return *this; - } - inline QMacCGContext &operator=(CGContextRef cg) { - if (context) - CGContextRelease(context); - context = cg; - CGContextRetain(context); //we do not take ownership - return *this; - } + + operator CGContextRef() { return context; } private: - CGContextRef context; + void initialize(QPaintDevice *paintDevice); + void initialize(const QImage *, QPainter *painter = nullptr); + QCFType context; }; QT_END_NAMESPACE diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index fba91c62c8..5d0ef150f3 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -385,8 +385,8 @@ QHostAddress QNetmask::address(QAbstractSocket::NetworkLayerProtocol protocol) c \value LocalHost The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1"). \value LocalHostIPv6 The IPv6 localhost address. Equivalent to QHostAddress("::1"). \value Broadcast The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255"). - \value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interaces. - \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interaces. + \value AnyIPv4 The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interfaces. + \value AnyIPv6 The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interfaces. \value Any The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces. */ diff --git a/src/platformsupport/platformcompositor/qopenglcompositor.cpp b/src/platformsupport/platformcompositor/qopenglcompositor.cpp index 0f4946f81a..635bf0107f 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositor.cpp +++ b/src/platformsupport/platformcompositor/qopenglcompositor.cpp @@ -188,14 +188,15 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight) topLeftRect.width(), topLeftRect.height()); } -static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &targetWindowRect, +static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &sourceWindowRect, + const QRect &targetWindowRect, QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix) { const QRect clipRect = textures->clipRect(idx); if (clipRect.isEmpty()) return; - const QRect rectInWindow = textures->geometry(idx); + const QRect rectInWindow = textures->geometry(idx).translated(sourceWindowRect.topLeft()); const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft()); const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height()); @@ -218,7 +219,7 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) const QRect targetWindowRect(QPoint(0, 0), m_targetWindow->geometry().size()); float currentOpacity = 1.0f; BlendStateBinder blend; - + const QRect sourceWindowRect = window->sourceWindow()->geometry(); for (int i = 0; i < textures->count(); ++i) { uint textureId = textures->textureId(i); const float opacity = window->sourceWindow()->opacity(); @@ -243,16 +244,16 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window) target = m_rotationMatrix * target; m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft); } else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { - // Texture from an FBO belonging to a QOpenGLWidget + // Texture from an FBO belonging to a QOpenGLWidget or QQuickWidget blend.set(false); - clippedBlit(textures, i, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); + clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); } } for (int i = 0; i < textures->count(); ++i) { if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) { blend.set(true); - clippedBlit(textures, i, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); + clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr); } } diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 508f24d578..6f24598250 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -93,6 +93,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..d42a723b47 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -460,12 +460,29 @@ void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion ®ion, NSView *backingStoreView = static_cast(window()->handle())->view(); NSView *flushedView = static_cast(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; 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/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 ecdfb352ab..3e78196227 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp @@ -116,6 +116,8 @@ public: , m_egl_stream(EGL_NO_STREAM_KHR) { } + ~QEglFSKmsEglDeviceWindow() { destroy(); } + void invalidateSurface() override; void resetSurface() override; 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/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 #include +#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 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 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/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index c050369801..c5af4d8042 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -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) diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index f1960f1585..9a8b5d5121 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); @@ -531,7 +548,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) @@ -547,7 +564,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase - << __FUNCTION__ << " pointerId=" << pointerId + << __FUNCTION__ << " sourceDevice=" << sourceDevice << " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos << " message=" << hex << msg.message << " flags=" << hex << penInfo->pointerInfo.pointerFlags; @@ -570,7 +587,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 +600,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) @@ -607,7 +624,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. } } @@ -681,7 +698,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) @@ -709,7 +725,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, const MouseEvent mouseEvent = eventFromMsg(msg); if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { - QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, + const Qt::MouseButtons nonclientButtons = queryMouseButtons(); + QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, nonclientButtons, mouseEvent.button, mouseEvent.type, keyModifiers, source); return false; // Allow further event processing } @@ -725,6 +742,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, return true; } + const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); + handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons); handleEnterLeave(window, currentWindowUnderPointer, globalPos); 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/widgets/util/qsystemtrayicon_p.h b/src/widgets/util/qsystemtrayicon_p.h index 5bdf020a47..e31532ea19 100644 --- a/src/widgets/util/qsystemtrayicon_p.h +++ b/src/widgets/util/qsystemtrayicon_p.h @@ -69,6 +69,7 @@ QT_BEGIN_NAMESPACE class QSystemTrayIconSys; +class QSystemTrayWatcher; class QPlatformSystemTrayIcon; class QToolButton; class QLabel; @@ -90,6 +91,8 @@ public: void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon, QSystemTrayIcon::MessageIcon msgIcon, int msecs); + void destroyIcon(); + static bool isSystemTrayAvailable_sys(); static bool supportsMessages_sys(); @@ -101,6 +104,7 @@ public: QSystemTrayIconSys *sys; QPlatformSystemTrayIcon *qpa_sys; bool visible; + QSystemTrayWatcher *trayWatcher; private: void install_sys_qpa(); diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp index 86532456c7..70e5f3678e 100644 --- a/src/widgets/util/qsystemtrayicon_x11.cpp +++ b/src/widgets/util/qsystemtrayicon_x11.cpp @@ -92,9 +92,6 @@ protected: virtual void resizeEvent(QResizeEvent *) override; virtual void moveEvent(QMoveEvent *) override; -private slots: - void systemTrayWindowChanged(QScreen *screen); - private: QSystemTrayIcon *q; }; @@ -116,15 +113,6 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn) setMouseTracking(true); } -void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *) -{ - if (!locateSystemTray()) { - QBalloonTip::hideBalloon(); - hide(); // still no luck - destroy(); - } -} - QRect QSystemTrayIconSys::globalGeometry() const { return QRect(mapToGlobal(QPoint(0, 0)), size()); @@ -199,10 +187,41 @@ void QSystemTrayIconSys::resizeEvent(QResizeEvent *event) } //////////////////////////////////////////////////////////////////////////// +class QSystemTrayWatcher: public QObject +{ + Q_OBJECT +public: + QSystemTrayWatcher(QSystemTrayIcon *trayIcon) + : QObject(trayIcon) + , mTrayIcon(trayIcon) + { + // This code uses string-based syntax because we want to connect to a signal + // which is defined in XCB plugin - QXcbNativeInterface::systemTrayWindowChanged(). + connect(qGuiApp->platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), + this, SLOT(systemTrayWindowChanged(QScreen*))); + } + +private slots: + void systemTrayWindowChanged(QScreen *) + { + auto icon = static_cast(QObjectPrivate::get(mTrayIcon)); + icon->destroyIcon(); + if (icon->visible && locateSystemTray()) { + icon->sys = new QSystemTrayIconSys(mTrayIcon); + icon->sys->show(); + } + } + +private: + QSystemTrayIcon *mTrayIcon = nullptr; +}; +//////////////////////////////////////////////////////////////////////////// + QSystemTrayIconPrivate::QSystemTrayIconPrivate() : sys(0), qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()), - visible(false) + visible(false), + trayWatcher(nullptr) { } @@ -213,16 +232,21 @@ QSystemTrayIconPrivate::~QSystemTrayIconPrivate() void QSystemTrayIconPrivate::install_sys() { + Q_Q(QSystemTrayIcon); + if (qpa_sys) { install_sys_qpa(); return; } - Q_Q(QSystemTrayIcon); - if (!sys && locateSystemTray()) { - sys = new QSystemTrayIconSys(q); - QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), - sys, SLOT(systemTrayWindowChanged(QScreen*))); - sys->show(); + + if (!sys) { + if (!trayWatcher) + trayWatcher = new QSystemTrayWatcher(q); + + if (locateSystemTray()) { + sys = new QSystemTrayIconSys(q); + sys->show(); + } } } @@ -241,14 +265,21 @@ void QSystemTrayIconPrivate::remove_sys() remove_sys_qpa(); return; } + + destroyIcon(); +} + +void QSystemTrayIconPrivate::destroyIcon() +{ if (!sys) return; QBalloonTip::hideBalloon(); - sys->hide(); // this should do the trick, but... - delete sys; // wm may resize system tray only for DestroyEvents - sys = 0; + sys->hide(); + delete sys; + sys = nullptr; } + void QSystemTrayIconPrivate::updateIcon_sys() { if (qpa_sys) {