diff options
Diffstat (limited to 'src/plugins/platforms/winrt/qwinrtscreen.cpp')
-rw-r--r-- | src/plugins/platforms/winrt/qwinrtscreen.cpp | 136 |
1 files changed, 124 insertions, 12 deletions
diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index e39a87148a..bd2bbcb81c 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -46,9 +46,11 @@ #include "qwinrtdrag.h" #endif #include "qwinrtwindow.h" +#include "qwinrtcanvas.h" #include <private/qeventdispatcher_winrt_p.h> #include <private/qhighdpiscaling_p.h> +#include <QtCore/qdebug.h> #include <QtCore/QLoggingCategory> #include <QtGui/QSurfaceFormat> #include <QtGui/QGuiApplication> @@ -99,6 +101,31 @@ typedef ITypedEventHandler<ApplicationView*, IInspectable*> VisibleBoundsChanged QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") + +#if !defined(QT_NO_DEBUG_STREAM) +QDebug operator<<(QDebug dbg, QWinRTScreen::MousePositionTransition transition) +{ + QDebugStateSaver saver(dbg); + dbg.nospace() << "QWinRTScreen::MousePositionTransition::"; + switch (transition) { + case QWinRTScreen::MousePositionTransition::MovedOut: + dbg << "MovedOut"; + break; + case QWinRTScreen::MousePositionTransition::MovedIn: + dbg << "MovedIn"; + break; + case QWinRTScreen::MousePositionTransition::StayedOut: + dbg << "StayedOut"; + break; + case QWinRTScreen::MousePositionTransition::StayedIn: + dbg << "StayedIn"; + break; + } + return dbg; +} +#endif + struct KeyInfo { KeyInfo() { @@ -463,7 +490,7 @@ public: QTouchDevice *touchDevice; ComPtr<ICoreWindow> coreWindow; ComPtr<ICorePointerRedirector> redirect; - ComPtr<Xaml::IDependencyObject> canvas; + ComPtr<QWinRTCanvas> canvas; ComPtr<IApplicationView> view; ComPtr<IDisplayInformation> displayInformation; @@ -490,6 +517,7 @@ public: QAtomicPointer<QWinRTWindow> keyboardGrabWindow; QWindow *currentPressWindow = nullptr; QWindow *currentTargetWindow = nullptr; + bool firstMouseMove = true; }; // To be called from the XAML thread @@ -553,27 +581,25 @@ QWinRTScreen::QWinRTScreen() hr = applicationViewStatics->GetForCurrentView(&d->view); RETURN_VOID_IF_FAILED("Could not access currentView"); - // Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added - ComPtr<Xaml::Controls::ICanvas> canvas; - hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas); - Q_ASSERT_SUCCEEDED(hr); + d->canvas = Make<QWinRTCanvas>([this]() { return topWindow(); }); + ComPtr<Xaml::IFrameworkElement> frameworkElement; - hr = canvas.As(&frameworkElement); + hr = d->canvas.As(&frameworkElement); Q_ASSERT_SUCCEEDED(hr); hr = frameworkElement->put_Width(d->logicalRect.width()); Q_ASSERT_SUCCEEDED(hr); hr = frameworkElement->put_Height(d->logicalRect.height()); Q_ASSERT_SUCCEEDED(hr); + ComPtr<Xaml::IUIElement> uiElement; - hr = canvas.As(&uiElement); + hr = d->canvas.As(&uiElement); Q_ASSERT_SUCCEEDED(hr); + #if QT_CONFIG(draganddrop) QWinRTDrag::instance()->setUiElement(uiElement); #endif hr = window->put_Content(uiElement.Get()); Q_ASSERT_SUCCEEDED(hr); - hr = canvas.As(&d->canvas); - Q_ASSERT_SUCCEEDED(hr); d->cursor.reset(new QWinRTCursor); @@ -723,7 +749,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const Xaml::IDependencyObject *QWinRTScreen::canvas() const { Q_D(const QWinRTScreen); - return d->canvas.Get(); + Xaml::IDependencyObject *depCanvas; + if (SUCCEEDED(d->canvas.CopyTo(&depCanvas))) + return depCanvas; + return nullptr; } void QWinRTScreen::initialize() @@ -848,6 +877,7 @@ void QWinRTScreen::addWindow(QWindow *window) } handleExpose(); + d->firstMouseMove = true; QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); #if QT_CONFIG(draganddrop) @@ -860,6 +890,8 @@ void QWinRTScreen::removeWindow(QWindow *window) Q_D(QWinRTScreen); qCDebug(lcQpaWindows) << __FUNCTION__ << window; + handleExpose(); + const bool wasTopWindow = window == topWindow(); if (!d->visibleWindows.removeAll(window)) return; @@ -867,7 +899,6 @@ void QWinRTScreen::removeWindow(QWindow *window) const Qt::WindowType type = window->type(); if (wasTopWindow && type != Qt::Popup && type != Qt::ToolTip && type != Qt::Tool) QWindowSystemInterface::handleWindowActivated(nullptr, Qt::OtherFocusReason); - handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); #if QT_CONFIG(draganddrop) if (wasTopWindow) @@ -1075,6 +1106,7 @@ HRESULT QWinRTScreen::onCharacterReceived(ICoreWindow *, ICharacterReceivedEvent HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); + qCDebug(lcQpaEvents) << __FUNCTION__; ComPtr<IPointerPoint> pointerPoint; if (SUCCEEDED(args->get_CurrentPoint(&pointerPoint))) { @@ -1087,7 +1119,9 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) if (d->mouseGrabWindow) d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow << pos; QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos); + d->firstMouseMove = false; } return S_OK; } @@ -1095,7 +1129,7 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); - + qCDebug(lcQpaEvents) << __FUNCTION__; ComPtr<IPointerPoint> pointerPoint; if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; @@ -1109,6 +1143,7 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) if (d->mouseGrabWindow) d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow; QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow); d->currentTargetWindow = nullptr; return S_OK; @@ -1120,6 +1155,7 @@ ComPtr<IPointerPoint> qt_winrt_lastPointerPoint; HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); + qCDebug(lcQpaEvents) << __FUNCTION__; ComPtr<IPointerPoint> pointerPoint; if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; @@ -1175,6 +1211,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) boolean isHorizontal; properties->get_IsHorizontalMouseWheel(&isHorizontal); QPoint angleDelta(isHorizontal ? delta : 0, isHorizontal ? 0 : delta); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleWheelEvent" << d->currentTargetWindow + << localPos << pos << angleDelta << mods; QWindowSystemInterface::handleWheelEvent(d->currentTargetWindow, localPos, pos, QPoint(), angleDelta, mods); break; } @@ -1213,6 +1251,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) const QPointF globalPosDelta = pos - posPoint; const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta; + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow + << localPressPos << pos << buttons << mods; QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, buttons, mods); d->currentPressWindow = nullptr; } @@ -1224,6 +1264,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) d->currentPressWindow = nullptr; } + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow + << localPos << pos << buttons << mods; QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, buttons, mods); break; @@ -1280,6 +1322,8 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) it.value().normalPosition = QPointF(point.X/d->logicalRect.width(), point.Y/d->logicalRect.height()); it.value().pressure = pressure; + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTouchEvent" << d->currentTargetWindow + << d->touchDevice << d->touchPoints.values() << mods; QWindowSystemInterface::handleTouchEvent(d->currentTargetWindow, d->touchDevice, d->touchPoints.values(), mods); if (wasPressEvent) it.value().state = Qt::TouchPointStationary; @@ -1301,6 +1345,9 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) float rotation; properties->get_Twist(&rotation); + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleTabletEvent" << d->currentTargetWindow + << isPressed << pos << pointerType << pressure << xTilt << yTilt + << rotation << id << mods; QWindowSystemInterface::handleTabletEvent(d->currentTargetWindow, isPressed, pos, pos, 0, pointerType, pressure, xTilt, yTilt, 0, rotation, 0, id, mods); @@ -1312,6 +1359,70 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) return S_OK; } +void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransition transition) +{ + Q_D(QWinRTScreen); + qCDebug(lcQpaEvents) << __FUNCTION__ << point << transition; + if (transition == MousePositionTransition::StayedOut) + return; + qt_winrt_lastPointerPoint = nullptr; + const QPointF pos(point.x() * d->scaleFactor, point.y() * d->scaleFactor); + QPointF localPos = pos; + + const QPoint posPoint = pos.toPoint(); + QWindow *windowUnderPointer = windowAt(QHighDpiScaling::mapPositionFromNative(posPoint, this)); + d->currentTargetWindow = windowUnderPointer; + + if (d->mouseGrabWindow) + d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + + if (d->currentTargetWindow) { + const QPointF globalPosDelta = pos - posPoint; + localPos = d->currentTargetWindow->mapFromGlobal(posPoint) + globalPosDelta; + } + + // In case of a mouse grab we have to store the target of a press event + // to be able to send one additional release event to this target when the mouse + // button is released. This is a similar approach to AutoMouseCapture in the + // windows qpa backend. Otherwise the release might not be propagated and the original + // press event receiver considers a button to still be pressed, as in Qt Quick Controls 1 + // menus. + if (d->currentPressWindow && d->mouseGrabWindow) { + const QPointF globalPosDelta = pos - posPoint; + const QPointF localPressPos = d->currentPressWindow->mapFromGlobal(posPoint) + globalPosDelta; + + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentPressWindow + << localPressPos << pos << Qt::NoButton << Qt::NoModifier; + QWindowSystemInterface::handleMouseEvent(d->currentPressWindow, localPressPos, pos, + Qt::NoButton, Qt::NoModifier); + d->currentPressWindow = nullptr; + } + // If the mouse button is released outside of a window, targetWindow is 0, but the event + // has to be delivered to the window, that initially received the mouse press. Do not reset + // d->currentTargetWindow though, as it is used (and reset) in onPointerExited. + if (d->currentPressWindow && !d->currentTargetWindow) { + d->currentTargetWindow = d->currentPressWindow; + d->currentPressWindow = nullptr; + } + + if (transition == MousePositionTransition::MovedOut) { + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow; + QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow); + return; + } + + if (transition == MousePositionTransition::MovedIn || d->firstMouseMove) { + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow + << localPos << pos; + QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, localPos, pos); + d->firstMouseMove = false; + } + qCDebug(lcQpaEvents) << __FUNCTION__ << "handleMouseEvent" << d->currentTargetWindow + << localPos << pos << Qt::NoButton << Qt::NoModifier; + QWindowSystemInterface::handleMouseEvent(d->currentTargetWindow, localPos, pos, Qt::NoButton, + Qt::NoModifier); +} + HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args) { Q_D(QWinRTScreen); @@ -1413,6 +1524,7 @@ HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEvent { // When dragging ends with a non-mouse input device then onRedirectRelease is invoked. // QTBUG-58781 + qCDebug(lcQpaEvents) << __FUNCTION__; return onPointerUpdated(nullptr, args); } |