From 35069301f048eed21a27f89b6495d56c44f2b55d Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 30 Oct 2018 17:58:17 +0100 Subject: Windows QPA: Fix incorrect button state reporting for touchpad The current state of (emulated) mouse buttons was being incorrectly reported for touchpad events under some conditions. In the handling of pointer messages, GetAsyncKeyState() was being used to retrieve the mouse button state. However, it does not seem to work always with all touchpads. Furthermore, its use is not necessary, since the button state information comes as a set of flags with the pointer message itself. This change makes the handler use these flags instead. Fixes: QTBUG-71470 Change-Id: Ie2e35bd80778ef74db672604a0f2af659785efbf Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowspointerhandler.cpp | 53 ++++++++++++++-------- .../platforms/windows/qwindowspointerhandler.h | 1 - 2 files changed, 34 insertions(+), 20 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 2b6c696979..4d3e2f71ec 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -336,6 +336,38 @@ static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeTyp *mouseButton = buttonMapping.value(changeType, Qt::NoButton); } +static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags) +{ + 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; +} + +static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState) +{ + Qt::MouseButtons result = Qt::NoButton; + if (keyState & MK_LBUTTON) + result |= Qt::LeftButton; + if (keyState & MK_RBUTTON) + result |= Qt::RightButton; + if (keyState & MK_MBUTTON) + result |= Qt::MiddleButton; + if (keyState & MK_XBUTTON1) + result |= Qt::XButton1; + if (keyState & MK_XBUTTON2) + result |= Qt::XButton2; + return result; +} + static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) { QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); @@ -405,23 +437,6 @@ QTouchDevice *QWindowsPointerHandler::ensureTouchDevice() return m_touchDevice; } -Qt::MouseButtons QWindowsPointerHandler::queryMouseButtons() -{ - Qt::MouseButtons result = 0; - 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; -} - bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo) @@ -430,7 +445,7 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h 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 = queryMouseButtons(); + const Qt::MouseButtons mouseButtons = mouseButtonsFromPointerFlags(pointerInfo->pointerFlags); QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos); QWindowsWindow *platformWindow = static_cast(window->handle()); @@ -788,7 +803,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW m_windowUnderPointer = currentWindowUnderPointer; } - const Qt::MouseButtons mouseButtons = queryMouseButtons(); + const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); if (!discardEvent) QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::NoButton, QEvent::MouseMove, diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index c4d0e0ce4a..3861ebf919 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -61,7 +61,6 @@ public: bool translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result); QTouchDevice *touchDevice() const { return m_touchDevice; } QTouchDevice *ensureTouchDevice(); - Qt::MouseButtons queryMouseButtons(); QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); } void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; } -- cgit v1.2.3 From 2697148775703883ae700b15d4efe240050273a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 22 Oct 2018 13:04:42 +0200 Subject: macOS: Only enable layer-backed views on 10.14 if built against 10.14 SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of explicitly enabling layer-backing for Qt 5.12 on all macOS version, we follow the macOS default to enable it for 10.14 if the application binary was built against the 10.14 SDK. Aligning ourselves with Apple's switch to forced layer-backing means we have an easier story when it comes to supporting different runtime configurations. Fixes: QTBUG-71499 Change-Id: I34ee49b3daeb6ed8df444a3759d3573ebc9ea30f Reviewed-by: Tor Arne Vestbø --- src/plugins/platforms/cocoa/qnsview.mm | 15 +------ src/plugins/platforms/cocoa/qnsview_drawing.mm | 61 +++++++++++++++++++++----- 2 files changed, 53 insertions(+), 23 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 9bd53ed334..540f701d43 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -71,7 +71,7 @@ @end @interface QT_MANGLE_NAMESPACE(QNSView) (Drawing) -- (BOOL)wantsLayerHelper; +- (void)initDrawing; @end @interface QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) : NSObject @@ -152,19 +152,8 @@ self.focusRingType = NSFocusRingTypeNone; self.cursor = nil; - self.wantsLayer = [self wantsLayerHelper]; - - // Enable high-DPI OpenGL for retina displays. Enabling has the side - // effect that Cocoa will start calling glViewport(0, 0, width, height), - // overriding any glViewport calls in application code. This is usually not a - // problem, except if the application wants to have a "custom" viewport. - // (like the hellogl example) - if (m_platformWindow->window()->supportsOpenGL()) { - self.wantsBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, m_platformWindow->window(), - "_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); - // See also QCocoaGLContext::makeCurrent for software renderer workarounds. - } + [self initDrawing]; [self registerDragTypes]; [[NSNotificationCenter defaultCenter] addObserver:self diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index 4f9d17504d..e9af90a45c 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -41,6 +41,24 @@ @implementation QT_MANGLE_NAMESPACE(QNSView) (Drawing) +- (void)initDrawing +{ + self.wantsLayer = [self layerExplicitlyRequested] + || [self shouldUseMetalLayer] + || [self layerEnabledByMacOS]; + + // Enable high-DPI OpenGL for retina displays. Enabling has the side + // effect that Cocoa will start calling glViewport(0, 0, width, height), + // overriding any glViewport calls in application code. This is usually not a + // problem, except if the application wants to have a "custom" viewport. + // (like the hellogl example) + if (m_platformWindow->window()->supportsOpenGL()) { + self.wantsBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, m_platformWindow->window(), + "_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); + // See also QCocoaGLContext::makeCurrent for software renderer workarounds. + } +} + - (BOOL)isOpaque { if (!m_platformWindow) @@ -71,23 +89,38 @@ m_platformWindow->handleExposeEvent(exposedRegion); } -- (BOOL)shouldUseMetalLayer +- (BOOL)layerEnabledByMacOS { - // MetalSurface needs a layer, and so does VulkanSurface (via MoltenVK) - QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType(); - return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface; + // AppKit has its own logic for this, but if we rely on that, our layers are created + // by AppKit at a point where we've already set up other parts of the platform plugin + // based on the presence of layers or not. Once we've rewritten these parts to support + // dynamically picking up layer enablement we can let AppKit do its thing. + return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave + && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave; } -- (BOOL)wantsLayerHelper +- (BOOL)layerExplicitlyRequested { - Q_ASSERT(m_platformWindow); + static bool wantsLayer = [&]() { + int wantsLayer = qt_mac_resolveOption(-1, m_platformWindow->window(), + "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); - bool wantsLayer = qt_mac_resolveOption(true, m_platformWindow->window(), - "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); + if (wantsLayer != -1 && [self layerEnabledByMacOS]) { + qCWarning(lcQpaDrawing) << "Layer-backing can not be explicitly controlled on 10.14 when built against the 10.14 SDK"; + return true; + } - bool layerForSurfaceType = [self shouldUseMetalLayer]; + return wantsLayer == 1; + }(); - return wantsLayer || layerForSurfaceType; + return wantsLayer; +} + +- (BOOL)shouldUseMetalLayer +{ + // MetalSurface needs a layer, and so does VulkanSurface (via MoltenVK) + QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType(); + return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface; } - (CALayer *)makeBackingLayer @@ -115,6 +148,14 @@ return [super makeBackingLayer]; } +- (void)setLayer:(CALayer *)layer +{ + qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer + << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested" + : [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS"); + [super setLayer:layer]; +} + - (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy { // We need to set this explicitly since the super implementation -- cgit v1.2.3 From 1b0080a456871a52ac9b11ed8c9685b93bf20723 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 30 Oct 2018 13:07:34 +0100 Subject: Fix no-opengl developer builds Change-Id: I0c8fb7d0aa9a0d95a13447315bd8c1104089fed1 Reviewed-by: Friedemann Kleint Reviewed-by: Andy Nichols Reviewed-by: Laszlo Agocs --- src/plugins/platforms/eglfs/api/qeglfsintegration.cpp | 1 + src/plugins/platforms/eglfs/api/qeglfsscreen.cpp | 10 +++++++++- src/plugins/platforms/minimalegl/qminimaleglintegration.cpp | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp index 43f2e31a49..72420199e3 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp @@ -198,6 +198,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi static_cast(window->handle())->setBackingStore(bs); return bs; #else + Q_UNUSED(window); return nullptr; #endif } diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp index d5c22b3d37..285dbd93d3 100644 --- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp @@ -183,6 +183,8 @@ void QEglFSScreen::handleCursorMove(const QPoint &pos) if (enter && leave) QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos); +#else + Q_UNUSED(pos); #endif } @@ -231,7 +233,13 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c return QPixmap::fromImage(img).copy(rect); } } -#endif // QT_NO_OPENGL +#else // QT_NO_OPENGL + Q_UNUSED(wid); + Q_UNUSED(x); + Q_UNUSED(y); + Q_UNUSED(width); + Q_UNUSED(height); +#endif return QPixmap(); } diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp index 5d31af53d5..da58441d67 100644 --- a/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp +++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.cpp @@ -132,6 +132,7 @@ QPlatformBackingStore *QMinimalEglIntegration::createPlatformBackingStore(QWindo #ifndef QT_NO_OPENGL return new QMinimalEglBackingStore(window); #else + Q_UNUSED(window); return nullptr; #endif } -- cgit v1.2.3 From ee3c66ca917b77f759acea7c6b27d15066f0b814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 12 Nov 2018 15:29:33 +0100 Subject: macOS: Disable threaded GL rendering on SDK 10.14+ AppKit expects rendering to happen on the main thread, or at least any interaction with AppKit UI classes such as NSView. Our OpenGL helpers, such as QOpenGLContext, do not enforce this, and we may end up calling into AppKit UI classes on the render thread, deadlocking the application. Until this can be investigated and new APIs possibly introduced that allow a more fine grained control in our own classes, we disable threaded GL as a capability of the platform, which will inform clients such as QtQuick to use the basic render loop. [ChangeLog][macOS] Threaded OpenGL usage has been disabled when building using Xcode 10/SDK 10.14 and later. Qt Quick defaults to the 'basic' render loop now on macOS. Task-number: QTBUG-71731 Change-Id: I6fc3295e833ecd48ad49382b8275c762fa7978a6 Reviewed-by: Laszlo Agocs Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/cocoa/qcocoaintegration.mm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 936fecf8de..1bd1029863 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -340,12 +340,17 @@ QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen) bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { - case ThreadedPixmaps: #ifndef QT_NO_OPENGL - case OpenGL: case ThreadedOpenGL: + // AppKit expects rendering to happen on the main thread, and we can + // easily end up in situations where rendering on secondary threads + // will result in visual artifacts, bugs, or even deadlocks, when + // building with SDK 10.14 or higher which enbles view layer-backing. + return QMacVersion::buildSDK() < QOperatingSystemVersion(QOperatingSystemVersion::MacOSMojave); + case OpenGL: case BufferQueueingOpenGL: #endif + case ThreadedPixmaps: case WindowMasks: case MultipleWindows: case ForeignWindows: -- cgit v1.2.3 From d9200fcac58a9347decd417c217c18b7e34471ec Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Tue, 13 Nov 2018 20:22:20 +0100 Subject: Windows QPA: Fix broken focus for native child windows This issue was caused by missing logic in the implementation of the pointer message handler, necessary to support "click to focus" for native child windows. Fixes: QTBUG-71352 Change-Id: I2e261caa8dfab096647799ec1e7d781bec40654e Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowspointerhandler.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 4d3e2f71ec..3c7372958f 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -467,6 +467,11 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h keyModifiers, Qt::MouseEventNotSynthesized); return false; // To allow window dragging, etc. } else { + if (eventType == QEvent::MouseButtonPress) { + // Implement "Click to focus" for native child windows (unless it is a native widget window). + if (!window->isTopLevel() && !window->inherits("QWidgetWindow") && QGuiApplication::focusWindow() != window) + window->requestActivate(); + } if (currentWindowUnderPointer != m_windowUnderPointer) { if (m_windowUnderPointer && m_windowUnderPointer == m_currentWindow) { QWindowSystemInterface::handleLeaveEvent(m_windowUnderPointer); -- cgit v1.2.3 From ad2c7f588321f8c671cb9419f90a1e24887ed562 Mon Sep 17 00:00:00 2001 From: Andre de la Rocha Date: Wed, 14 Nov 2018 18:10:25 +0100 Subject: Windows QPA: Fix input context visibility status QWindowsInputContext::isInputPanelVisible() was ignoring the visibility status of the IME, only returning the status of the Win10 virtual keyboard. This issue caused qtwebengine to try to show the IME multiple times, breaking Asian languages input. Task-number: QTBUG-71753 Change-Id: Iaa4cef37b7dc98a9e0a787750a34d2e98a87a777 Reviewed-by: Allan Sandfeld Jensen Reviewed-by: Alexandru Croitor Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowsinputcontext.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 30da0da1de..d1e99c037b 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -242,7 +242,18 @@ QRectF QWindowsInputContext::keyboardRect() const bool QWindowsInputContext::isInputPanelVisible() const { HWND hwnd = getVirtualKeyboardWindowHandle(); - return hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd); + if (hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd)) + return true; + // check if the Input Method Editor is open + if (inputMethodAccepted()) { + if (QWindow *window = QGuiApplication::focusWindow()) { + if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window)) { + if (HIMC himc = ImmGetContext(platformWindow->handle())) + return ImmGetOpenStatus(himc); + } + } + } + return false; } void QWindowsInputContext::showInputPanel() -- cgit v1.2.3