diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-02-15 01:00:50 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-02-15 01:00:51 +0100 |
commit | ef2ddcf551dec13215cb45cb000731f94b2f8e34 (patch) | |
tree | c8810f6ee77a81c3003ccc8783c9d3b17f0b8a5e /src | |
parent | e2cf6ade3535467bc2f21b54b82ed007d5ce279b (diff) | |
parent | 501cca2c4b0851cea7133ba56c3a05d71c25ce6d (diff) |
Merge remote-tracking branch 'origin/5.12' into 5.13
Change-Id: I8cad26f17834dbc9f7151edc0f17786f9e32025d
Diffstat (limited to 'src')
21 files changed, 380 insertions, 489 deletions
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index bc23e821fd..4550891e2a 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -48,6 +48,11 @@ #include <UIKit/UIKit.h> #endif +#include <execinfo.h> +#include <dlfcn.h> +#include <cxxabi.h> +#include <objc/runtime.h> + #include <qdebug.h> QT_BEGIN_NAMESPACE @@ -127,12 +132,54 @@ QT_USE_NAMESPACE } @end QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker); + QT_BEGIN_NAMESPACE QMacAutoReleasePool::QMacAutoReleasePool() : pool([[NSAutoreleasePool alloc] init]) { - [[[QMacAutoReleasePoolTracker alloc] initWithPool: + Class trackerClass = [QMacAutoReleasePoolTracker class]; + +#ifdef QT_DEBUG + void *poolFrame = nullptr; + if (__builtin_available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 5.0, *)) { + void *frame; + if (backtrace_from_fp(__builtin_frame_address(0), &frame, 1)) + poolFrame = frame; + } else { + static const int maxFrames = 3; + void *callstack[maxFrames]; + if (backtrace(callstack, maxFrames) == maxFrames) + poolFrame = callstack[maxFrames - 1]; + } + + if (poolFrame) { + Dl_info info; + if (dladdr(poolFrame, &info) && info.dli_sname) { + const char *symbolName = info.dli_sname; + if (symbolName[0] == '_') { + int status; + if (char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status)) + symbolName = demangled; + } + + char *className = nullptr; + asprintf(&className, " ^-- allocated in function: %s", symbolName); + + if (Class existingClass = objc_getClass(className)) + trackerClass = existingClass; + else + trackerClass = objc_duplicateClass(trackerClass, className, 0); + + free(className); + + if (symbolName != info.dli_sname) + free((char*)symbolName); + } + } +#endif + + [[[trackerClass alloc] initWithPool: reinterpret_cast<NSAutoreleasePool **>(&pool)] autorelease]; } diff --git a/src/gui/configure.json b/src/gui/configure.json index 4420b81409..b5bfdc4a33 100644 --- a/src/gui/configure.json +++ b/src/gui/configure.json @@ -59,8 +59,9 @@ }, "bcm_host": { "export": "", + "headers": ["bcm_host.h"], "sources": [ - "-lbcm_host" + { "type": "makeSpec", "spec": "BCM_HOST" } ] }, "dxguid": { diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index 8d71d1c3a9..d935deb4d6 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -62,7 +62,7 @@ public: } QWindow *window; - QPlatformBackingStore *platformBackingStore; + QPlatformBackingStore *platformBackingStore = nullptr; QScopedPointer<QImage> highDpiBackingstore; QRegion staticContents; QSize size; @@ -95,8 +95,6 @@ public: QBackingStore::QBackingStore(QWindow *window) : d_ptr(new QBackingStorePrivate(window)) { - d_ptr->platformBackingStore = QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(window); - d_ptr->platformBackingStore->setBackingStore(this); } /*! @@ -131,7 +129,8 @@ void QBackingStore::beginPaint(const QRegion ®ion) d_ptr->highDpiBackingstore->devicePixelRatio() != d_ptr->window->devicePixelRatio()) resize(size()); - d_ptr->platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window)); + QPlatformBackingStore *platformBackingStore = handle(); + platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window)); // When QtGui is applying a high-dpi scale factor the backing store // creates a "large" backing store image. This image needs to be @@ -139,7 +138,7 @@ void QBackingStore::beginPaint(const QRegion ®ion) // devicePixelRatio. Do this on a separate image instance that shares // the image data to avoid having the new devicePixelRatio be propagated // back to the platform plugin. - QPaintDevice *device = d_ptr->platformBackingStore->paintDevice(); + QPaintDevice *device = platformBackingStore->paintDevice(); if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) { QImage *source = static_cast<QImage *>(device); const bool needsNewImage = d_ptr->highDpiBackingstore.isNull() @@ -168,7 +167,7 @@ void QBackingStore::beginPaint(const QRegion ®ion) */ QPaintDevice *QBackingStore::paintDevice() { - QPaintDevice *device = d_ptr->platformBackingStore->paintDevice(); + QPaintDevice *device = handle()->paintDevice(); if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) return d_ptr->highDpiBackingstore.data(); @@ -189,7 +188,18 @@ void QBackingStore::endPaint() if (paintDevice()->paintingActive()) qWarning() << "QBackingStore::endPaint() called with active painter on backingstore paint device"; - d_ptr->platformBackingStore->endPaint(); + handle()->endPaint(); +} + +static bool isRasterSurface(QWindow *window) +{ + switch (window->surfaceType()) { + case QSurface::RasterSurface: + case QSurface::RasterGLSurface: + return true; + default: + return false; + }; } /*! @@ -220,6 +230,13 @@ void QBackingStore::flush(const QRegion ®ion, QWindow *window, const QPoint & return; } + if (!isRasterSurface(window)) { + qWarning() << "Attempted flush to non-raster surface" << window << "of type" << window->surfaceType() + << (window->inherits("QWidgetWindow") ? "(consider using Qt::WA_PaintOnScreen to exclude " + "from backingstore sync)" : ""); + return; + } + #ifdef QBACKINGSTORE_DEBUG if (window && window->isTopLevel() && !qt_window_private(window)->receivedExpose) { qWarning().nospace() << "QBackingStore::flush() called with non-exposed window " @@ -229,7 +246,7 @@ void QBackingStore::flush(const QRegion ®ion, QWindow *window, const QPoint & Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients)); - d_ptr->platformBackingStore->flush(window, QHighDpi::toNativeLocalRegion(region, window), + handle()->flush(window, QHighDpi::toNativeLocalRegion(region, window), QHighDpi::toNativeLocalPosition(offset, window)); } @@ -241,7 +258,7 @@ void QBackingStore::flush(const QRegion ®ion, QWindow *window, const QPoint & void QBackingStore::resize(const QSize &size) { d_ptr->size = size; - d_ptr->platformBackingStore->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents); + handle()->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents); } /*! @@ -268,7 +285,7 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy) if (qFloor(nativeDx) != nativeDx || qFloor(nativeDy) != nativeDy) return false; - return d_ptr->platformBackingStore->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window), + return handle()->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window), nativeDx, nativeDy); } @@ -349,6 +366,10 @@ void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPo */ QPlatformBackingStore *QBackingStore::handle() const { + if (!d_ptr->platformBackingStore) { + d_ptr->platformBackingStore = QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(d_ptr->window); + d_ptr->platformBackingStore->setBackingStore(const_cast<QBackingStore*>(this)); + } return d_ptr->platformBackingStore; } diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index d2fe87d560..aef4ea1522 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -1141,7 +1141,8 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode() // #################### // block.setFloatPosition(node->cssFloat); - if (wsm == QTextHtmlParserNode::WhiteSpacePre) { + if (wsm == QTextHtmlParserNode::WhiteSpacePre + || wsm == QTextHtmlParserNode::WhiteSpaceNoWrap) { block.setNonBreakableLines(true); modifiedBlockFormat = true; } diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index aa2d36423d..10df85f68e 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -1429,8 +1429,8 @@ QT_WARNING_POP reinterpret_cast<const OS2Table *>(fontData.constData() + qFromBigEndian<quint32>(os2TableEntry->offset)); - bool italic = qFromBigEndian<quint16>(os2Table->selection) & 1; - bool oblique = qFromBigEndian<quint16>(os2Table->selection) & 128; + bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0); + bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9); if (italic) fontEngine->fontDef.style = QFont::StyleItalic; diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp index f68ea54dcf..db2186644b 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp @@ -115,30 +115,33 @@ static FontKeys &fontKeys() { static FontKeys result; if (result.isEmpty()) { - const QSettings fontRegistry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), - QSettings::NativeFormat); - const QStringList allKeys = fontRegistry.allKeys(); - const QString trueType = QStringLiteral("(TrueType)"); + const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), + QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") }; + for (const auto key : keys) { + const QSettings fontRegistry(key, QSettings::NativeFormat); + const QStringList allKeys = fontRegistry.allKeys(); + const QString trueType = QStringLiteral("(TrueType)"); #if QT_CONFIG(regularexpression) - const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+")); + const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+")); #else - const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+")); + const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+")); #endif - Q_ASSERT(sizeListMatch.isValid()); - const int size = allKeys.size(); - result.reserve(size); - for (int i = 0; i < size; ++i) { - FontKey fontKey; - const QString ®istryFontKey = allKeys.at(i); - fontKey.fileName = fontRegistry.value(registryFontKey).toString(); - QString realKey = registryFontKey; - realKey.remove(trueType); - realKey.remove(sizeListMatch); - const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&')); - fontKey.fontNames.reserve(fontNames.size()); - for (const QStringRef &fontName : fontNames) - fontKey.fontNames.append(fontName.trimmed().toString()); - result.append(fontKey); + Q_ASSERT(sizeListMatch.isValid()); + const int size = allKeys.size(); + result.reserve(result.size() + size); + for (int i = 0; i < size; ++i) { + FontKey fontKey; + const QString ®istryFontKey = allKeys.at(i); + fontKey.fileName = fontRegistry.value(registryFontKey).toString(); + QString realKey = registryFontKey; + realKey.remove(trueType); + realKey.remove(sizeListMatch); + const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&')); + fontKey.fontNames.reserve(fontNames.size()); + for (const QStringRef &fontName : fontNames) + fontKey.fontNames.append(fontName.trimmed().toString()); + result.append(fontKey); + } } } return result; diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm index 36c11ba8af..830a387fd1 100644 --- a/src/plugins/platforms/cocoa/qcocoascreen.mm +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -269,15 +269,14 @@ struct DeferredDebugHelper void QCocoaScreen::deliverUpdateRequests() { - if (!QGuiApplication::instance()) - return; + QMacAutoReleasePool pool; // The CVDisplayLink callback is a notification that it's a good time to produce a new frame. // Since the callback is delivered on a separate thread we have to marshal it over to the // main thread, as Qt requires update requests to be delivered there. This needs to happen // asynchronously, as otherwise we may end up deadlocking if the main thread calls back // into any of the CVDisplayLink APIs. - if (QThread::currentThread() != QGuiApplication::instance()->thread()) { + if (!NSThread.isMainThread) { // We're explicitly not using the data of the GCD source to track the pending updates, // as the data isn't reset to 0 until after the event handler, and also doesn't update // during the event handler, both of which we need to track late frames. diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index bf0a1216be..6bedbb556d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1513,9 +1513,9 @@ void QCocoaWindow::deliverUpdateRequest() void QCocoaWindow::requestActivateWindow() { - NSWindow *window = [m_view window]; - [window makeFirstResponder:m_view]; - [window makeKeyWindow]; + QMacAutoReleasePool pool; + [m_view.window makeFirstResponder:m_view]; + [m_view.window makeKeyWindow]; } QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel) diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 14f1ca0114..087cb3651f 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -102,40 +102,6 @@ static QCocoaWindow *toPlatformWindow(NSWindow *window) return QCocoaScreen::mapToNative(maximizedFrame); } -#pragma clang diagnostic push -// NSDisableScreenUpdates and NSEnableScreenUpdates are deprecated, but the -// NSAnimationContext API that replaces them doesn't handle the use-case of -// cross-thread screen update synchronization. -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)frameSize -{ - Q_ASSERT(toPlatformWindow(window)); - - qCDebug(lcQpaWindow) << window << "will resize to" << QSizeF::fromCGSize(frameSize) - << "- disabling screen updates temporarily"; - - // There may be separate threads rendering to CA layers in this window, - // and if any of them do a swap while the resize is still in progress, - // the visual bounds of that layer will be updated before the visual - // bounds of the window frame, resulting in flickering while resizing. - - // To prevent this we disable screen updates for the whole process until - // the resize is complete, which makes the whole thing visually atomic. - NSDisableScreenUpdates(); - - return frameSize; -} - -- (void)windowDidResize:(NSNotification *)notification -{ - NSWindow *window = notification.object; - Q_ASSERT(toPlatformWindow(window)); - - qCDebug(lcQpaWindow) << window << "was resized - re-enabling screen updates"; - NSEnableScreenUpdates(); -} -#pragma clang diagnostic pop - - (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu { Q_UNUSED(menu); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp index 1e4f4e72c8..f154520669 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp @@ -63,7 +63,6 @@ QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration() #ifndef EGL_EXT_platform_base typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list); -typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list); #endif #ifndef EGL_PLATFORM_GBM_KHR diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp index 65a7c4f38a..a93762e5b4 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmwindow.cpp @@ -45,6 +45,10 @@ QT_BEGIN_NAMESPACE +#ifndef EGL_EXT_platform_base +typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list); +#endif + void QEglFSKmsGbmWindow::resetSurface() { QEglFSKmsGbmScreen *gbmScreen = static_cast<QEglFSKmsGbmScreen *>(screen()); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 2b96fb3a5e..41655dbd57 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -334,12 +334,8 @@ bool QWindowsContext::initTouch(unsigned integrationOptions) if (!touchDevice) return false; - if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) { - QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); - } else { - if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) - touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation); - } + if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) + touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation); QWindowSystemInterface::registerTouchDevice(touchDevice); @@ -376,7 +372,6 @@ bool QWindowsContext::initPointer(unsigned integrationOptions) if (!QWindowsContext::user32dll.supportsPointerApi()) return false; - QWindowsContext::user32dll.enableMouseInPointer(TRUE); d->m_systemInfo |= QWindowsContext::SI_SupportsPointer; return true; } @@ -1218,9 +1213,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::ExposeEvent: return platformWindow->handleWmPaint(hwnd, message, wParam, lParam); case QtWindows::NonClientMouseEvent: - if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) + if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) + return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); + else return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); - break; case QtWindows::NonClientPointerEvent: if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled()) return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result); @@ -1246,10 +1242,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, window = window->parent(); if (!window) return false; - if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer)) - return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result); - else + if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result); + else + return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result); } break; case QtWindows::TouchEvent: diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 203d803a1b..f1960f1585 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -50,9 +50,6 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsscreen.h" -#if QT_CONFIG(draganddrop) -# include "qwindowsdrag.h" -#endif #include <QtGui/qguiapplication.h> #include <QtGui/qscreen.h> @@ -78,111 +75,9 @@ enum { QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD }; -struct PointerTouchEventInfo { - QPointer<QWindow> window; - QList<QWindowSystemInterface::TouchPoint> points; - Qt::KeyboardModifiers modifiers; -}; - -struct PointerTabletEventInfo { - QPointer<QWindow> window; - QPointF local; - QPointF global; - int device; - int pointerType; - Qt::MouseButtons buttons; - qreal pressure; - int xTilt; - int yTilt; - qreal tangentialPressure; - qreal rotation; - int z; - qint64 uid; - Qt::KeyboardModifiers modifiers; -}; - -static QQueue<PointerTouchEventInfo> touchEventQueue; -static QQueue<PointerTabletEventInfo> tabletEventQueue; - -static void enqueueTouchEvent(QWindow *window, - const QList<QWindowSystemInterface::TouchPoint> &points, - Qt::KeyboardModifiers modifiers) -{ - PointerTouchEventInfo eventInfo; - eventInfo.window = window; - eventInfo.points = points; - eventInfo.modifiers = modifiers; - touchEventQueue.enqueue(eventInfo); -} - -static void enqueueTabletEvent(QWindow *window, const QPointF &local, const QPointF &global, - int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, - int xTilt, int yTilt, qreal tangentialPressure, qreal rotation, - int z, qint64 uid, Qt::KeyboardModifiers modifiers) -{ - PointerTabletEventInfo eventInfo; - eventInfo.window = window; - eventInfo.local = local; - eventInfo.global = global; - eventInfo.device = device; - eventInfo.pointerType = pointerType; - eventInfo.buttons = buttons; - eventInfo.pressure = pressure; - eventInfo.xTilt = xTilt; - eventInfo.yTilt = yTilt; - eventInfo.tangentialPressure = tangentialPressure; - eventInfo.rotation = rotation; - eventInfo.z = z; - eventInfo.uid = uid; - eventInfo.modifiers = modifiers; - tabletEventQueue.enqueue(eventInfo); -} - -static void flushTouchEvents(QTouchDevice *touchDevice) -{ - while (!touchEventQueue.isEmpty()) { - PointerTouchEventInfo eventInfo = touchEventQueue.dequeue(); - if (eventInfo.window) { - QWindowSystemInterface::handleTouchEvent(eventInfo.window, - touchDevice, - eventInfo.points, - eventInfo.modifiers); - } - } -} - -static void flushTabletEvents() -{ - while (!tabletEventQueue.isEmpty()) { - PointerTabletEventInfo eventInfo = tabletEventQueue.dequeue(); - if (eventInfo.window) { - QWindowSystemInterface::handleTabletEvent(eventInfo.window, - eventInfo.local, - eventInfo.global, - eventInfo.device, - eventInfo.pointerType, - eventInfo.buttons, - eventInfo.pressure, - eventInfo.xTilt, - eventInfo.yTilt, - eventInfo.tangentialPressure, - eventInfo.rotation, - eventInfo.z, - eventInfo.uid, - eventInfo.modifiers); - } - } -} - bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) { *result = 0; - - // If we are inside the move/resize modal loop, let DefWindowProc() handle it (but process NC button release). - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); - if (msg.message != WM_NCPOINTERUP && platformWindow->testFlag(QWindowsWindow::ResizeMoveActive)) - return false; - const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam); POINTER_INPUT_TYPE pointerType; @@ -191,30 +86,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q return false; } - m_lastPointerType = pointerType; - - // Handle non-client pen/touch as generic mouse events for compatibility with QDockWindow. - if ((pointerType == QT_PT_TOUCH || pointerType == QT_PT_PEN) && (et & QtWindows::NonClientEventFlag)) { - POINTER_INFO pointerInfo; - if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) { - qWarning() << "GetPointerInfo() failed:" << qt_error_string(); - return false; - } - if (pointerInfo.pointerFlags & (POINTER_FLAG_UP | POINTER_FLAG_DOWN)) - return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo); - return false; - } - switch (pointerType) { case QT_PT_POINTER: case QT_PT_MOUSE: case QT_PT_TOUCHPAD: { - POINTER_INFO pointerInfo; - if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) { - qWarning() << "GetPointerInfo() failed:" << qt_error_string(); - return false; - } - return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo); + // Let Mouse/TouchPad be handled using legacy messages. + return false; } case QT_PT_TOUCH: { quint32 pointerCount = 0; @@ -290,76 +167,71 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q return false; } -static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QEvent::Type *eventType, Qt::MouseButton *mouseButton) -{ - static const QHash<POINTER_BUTTON_CHANGE_TYPE, Qt::MouseButton> buttonMapping { - {POINTER_CHANGE_FIRSTBUTTON_DOWN, Qt::LeftButton}, - {POINTER_CHANGE_FIRSTBUTTON_UP, Qt::LeftButton}, - {POINTER_CHANGE_SECONDBUTTON_DOWN, Qt::RightButton}, - {POINTER_CHANGE_SECONDBUTTON_UP, Qt::RightButton}, - {POINTER_CHANGE_THIRDBUTTON_DOWN, Qt::MiddleButton}, - {POINTER_CHANGE_THIRDBUTTON_UP, Qt::MiddleButton}, - {POINTER_CHANGE_FOURTHBUTTON_DOWN, Qt::XButton1}, - {POINTER_CHANGE_FOURTHBUTTON_UP, Qt::XButton1}, - {POINTER_CHANGE_FIFTHBUTTON_DOWN, Qt::XButton2}, - {POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2}, - }; - - static const POINTER_BUTTON_CHANGE_TYPE downChanges[] = { - POINTER_CHANGE_FIRSTBUTTON_DOWN, - POINTER_CHANGE_SECONDBUTTON_DOWN, - POINTER_CHANGE_THIRDBUTTON_DOWN, - POINTER_CHANGE_FOURTHBUTTON_DOWN, - POINTER_CHANGE_FIFTHBUTTON_DOWN, - }; - - static const POINTER_BUTTON_CHANGE_TYPE upChanges[] = { - POINTER_CHANGE_FIRSTBUTTON_UP, - POINTER_CHANGE_SECONDBUTTON_UP, - POINTER_CHANGE_THIRDBUTTON_UP, - POINTER_CHANGE_FOURTHBUTTON_UP, - POINTER_CHANGE_FIFTHBUTTON_UP, - }; - - if (!eventType || !mouseButton) - return; - - const bool nonClient = message == WM_NCPOINTERUPDATE || - message == WM_NCPOINTERDOWN || - message == WM_NCPOINTERUP; - - if (std::find(std::begin(downChanges), - std::end(downChanges), changeType) < std::end(downChanges)) { - *eventType = nonClient ? QEvent::NonClientAreaMouseButtonPress : - QEvent::MouseButtonPress; - } else if (std::find(std::begin(upChanges), - std::end(upChanges), changeType) < std::end(upChanges)) { - *eventType = nonClient ? QEvent::NonClientAreaMouseButtonRelease : - QEvent::MouseButtonRelease; - } else if (message == WM_POINTERWHEEL || message == WM_POINTERHWHEEL) { - *eventType = QEvent::Wheel; - } else { - *eventType = nonClient ? QEvent::NonClientAreaMouseMove : - QEvent::MouseMove; - } +namespace { +struct MouseEvent { + QEvent::Type type; + Qt::MouseButton button; +}; +} // namespace - *mouseButton = buttonMapping.value(changeType, Qt::NoButton); +static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON... +{ + return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton; } -static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags) +static inline MouseEvent eventFromMsg(const MSG &msg) { - Qt::MouseButtons result = Qt::NoButton; - if (pointerFlags & POINTER_FLAG_FIRSTBUTTON) - result |= Qt::LeftButton; - if (pointerFlags & POINTER_FLAG_SECONDBUTTON) - result |= Qt::RightButton; - if (pointerFlags & POINTER_FLAG_THIRDBUTTON) - result |= Qt::MiddleButton; - if (pointerFlags & POINTER_FLAG_FOURTHBUTTON) - result |= Qt::XButton1; - if (pointerFlags & POINTER_FLAG_FIFTHBUTTON) - result |= Qt::XButton2; - return result; + switch (msg.message) { + case WM_MOUSEMOVE: + return {QEvent::MouseMove, Qt::NoButton}; + case WM_LBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::LeftButton}; + case WM_LBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::LeftButton}; + case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press + return {QEvent::MouseButtonPress, Qt::LeftButton}; + case WM_MBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::MidButton}; + case WM_MBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::MidButton}; + case WM_MBUTTONDBLCLK: + return {QEvent::MouseButtonPress, Qt::MidButton}; + case WM_RBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::RightButton}; + case WM_RBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::RightButton}; + case WM_RBUTTONDBLCLK: + return {QEvent::MouseButtonPress, Qt::RightButton}; + case WM_XBUTTONDOWN: + return {QEvent::MouseButtonPress, extraButton(msg.wParam)}; + case WM_XBUTTONUP: + return {QEvent::MouseButtonRelease, extraButton(msg.wParam)}; + case WM_XBUTTONDBLCLK: + return {QEvent::MouseButtonPress, extraButton(msg.wParam)}; + case WM_NCMOUSEMOVE: + return {QEvent::NonClientAreaMouseMove, Qt::NoButton}; + case WM_NCLBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton}; + case WM_NCLBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton}; + case WM_NCLBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton}; + case WM_NCMBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton}; + case WM_NCMBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton}; + case WM_NCMBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton}; + case WM_NCRBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton}; + case WM_NCRBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton}; + case WM_NCRBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton}; + default: // WM_MOUSELEAVE + break; + } + return {QEvent::None, Qt::NoButton}; } static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState) @@ -419,15 +291,6 @@ static bool isValidWheelReceiver(QWindow *candidate) return false; } -static bool isMenuWindow(QWindow *window) -{ - if (window) - if (QObject *fo = window->focusObject()) - if (fo->inherits("QMenu")) - return true; - return false; -} - static QTouchDevice *createTouchDevice() { const int digitizers = GetSystemMetrics(SM_DIGITIZER); @@ -553,71 +416,6 @@ void QWindowsPointerHandler::handleEnterLeave(QWindow *window, m_previousCaptureWindow = hasCapture ? window : nullptr; } -bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd, - QtWindows::WindowsEventType et, - MSG msg, PVOID vPointerInfo) -{ - POINTER_INFO *pointerInfo = static_cast<POINTER_INFO *>(vPointerInfo); - const QPoint globalPos = QPoint(pointerInfo->ptPixelLocation.x, pointerInfo->ptPixelLocation.y); - const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); - const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - const Qt::MouseButtons mouseButtons = mouseButtonsFromPointerFlags(pointerInfo->pointerFlags); - QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - - switch (msg.message) { - case WM_NCPOINTERDOWN: - case WM_NCPOINTERUP: - case WM_NCPOINTERUPDATE: - case WM_POINTERDOWN: - case WM_POINTERUP: - case WM_POINTERUPDATE: { - - QEvent::Type eventType; - Qt::MouseButton button; - getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, &eventType, &button); - - if (et & QtWindows::NonClientEventFlag) { - QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType, - keyModifiers, Qt::MouseEventNotSynthesized); - return false; // To allow window dragging, etc. - } else { - - handleCaptureRelease(window, currentWindowUnderPointer, hwnd, eventType, mouseButtons); - handleEnterLeave(window, currentWindowUnderPointer, globalPos); - - QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType, - keyModifiers, Qt::MouseEventNotSynthesized); - - // The initial down click over the QSizeGrip area, which posts a resize WM_SYSCOMMAND - // has go to through DefWindowProc() for resizing to work, so we return false here, - // unless the click was on a menu, as it would mess with menu processing. - return msg.message != WM_POINTERDOWN || isMenuWindow(window); - } - } - case WM_POINTERHWHEEL: - case WM_POINTERWHEEL: { - - if (!isValidWheelReceiver(window)) - return true; - - int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); - - // Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL - if (msg.message == WM_POINTERHWHEEL) - delta = -delta; - - const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ? - QPoint(delta, 0) : QPoint(0, delta); - - QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); - return true; - } - case WM_POINTERLEAVE: - return true; - } - return false; -} - bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, quint32 count) @@ -653,15 +451,14 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QList<QWindowSystemInterface::TouchPoint> touchPoints; - bool primaryPointer = false; - bool pressRelease = false; - if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase << __FUNCTION__ << " message=" << hex << msg.message << " count=" << dec << count; + Qt::TouchPointStates allStates = 0; + for (quint32 i = 0; i < count; ++i) { if (QWindowsContext::verbose > 1) qCDebug(lcQpaEvents).noquote().nospace() << showbase @@ -670,7 +467,13 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, << " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags; QWindowSystemInterface::TouchPoint touchPoint; - touchPoint.id = touchInfo[i].pointerInfo.pointerId; + const quint32 pointerId = touchInfo[i].pointerInfo.pointerId; + int id = m_touchInputIDToTouchPointID.value(pointerId, -1); + if (id == -1) { + id = m_touchInputIDToTouchPointID.size(); + m_touchInputIDToTouchPointID.insert(pointerId, id); + } + touchPoint.id = id; touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ? touchInfo[i].pressure / 1024.0 : 1.0; if (m_lastTouchPositions.contains(touchPoint.id)) @@ -691,32 +494,27 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) { touchPoint.state = Qt::TouchPointPressed; m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); - pressRelease = true; } else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) { touchPoint.state = Qt::TouchPointReleased; m_lastTouchPositions.remove(touchPoint.id); - pressRelease = true; } else { touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved; m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); } - if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) - primaryPointer = true; + allStates |= touchPoint.state; touchPoints.append(touchPoint); // Avoid getting repeated messages for this frame if there are multiple pointerIds QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } - if (primaryPointer && !pressRelease) { - // Postpone event delivery to avoid hanging inside DoDragDrop(). - // Only the primary pointer will generate mouse messages. - enqueueTouchEvent(window, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers()); - } else { - flushTouchEvents(m_touchDevice); - QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, - QWindowsKeyMapper::queryKeyboardModifiers()); - } + + // all touch points released, forget the ids we've seen. + if (allStates == Qt::TouchPointReleased) + m_touchInputIDToTouchPointID.clear(); + + QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, + QWindowsKeyMapper::queryKeyboardModifiers()); return false; // Allow mouse messages to be generated. } @@ -807,10 +605,9 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - // Postpone event delivery to avoid hanging inside DoDragDrop(). - enqueueTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, - pressure, xTilt, yTilt, tangentialPressure, rotation, z, - pointerId, keyModifiers); + QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, + pressure, xTilt, yTilt, tangentialPressure, rotation, z, + pointerId, keyModifiers); return false; // Allow mouse messages to be generated. } } @@ -835,18 +632,46 @@ static inline bool isMouseEventSynthesizedFromPenOrTouch() return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE); } -// Process old-style mouse messages here. -bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) +bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window, + QWindow *currentWindowUnderPointer, + MSG msg, + QPoint globalPos, + Qt::KeyboardModifiers keyModifiers) { - // Generate enqueued events. - flushTouchEvents(m_touchDevice); - flushTabletEvents(); + QWindow *receiver = currentWindowUnderPointer; + if (!isValidWheelReceiver(receiver)) + receiver = window; + if (!isValidWheelReceiver(receiver)) + return true; + + int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); + // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL + if (msg.message == WM_MOUSEHWHEEL) + delta = -delta; + + const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ? + QPoint(delta, 0) : QPoint(0, delta); + + QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos); + + QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); + return true; +} + +// Process legacy mouse messages here. +bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, + HWND hwnd, + QtWindows::WindowsEventType et, + MSG msg, + LRESULT *result) +{ *result = 0; const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); QPoint localPos; QPoint globalPos; + if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) { globalPos = eventPos; localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos); @@ -857,46 +682,39 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); + QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - // Handle "press and hold for right-clicking". - // We have to synthesize it here as it only comes from Windows as a fake RMB. - // MS docs say we could use bit 7 from extraInfo to distinguish pen from touch, - // but on the Surface it is set for both. So we use the last pointer type. - if (isMouseEventSynthesizedFromPenOrTouch()) { - if ((msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP) - && (((m_lastPointerType == QT_PT_PEN) - && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) - || ((m_lastPointerType == QT_PT_TOUCH) - && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)))) { - QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::RightButton, - (msg.message == WM_RBUTTONDOWN) ? QEvent::MouseButtonPress - : QEvent::MouseButtonRelease, - keyModifiers, Qt::MouseEventSynthesizedBySystem); - } - // Messages synthesized from touch/pen are only used for flushing queues and press&hold. - return false; + if (et == QtWindows::MouseWheelEvent) + return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers); + + // Windows sends a mouse move with no buttons pressed to signal "Enter" + // when a window is shown over the cursor. Discard the event and only use + // it for generating QEvent::Enter to be consistent with other platforms - + // X11 and macOS. + bool discardEvent = false; + if (msg.message == WM_MOUSEMOVE) { + static QPoint lastMouseMovePos; + if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos)) + discardEvent = true; + lastMouseMovePos = globalPos; } - if (et == QtWindows::MouseWheelEvent) { - - if (!isValidWheelReceiver(window)) - return true; - - int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam); - - // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL - if (msg.message == WM_MOUSEHWHEEL) - delta = -delta; + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; + if (isMouseEventSynthesizedFromPenOrTouch()) { + if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch) + return false; + source = Qt::MouseEventSynthesizedBySystem; + } - const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ? - QPoint(delta, 0) : QPoint(0, delta); + const MouseEvent mouseEvent = eventFromMsg(msg); - QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers); - return true; + if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { + QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, + mouseEvent.button, mouseEvent.type, keyModifiers, source); + return false; // Allow further event processing } if (msg.message == WM_MOUSELEAVE) { - if (window == m_currentWindow) { QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow; qCDebug(lcQpaEvents) << "Leaving window " << leaveTarget; @@ -904,14 +722,21 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = nullptr; m_currentWindow = nullptr; } + return true; + } - } else if (msg.message == WM_MOUSEMOVE) { + handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons); + handleEnterLeave(window, currentWindowUnderPointer, globalPos); - QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); - handleCaptureRelease(window, currentWindowUnderPointer, hwnd, QEvent::MouseMove, mouseButtons); - handleEnterLeave(window, currentWindowUnderPointer, globalPos); + if (!discardEvent && mouseEvent.type != QEvent::None) { + QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, + mouseEvent.button, mouseEvent.type, keyModifiers, source); } - return false; + + // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND + // is sent for unhandled WM_XBUTTONDOWN. + return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK) + || QWindowSystemInterface::flushWindowSystemEvents(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index ec3179e821..aebef062bc 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -66,19 +66,19 @@ public: void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; } private: - bool translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo); bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count); bool translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo); + bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers); void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons); void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos); QTouchDevice *m_touchDevice = nullptr; QHash<int, QPointF> m_lastTouchPositions; + QHash<DWORD, int> m_touchInputIDToTouchPointID; QPointer<QWindow> m_windowUnderPointer; QPointer<QWindow> m_currentWindow; QWindow *m_previousCaptureWindow = nullptr; bool m_needsEnterOnPointerUpdate = false; - DWORD m_lastPointerType = 0; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 7f1854c601..e611c7be24 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -511,6 +511,7 @@ public: QWindow *currentPressWindow = nullptr; QWindow *currentTargetWindow = nullptr; bool firstMouseMove = true; + bool resizePending = false; }; // To be called from the XAML thread @@ -1402,6 +1403,18 @@ void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransitio Qt::NoModifier); } +void QWinRTScreen::setResizePending() +{ + Q_D(QWinRTScreen); + d->resizePending = true; +} + +bool QWinRTScreen::resizePending() const +{ + Q_D(const QWinRTScreen); + return d->resizePending; +} + HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { Q_D(QWinRTScreen); @@ -1507,7 +1520,7 @@ HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEvent return onPointerUpdated(nullptr, args); } -HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *) +HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *w, IInspectable *) { Q_D(QWinRTScreen); @@ -1527,6 +1540,9 @@ HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *) QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry()); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); + // If we "emulate" a resize, w will be nullptr.Checking w shows whether it's a real resize + if (w) + d->resizePending = false; return S_OK; } diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index e28cfd8cc8..63c254940d 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -136,6 +136,9 @@ public: void emulateMouseMove(const QPointF &point, MousePositionTransition transition); + void setResizePending(); + bool resizePending() const; + private: void handleExpose(); diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index 83c3715bfd..73816b6512 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -225,7 +225,8 @@ bool QWinRTWindow::isActive() const bool QWinRTWindow::isExposed() const { - const bool exposed = isActive(); + Q_D(const QWinRTWindow); + const bool exposed = isActive() && !d->screen->resizePending(); return exposed; } @@ -360,6 +361,7 @@ void QWinRTWindow::setWindowState(Qt::WindowStates state) qCDebug(lcQpaWindows) << "Failed to enter full screen mode."; return; } + d->screen->setResizePending(); d->state = state; return; } @@ -384,6 +386,7 @@ void QWinRTWindow::setWindowState(Qt::WindowStates state) qCDebug(lcQpaWindows) << "Failed to exit full screen mode."; return; } + d->screen->setResizePending(); } if (d->state & Qt::WindowMinimized || state == Qt::WindowNoState || state == Qt::WindowActive) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index b91d637766..6a5f80f1ff 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -8298,49 +8298,57 @@ void QWidgetPrivate::hide_sys() \endlist */ - void QWidget::setVisible(bool visible) { - if (visible) { // show - if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)) - return; + if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) == !visible) + return; - Q_D(QWidget); + // Remember that setVisible was called explicitly + setAttribute(Qt::WA_WState_ExplicitShowHide); + + Q_D(QWidget); + d->setVisible(visible); +} +// This method is called from QWidgetWindow in response to QWindow::setVisible, +// and should match the semantics of QWindow::setVisible. QWidget::setVisible on +// the other hand keeps track of WA_WState_ExplicitShowHide in addition. +void QWidgetPrivate::setVisible(bool visible) +{ + Q_Q(QWidget); + if (visible) { // show // Designer uses a trick to make grabWidget work without showing - if (!isWindow() && parentWidget() && parentWidget()->isVisible() - && !parentWidget()->testAttribute(Qt::WA_WState_Created)) - parentWidget()->window()->d_func()->createRecursively(); + if (!q->isWindow() && q->parentWidget() && q->parentWidget()->isVisible() + && !q->parentWidget()->testAttribute(Qt::WA_WState_Created)) + q->parentWidget()->window()->d_func()->createRecursively(); //create toplevels but not children of non-visible parents - QWidget *pw = parentWidget(); - if (!testAttribute(Qt::WA_WState_Created) - && (isWindow() || pw->testAttribute(Qt::WA_WState_Created))) { - create(); + QWidget *pw = q->parentWidget(); + if (!q->testAttribute(Qt::WA_WState_Created) + && (q->isWindow() || pw->testAttribute(Qt::WA_WState_Created))) { + q->create(); } - bool wasResized = testAttribute(Qt::WA_Resized); - Qt::WindowStates initialWindowState = windowState(); + bool wasResized = q->testAttribute(Qt::WA_Resized); + Qt::WindowStates initialWindowState = q->windowState(); // polish if necessary - ensurePolished(); + q->ensurePolished(); - // remember that show was called explicitly - setAttribute(Qt::WA_WState_ExplicitShowHide); // whether we need to inform the parent widget immediately - bool needUpdateGeometry = !isWindow() && testAttribute(Qt::WA_WState_Hidden); + bool needUpdateGeometry = !q->isWindow() && q->testAttribute(Qt::WA_WState_Hidden); // we are no longer hidden - setAttribute(Qt::WA_WState_Hidden, false); + q->setAttribute(Qt::WA_WState_Hidden, false); if (needUpdateGeometry) - d->updateGeometry_helper(true); + updateGeometry_helper(true); // activate our layout before we and our children become visible - if (d->layout) - d->layout->activate(); + if (layout) + layout->activate(); - if (!isWindow()) { - QWidget *parent = parentWidget(); + if (!q->isWindow()) { + QWidget *parent = q->parentWidget(); while (parent && parent->isVisible() && parent->d_func()->layout && !parent->data->in_show) { parent->d_func()->layout->activate(); if (parent->isWindow()) @@ -8353,30 +8361,28 @@ void QWidget::setVisible(bool visible) // adjust size if necessary if (!wasResized - && (isWindow() || !parentWidget()->d_func()->layout)) { - if (isWindow()) { - adjustSize(); - if (windowState() != initialWindowState) - setWindowState(initialWindowState); + && (q->isWindow() || !q->parentWidget()->d_func()->layout)) { + if (q->isWindow()) { + q->adjustSize(); + if (q->windowState() != initialWindowState) + q->setWindowState(initialWindowState); } else { - adjustSize(); + q->adjustSize(); } - setAttribute(Qt::WA_Resized, false); + q->setAttribute(Qt::WA_Resized, false); } - setAttribute(Qt::WA_KeyboardFocusChange, false); + q->setAttribute(Qt::WA_KeyboardFocusChange, false); - if (isWindow() || parentWidget()->isVisible()) { - d->show_helper(); + if (q->isWindow() || q->parentWidget()->isVisible()) { + show_helper(); - qApp->d_func()->sendSyntheticEnterLeave(this); + qApp->d_func()->sendSyntheticEnterLeave(q); } QEvent showToParentEvent(QEvent::ShowToParent); - QApplication::sendEvent(this, &showToParentEvent); + QApplication::sendEvent(q, &showToParentEvent); } else { // hide - if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden)) - return; #if 0 // Used to be included in Qt4 for Q_WS_WIN // reset WS_DISABLED style in a Blocked window if(isWindow() && testAttribute(Qt::WA_WState_Created) @@ -8387,33 +8393,30 @@ void QWidget::setVisible(bool visible) SetWindowLong(winId(), GWL_STYLE, dwStyle); } #endif - if (QApplicationPrivate::hidden_focus_widget == this) + if (QApplicationPrivate::hidden_focus_widget == q) QApplicationPrivate::hidden_focus_widget = 0; - Q_D(QWidget); - // hw: The test on getOpaqueRegion() needs to be more intelligent // currently it doesn't work if the widget is hidden (the region will // be clipped). The real check should be testing the cached region // (and dirty flag) directly. - if (!isWindow() && parentWidget()) // && !d->getOpaqueRegion().isEmpty()) - parentWidget()->d_func()->setDirtyOpaqueRegion(); + if (!q->isWindow() && q->parentWidget()) // && !d->getOpaqueRegion().isEmpty()) + q->parentWidget()->d_func()->setDirtyOpaqueRegion(); - setAttribute(Qt::WA_WState_Hidden); - setAttribute(Qt::WA_WState_ExplicitShowHide); - if (testAttribute(Qt::WA_WState_Created)) - d->hide_helper(); + q->setAttribute(Qt::WA_WState_Hidden); + if (q->testAttribute(Qt::WA_WState_Created)) + hide_helper(); // invalidate layout similar to updateGeometry() - if (!isWindow() && parentWidget()) { - if (parentWidget()->d_func()->layout) - parentWidget()->d_func()->layout->invalidate(); - else if (parentWidget()->isVisible()) - QApplication::postEvent(parentWidget(), new QEvent(QEvent::LayoutRequest)); + if (!q->isWindow() && q->parentWidget()) { + if (q->parentWidget()->d_func()->layout) + q->parentWidget()->d_func()->layout->invalidate(); + else if (q->parentWidget()->isVisible()) + QApplication::postEvent(q->parentWidget(), new QEvent(QEvent::LayoutRequest)); } QEvent hideToParentEvent(QEvent::HideToParent); - QApplication::sendEvent(this, &hideToParentEvent); + QApplication::sendEvent(q, &hideToParentEvent); } } diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index e50d828775..797963b931 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -485,6 +485,7 @@ public: void hide_sys(); void hide_helper(); void _q_showIfNotHidden(); + void setVisible(bool); void setEnabled_helper(bool); static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0); diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 991a05fa02..e9b749d7c2 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -73,7 +73,7 @@ public: { Q_Q(QWidgetWindow); if (QWidget *widget = q->widget()) - widget->setVisible(visible); + QWidgetPrivate::get(widget)->setVisible(visible); else QWindowPrivate::setVisible(visible); } diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp index 7637877926..47c5267c73 100644 --- a/src/widgets/widgets/qcalendarwidget.cpp +++ b/src/widgets/widgets/qcalendarwidget.cpp @@ -3064,19 +3064,22 @@ bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event) { Q_D(QCalendarWidget); if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus()) { + // We can get filtered press events that were intended for Qt Virtual Keyboard's + // input panel (QQuickView), so we have to make sure that the window is indeed a QWidget - no static_cast. + // In addition, as we have a event filter on the whole application we first make sure that the top level widget + // of both this and the watched widget are the same to decide if we should finish the year edition. QWidget *tlw = window(); - QWidget *widget = static_cast<QWidget*>(watched); - //as we have a event filter on the whole application we first make sure that the top level widget - //of both this and the watched widget are the same to decide if we should finish the year edition. - if (widget->window() == tlw) { - QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos()); - QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size()); - if (!geom.contains(mousePos)) { - event->accept(); - d->_q_yearEditingFinished(); - setFocus(); - return true; - } + QWidget *widget = qobject_cast<QWidget *>(watched); + if (!widget || widget->window() != tlw) + return QWidget::eventFilter(watched, event); + + QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos()); + QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size()); + if (!geom.contains(mousePos)) { + event->accept(); + d->_q_yearEditingFinished(); + setFocus(); + return true; } } return QWidget::eventFilter(watched, event); |