diff options
Diffstat (limited to 'src/plugins/platforms/windows')
23 files changed, 183 insertions, 71 deletions
diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index e37351f9e0..072acdd115 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -93,7 +93,7 @@ }, { "id": 8, - "description": "Standard VGA: Insufficent support for OpenGL, D3D9 and D3D11", + "description": "Standard VGA: Insufficient support for OpenGL, D3D9 and D3D11", "vendor_id": "0x0000", "device_id": ["0x0000"], "os": { diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index e3939ca2d7..4a391eaa55 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -91,9 +91,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) { // Windows with alpha: Use blend function to update. QRect r = QHighDpi::toNativePixels(window->frameGeometry(), window); - QPoint frameOffset(QHighDpi::toNativePixels(QPoint(window->frameMargins().left(), window->frameMargins().top()), - static_cast<const QWindow *>(nullptr))); - QRect dirtyRect = br.translated(offset + frameOffset); + QMargins frameMargins = rw->frameMargins(); + QRect dirtyRect = br.translated(offset + QPoint(frameMargins.left(), frameMargins.top())); SIZE size = {r.width(), r.height()}; POINT ptDst = {r.x(), r.y()}; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index fa757b0edc..3e0059ca90 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -252,14 +252,12 @@ QWindowsContext *QWindowsContext::m_instance = nullptr; \internal */ -typedef QHash<HWND, QWindowsWindow *> HandleBaseWindowHash; - struct QWindowsContextPrivate { QWindowsContextPrivate(); unsigned m_systemInfo = 0; QSet<QString> m_registeredWindowClassNames; - HandleBaseWindowHash m_windows; + QWindowsContext::HandleBaseWindowHash m_windows; HDC m_displayContext = nullptr; int m_defaultDPI = 96; QWindowsKeyMapper m_keyMapper; @@ -513,6 +511,11 @@ QList<int> QWindowsContext::possibleKeys(const QKeyEvent *e) const return d->m_keyMapper.possibleKeys(e); } +QWindowsContext::HandleBaseWindowHash &QWindowsContext::windows() +{ + return d->m_windows; +} + QSharedPointer<QWindowCreationContext> QWindowsContext::setWindowCreationContext(const QSharedPointer<QWindowCreationContext> &ctx) { const QSharedPointer<QWindowCreationContext> old = d->m_creationContext; @@ -818,6 +821,8 @@ static inline bool findPlatformWindowHelper(const POINT &screenPoint, unsigned c if (!(cwexFlags & CWP_SKIPTRANSPARENT) && (GetWindowLongPtr(child, GWL_EXSTYLE) & WS_EX_TRANSPARENT)) { const HWND nonTransparentChild = ChildWindowFromPointEx(*hwnd, point, cwexFlags | CWP_SKIPTRANSPARENT); + if (!nonTransparentChild || nonTransparentChild == *hwnd) + return false; if (QWindowsWindow *nonTransparentWindow = context->findPlatformWindow(nonTransparentChild)) { *result = nonTransparentWindow; *hwnd = nonTransparentChild; @@ -921,7 +926,7 @@ static inline QString errorMessageFromComError(const _com_error &comError) TCHAR *message = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, nullptr, DWORD(comError.Error()), MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), - message, 0, nullptr); + reinterpret_cast<LPWSTR>(&message), 0, nullptr); if (message) { const QString result = QString::fromWCharArray(message).trimmed(); LocalFree(static_cast<HLOCAL>(message)); diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index c89b8b91f4..8eca31e8bc 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -157,6 +157,7 @@ class QWindowsContext { Q_DISABLE_COPY_MOVE(QWindowsContext) public: + using HandleBaseWindowHash = QHash<HWND, QWindowsWindow *>; enum SystemInfoFlags { @@ -236,6 +237,8 @@ public: bool useRTLExtensions() const; QList<int> possibleKeys(const QKeyEvent *e) const; + HandleBaseWindowHash &windows(); + static bool isSessionLocked(); QWindowsMimeConverter &mimeConverter() const; diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 338bb9ff8f..be0f2bad70 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -652,6 +652,11 @@ void QWindowsCursor::clearOverrideCursor() SetCursor(m_overriddenCursor); m_overriddenCursor = m_overrideCursor = nullptr; } + auto &windows = QWindowsContext::instance()->windows(); + for (auto it = windows.cbegin(), end = windows.cend(); it != end; ++it) { + if (it.value()->screen() == m_screen) + it.value()->setFlag(QWindowsWindow::RestoreOverrideCursor); + } } QPoint QWindowsCursor::mousePosition() diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 6fc90035ed..0ebe5bd413 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -148,7 +148,7 @@ void eatMouseMove() Base classes for native dialogs (using the CLSID-based dialog interfaces "IFileDialog", etc. available from Windows - Vista on) that mimick the behaviour of their QDialog + Vista on) that mimic the behavior of their QDialog counterparts as close as possible. Instances of derived classes are controlled by diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index ba049cf359..612e8cd90f 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -420,7 +420,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) } /*! - \brief Give feedback: Change cursor accoding to action. + \brief Give feedback: Change cursor according to action. */ QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 6fa5a8a2b3..1f49f0aefd 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -48,6 +48,7 @@ #include <qpa/qplatformnativeinterface.h> #include <QtPlatformHeaders/qwglnativecontext.h> +#include <private/qsystemlibrary_p.h> #include <algorithm> #include <wingdi.h> @@ -162,19 +163,25 @@ QFunctionPointer QWindowsOpengl32DLL::resolve(const char *name) bool QWindowsOpengl32DLL::init(bool softwareRendering) { - const QByteArray opengl32 = QByteArrayLiteral("opengl32.dll"); - const QByteArray swopengl = QByteArrayLiteral("opengl32sw.dll"); + const QByteArray opengl32 = QByteArrayLiteral("opengl32"); + const QByteArray swopengl = QByteArrayLiteral("opengl32sw"); + bool useSystemLib = false; QByteArray openglDll = qgetenv("QT_OPENGL_DLL"); - if (openglDll.isEmpty()) + if (openglDll.isEmpty()) { openglDll = softwareRendering ? swopengl : opengl32; + useSystemLib = !softwareRendering; + } openglDll = openglDll.toLower(); m_nonOpengl32 = openglDll != opengl32; qCDebug(lcQpaGl) << "Qt: Using WGL and OpenGL from" << openglDll; - m_lib = ::LoadLibraryA(openglDll.constData()); + if (useSystemLib) + m_lib = QSystemLibrary::load((wchar_t*)(QString::fromLatin1(openglDll).utf16())); + else + m_lib = LoadLibraryA(openglDll.constData()); if (!m_lib) { qErrnoWarning(::GetLastError(), "Failed to load %s", openglDll.constData()); return false; @@ -184,7 +191,7 @@ bool QWindowsOpengl32DLL::init(bool softwareRendering) // Load opengl32.dll always. GDI functions like ChoosePixelFormat do // GetModuleHandle for opengl32.dll and behave differently (and call back into // opengl32) when the module is present. This is fine for dummy contexts and windows. - ::LoadLibraryA("opengl32.dll"); + QSystemLibrary::load(L"opengl32"); } wglCreateContext = reinterpret_cast<HGLRC (WINAPI *)(HDC)>(resolve("wglCreateContext")); diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 4f46c05f7a..a7eac35c9d 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -389,7 +389,8 @@ static const uint KeyTbl[] = { // Keyboard mapping table Qt::Key_MediaNext, // 176 0xB0 VK_MEDIA_NEXT_TRACK | Next Track key Qt::Key_MediaPrevious, //177 0xB1 VK_MEDIA_PREV_TRACK | Previous Track key Qt::Key_MediaStop, // 178 0xB2 VK_MEDIA_STOP | Stop Media key - Qt::Key_MediaPlay, // 179 0xB3 VK_MEDIA_PLAY_PAUSE | Play/Pause Media key + Qt::Key_MediaTogglePlayPause, + // 179 0xB3 VK_MEDIA_PLAY_PAUSE | Play/Pause Media key Qt::Key_LaunchMail, // 180 0xB4 VK_LAUNCH_MAIL | Start Mail key Qt::Key_LaunchMedia,// 181 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key Qt::Key_Launch0, // 182 0xB6 VK_LAUNCH_APP1 | Start Application 1 key diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 09a99ffd02..e82b2a5155 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -280,8 +280,13 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, globalPosition = winEventPosition; clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); } else { - clientPosition = winEventPosition; globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition); + auto targetHwnd = hwnd; + if (auto *pw = window->handle()) + targetHwnd = HWND(pw->winId()); + clientPosition = targetHwnd == hwnd + ? winEventPosition + : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPosition); } // Windows sends a mouse move with no buttons pressed to signal "Enter" @@ -494,7 +499,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } if (!discardEvent && mouseEvent.type != QEvent::None) { - QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, + QWindowSystemInterface::handleMouseEvent(window,clientPosition, globalPosition, buttons, mouseEvent.button, mouseEvent.type, keyModifiers, source); } diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index d7d186e804..9eb4011bf2 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -49,6 +49,7 @@ #include <QtCore/qstandardpaths.h> #include <QtCore/qlibraryinfo.h> #include <QtCore/qhash.h> +#include <private/qsystemlibrary_p.h> #ifndef QT_NO_OPENGL #include <private/qopengl_p.h> @@ -396,7 +397,7 @@ bool QWindowsOpenGLTester::testDesktopGL() // Test #1: Load opengl32.dll and try to resolve an OpenGL 2 function. // This will typically fail on systems that do not have a real OpenGL driver. - lib = LoadLibraryA("opengl32.dll"); + lib = QSystemLibrary::load(L"opengl32"); if (lib) { CreateContext = reinterpret_cast<CreateContextType>( reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "wglCreateContext"))); diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 85cf310b62..c1a2c363f2 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -447,6 +447,8 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, { Q_UNUSED(hwnd); + auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo); + if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. @@ -456,10 +458,19 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (msg.message == WM_POINTERCAPTURECHANGED) { QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice, QWindowsKeyMapper::queryKeyboardModifiers()); - m_lastTouchPositions.clear(); + m_lastTouchPoints.clear(); return true; } + if (msg.message == WM_POINTERLEAVE) { + for (quint32 i = 0; i < count; ++i) { + const quint32 pointerId = touchInfo[i].pointerInfo.pointerId; + int id = m_touchInputIDToTouchPointID.value(pointerId, -1); + if (id != -1) + m_lastTouchPoints.remove(id); + } + } + // Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc. if (msg.message > WM_POINTERUP) return false; @@ -470,8 +481,6 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (!screen) return false; - auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo); - const QRect screenGeometry = screen->geometry(); QList<QWindowSystemInterface::TouchPoint> touchPoints; @@ -483,6 +492,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, << " count=" << Qt::dec << count; Qt::TouchPointStates allStates; + QSet<int> inputIds; for (quint32 i = 0; i < count; ++i) { if (QWindowsContext::verbose > 1) @@ -495,14 +505,17 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, const quint32 pointerId = touchInfo[i].pointerInfo.pointerId; int id = m_touchInputIDToTouchPointID.value(pointerId, -1); if (id == -1) { + // Start tracking after fingers touch the screen. Ignore bogus updates after touch is released. + if ((touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) == 0) + continue; 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)) - touchPoint.normalPosition = m_lastTouchPositions.value(touchPoint.id); + if (m_lastTouchPoints.contains(touchPoint.id)) + touchPoint.normalPosition = m_lastTouchPoints.value(touchPoint.id).normalPosition; const QPointF screenPos = QPointF(touchInfo[i].pointerInfo.ptPixelLocation.x, touchInfo[i].pointerInfo.ptPixelLocation.y); @@ -518,22 +531,36 @@ 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); + m_lastTouchPoints.insert(touchPoint.id, touchPoint); } else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) { touchPoint.state = Qt::TouchPointReleased; - m_lastTouchPositions.remove(touchPoint.id); + m_lastTouchPoints.remove(touchPoint.id); } else { touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved; - m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); + m_lastTouchPoints.insert(touchPoint.id, touchPoint); } allStates |= touchPoint.state; touchPoints.append(touchPoint); + inputIds.insert(touchPoint.id); // Avoid getting repeated messages for this frame if there are multiple pointerIds QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } + // Some devices send touches for each finger in a different message/frame, instead of consolidating + // them in the same frame as we were expecting. We account for missing unreleased touches here. + for (auto tp : qAsConst(m_lastTouchPoints)) { + if (!inputIds.contains(tp.id)) { + tp.state = Qt::TouchPointStationary; + allStates |= tp.state; + touchPoints.append(tp); + } + } + + if (touchPoints.count() == 0) + return false; + // all touch points released, forget the ids we've seen. if (allStates == Qt::TouchPointReleased) m_touchInputIDToTouchPointID.clear(); @@ -712,8 +739,13 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, globalPos = eventPos; localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos); } else { - localPos = eventPos; globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos); + auto targetHwnd = hwnd; + if (auto *pw = window->handle()) + targetHwnd = HWND(pw->winId()); + localPos = targetHwnd == hwnd + ? eventPos + : QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos); } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index 8874db27e3..73fd418ca2 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -47,6 +47,7 @@ #include <QtCore/qscopedpointer.h> #include <QtCore/qhash.h> #include <QtGui/qevent.h> +#include <qpa/qwindowsysteminterface.h> QT_BEGIN_NAMESPACE @@ -74,7 +75,7 @@ private: void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos); QTouchDevice *m_touchDevice = nullptr; - QHash<int, QPointF> m_lastTouchPositions; + QHash<int, QWindowSystemInterface::TouchPoint> m_lastTouchPoints; QHash<DWORD, int> m_touchInputIDToTouchPointID; QPointer<QWindow> m_windowUnderPointer; QPointer<QWindow> m_currentWindow; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 287ba931d9..100367e941 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -432,6 +432,11 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L if (m_currentDevice < 0) { m_currentDevice = m_devices.size(); m_devices.push_back(tabletInit(uniqueId, cursorType)); + } else { + // The user can switch pressure sensitivity level in the driver,which + // will make our saved values invalid (this option is provided by Wacom + // drivers for compatibility reasons, and it can be adjusted on the fly) + m_devices[m_currentDevice] = tabletInit(uniqueId, cursorType); } /** @@ -519,7 +524,6 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() return false; const int currentDevice = m_devices.at(m_currentDevice).currentDevice; - const int currentPointer = m_devices.at(m_currentDevice).currentPointerType; const qint64 uniqueId = m_devices.at(m_currentDevice).uniqueId; // The tablet can be used in 2 different modes (reflected in enum Mode), @@ -551,6 +555,27 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() const int z = currentDevice == QTabletEvent::FourDMouse ? int(packet.pkZ) : 0; + const auto currentPointer = m_devices.at(m_currentDevice).currentPointerType; + const auto packetPointerType = pointerType(packet.pkCursor); + + const Qt::MouseButtons buttons = + convertTabletButtons(packet.pkButtons, m_devices.at(m_currentDevice)); + + if (buttons == Qt::NoButton && packetPointerType != currentPointer) { + + QWindowSystemInterface::handleTabletLeaveProximityEvent(packet.pkTime, + int(currentDevice), + int(currentPointer), + uniqueId); + + m_devices[m_currentDevice].currentPointerType = packetPointerType; + + QWindowSystemInterface::handleTabletEnterProximityEvent(packet.pkTime, + int(currentDevice), + int(packetPointerType), + uniqueId); + } + QPointF globalPosF = m_devices.at(m_currentDevice).scaleCoordinates(packet.pkX, packet.pkY, virtualDesktopArea); @@ -617,9 +642,6 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - Qt::MouseButtons buttons = - convertTabletButtons(packet.pkButtons, m_devices.at(m_currentDevice)); - QWindowSystemInterface::handleTabletEvent(target, packet.pkTime, QPointF(localPos), globalPosF, currentDevice, currentPointer, buttons, diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index d2c22f4100..9d9180e4f5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2047,7 +2047,7 @@ HDC QWindowsWindow::getDC() } /*! - Relases the HDC for the window or does nothing in + Releases the HDC for the window or does nothing in case it was obtained from WinAPI BeginPaint within a WM_PAINT event. \sa getDC() @@ -2156,6 +2156,7 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, QWindowsWindowData result = m_data; result.flags = creationData.flags; result.embedded = creationData.embedded; + result.hasFrame = (creationData.style & (WS_DLGFRAME | WS_THICKFRAME)); return result; } @@ -2682,32 +2683,30 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const // This block fixes QTBUG-8361, QTBUG-4362: Frameless/title-less windows shouldn't cover the // taskbar when maximized - if ((testFlag(WithinMaximize) || window()->windowStates().testFlag(Qt::WindowMinimized)) - && (m_data.flags.testFlag(Qt::FramelessWindowHint) - || (m_data.flags.testFlag(Qt::CustomizeWindowHint) && !m_data.flags.testFlag(Qt::WindowTitleHint)))) { - const QScreen *screen = window()->screen(); - - // Documentation of MINMAXINFO states that it will only work for the primary screen - if (screen && screen == QGuiApplication::primaryScreen()) { - const QRect availableGeometry = QHighDpi::toNativePixels(screen->availableGeometry(), screen); + if (m_data.flags.testFlag(Qt::FramelessWindowHint) + || (m_data.flags.testFlag(Qt::CustomizeWindowHint) && !m_data.flags.testFlag(Qt::WindowTitleHint))) { + if (QPlatformScreen *currentScreen = screen()) { + const QRect geometry = currentScreen->geometry(); + const QRect availableGeometry = currentScreen->availableGeometry(); mmi->ptMaxSize.y = availableGeometry.height(); // Width, because you can have the taskbar on the sides too. mmi->ptMaxSize.x = availableGeometry.width(); // If you have the taskbar on top, or on the left you don't want it at (0,0): - mmi->ptMaxPosition.x = availableGeometry.x(); - mmi->ptMaxPosition.y = availableGeometry.y(); + QPoint availablePositionDiff = availableGeometry.topLeft() - geometry.topLeft(); + mmi->ptMaxPosition.x = availablePositionDiff.x(); + mmi->ptMaxPosition.y = availablePositionDiff.y(); if (!m_data.flags.testFlag(Qt::FramelessWindowHint)) { - const int borderWidth = getBorderWidth(screen->handle()); + const int borderWidth = getBorderWidth(currentScreen); mmi->ptMaxSize.x += borderWidth * 2; mmi->ptMaxSize.y += borderWidth * 2; mmi->ptMaxTrackSize = mmi->ptMaxSize; mmi->ptMaxPosition.x -= borderWidth; mmi->ptMaxPosition.y -= borderWidth; } - } else if (!screen){ - qWarning("window()->screen() returned a null screen"); + } else { + qWarning("screen() returned a null screen"); } } @@ -2819,7 +2818,14 @@ void QWindowsWindow::applyCursor() void QWindowsWindow::setCursor(const CursorHandlePtr &c) { #ifndef QT_NO_CURSOR - if (c->handle() != m_cursor->handle()) { + bool changed = c->handle() != m_cursor->handle(); + // QTBUG-98856: Cursors can get out of sync after restoring override + // cursors on native windows. Force an update. + if (testFlag(RestoreOverrideCursor)) { + clearFlag(RestoreOverrideCursor); + changed = true; + } + if (changed) { const bool apply = applyNewCursor(window()); qCDebug(lcQpaWindows) << window() << __FUNCTION__ << c->handle() << " doApply=" << apply; diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 6cd3cd979a..ac207aa48f 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -225,7 +225,8 @@ public: WithinDpiChanged = 0x400000, VulkanSurface = 0x800000, ResizeMoveActive = 0x1000000, - DisableNonClientScaling = 0x2000000 + DisableNonClientScaling = 0x2000000, + RestoreOverrideCursor = 0x4000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp index 93b9622655..50888d4a8e 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE using namespace QWindowsUiAutomation; +bool QWindowsUiaAccessibility::m_accessibleActive = false; QWindowsUiaAccessibility::QWindowsUiaAccessibility() { @@ -72,6 +73,7 @@ bool QWindowsUiaAccessibility::handleWmGetObject(HWND hwnd, WPARAM wParam, LPARA { // Start handling accessibility internally QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true); + m_accessibleActive = true; // Ignoring all requests while starting up / shutting down if (QCoreApplication::startingUp() || QCoreApplication::closingDown()) @@ -131,6 +133,11 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event if (!event) return; + // Ignore events sent before the first UI Automation + // request or while QAccessible is being activated. + if (!m_accessibleActive) + return; + switch (event->type()) { case QAccessible::PopupMenuStart: playSystemSound(QStringLiteral("MenuPopup")); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h index 48b4f9fa6a..ac01a51e76 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h @@ -56,6 +56,8 @@ public: virtual ~QWindowsUiaAccessibility(); static bool handleWmGetObject(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult); void notifyAccessibilityUpdate(QAccessibleEvent *event) override; +private: + static bool m_accessibleActive; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 9808d5481c..a01104a8e3 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -74,10 +74,13 @@ QT_BEGIN_NAMESPACE using namespace QWindowsUiAutomation; +QMutex QWindowsUiaMainProvider::m_mutex; // Returns a cached instance of the provider for a specific acessible interface. QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessibleInterface *accessible) { + QMutexLocker locker(&m_mutex); + if (!accessible) return nullptr; @@ -107,9 +110,12 @@ QWindowsUiaMainProvider::~QWindowsUiaMainProvider() void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event) { if (QAccessibleInterface *accessible = event->accessibleInterface()) { - if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + // If this is a table/tree/list, raise event for the focused cell/item instead. + if (accessible->tableInterface()) + if (QAccessibleInterface *child = accessible->focusChild()) + accessible = child; + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId); - } } } @@ -203,12 +209,16 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve void QWindowsUiaMainProvider::notifyNameChange(QAccessibleEvent *event) { if (QAccessibleInterface *accessible = event->accessibleInterface()) { - if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { - VARIANT oldVal, newVal; - clearVariant(&oldVal); - setVariantString(accessible->text(QAccessible::Name), &newVal); - QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal); - ::SysFreeString(newVal.bstrVal); + // Restrict notification to combo boxes, which need it for accessibility, + // in order to avoid slowdowns with unnecessary notifications. + if (accessible->role() == QAccessible::ComboBox) { + if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) { + VARIANT oldVal, newVal; + clearVariant(&oldVal); + setVariantString(accessible->text(QAccessible::Name), &newVal); + QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal); + ::SysFreeString(newVal.bstrVal); + } } } } @@ -264,6 +274,8 @@ ULONG QWindowsUiaMainProvider::AddRef() ULONG STDMETHODCALLTYPE QWindowsUiaMainProvider::Release() { + QMutexLocker locker(&m_mutex); + if (!--m_ref) { delete this; return 0; @@ -513,7 +525,7 @@ QString QWindowsUiaMainProvider::automationIdForAccessible(const QAccessibleInte while (obj) { QString name = obj->objectName(); if (name.isEmpty()) - return QString(); + return result; if (!result.isEmpty()) result.prepend(u'.'); result.prepend(name); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h index f7320388f7..8aadabd227 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h @@ -47,6 +47,7 @@ #include <QtCore/qpointer.h> #include <QtCore/qsharedpointer.h> +#include <QtCore/qmutex.h> #include <QtCore/qt_windows.h> #include <QtGui/qaccessible.h> @@ -98,6 +99,7 @@ public: private: QString automationIdForAccessible(const QAccessibleInterface *accessible); ULONG m_ref; + static QMutex m_mutex; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp index c55e827a46..0483cf4263 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaprovidercache.cpp @@ -75,7 +75,7 @@ void QWindowsUiaProviderCache::insert(QAccessible::Id id, QWindowsUiaBaseProvide m_providerTable[id] = provider; m_inverseTable[provider] = id; // Connects the destroyed signal to our slot, to remove deleted objects from the cache. - QObject::connect(provider, &QObject::destroyed, this, &QWindowsUiaProviderCache::objectDestroyed); + QObject::connect(provider, &QObject::destroyed, this, &QWindowsUiaProviderCache::objectDestroyed, Qt::DirectConnection); } } diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp index d8b8f7281d..3465c55bc4 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp @@ -143,7 +143,9 @@ HRESULT QWindowsUiaTextRangeProvider::ExpandToEnclosingUnit(TextUnit unit) m_endOffset = m_startOffset + 1; } else { QString text = textInterface->text(0, len); - for (int t = m_startOffset; t >= 0; --t) { + const int start = m_startOffset >= 0 && m_startOffset < len + ? m_startOffset : len - 1; + for (int t = start; t >= 0; --t) { if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) { m_startOffset = t; break; @@ -443,7 +445,9 @@ HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoin } m_endOffset = qBound(m_startOffset, m_endOffset, len); } else { - for (int t = m_startOffset - 1; (t >= 0) && (moved > count); --t) { + const int start = m_startOffset >= 0 && m_startOffset <= len + ? m_startOffset : len; + for (int t = start - 1; (t >= 0) && (moved > count); --t) { if (!isTextUnitSeparator(unit, text[t]) && ((t == 0) || isTextUnitSeparator(unit, text[t - 1]))) { m_startOffset = t; --moved; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index 682b8c19c0..12bdc9e6b7 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -132,22 +132,19 @@ void setVariantString(const QString &value, VARIANT *variant) void rectToNativeUiaRect(const QRect &rect, const QWindow *w, UiaRect *uiaRect) { if (w && uiaRect) { - const qreal factor = QHighDpiScaling::factor(w); - uiaRect->left = qreal(rect.x()) * factor; - uiaRect->top = qreal(rect.y()) * factor; - uiaRect->width = qreal(rect.width()) * factor; - uiaRect->height = qreal(rect.height()) * factor; + QRectF r = QHighDpi::toNativePixels(QRectF(rect), w); + uiaRect->left =r.x(); + uiaRect->top = r.y(); + uiaRect->width = r.width(); + uiaRect->height = r.height(); } } // Scales a point from native coordinates, according to high dpi settings. void nativeUiaPointToPoint(const UiaPoint &uiaPoint, const QWindow *w, QPoint *point) { - if (w && point) { - const qreal factor = QHighDpiScaling::factor(w); - point->setX(int(std::lround(uiaPoint.x / factor))); - point->setY(int(std::lround(uiaPoint.y / factor))); - } + if (w && point) + *point = QHighDpi::fromNativePixels(QPoint(uiaPoint.x, uiaPoint.y), w); } // Maps an accessibility role ID to an UI Automation control type ID. |