diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -320,11 +320,13 @@ set( testOnScreenNotification_SRCS onscreennotificationtest.cpp ../onscreennotification.cpp + ../input_event_spy.cpp ) add_executable( testOnScreenNotification ${testOnScreenNotification_SRCS}) target_link_libraries(testOnScreenNotification Qt5::Test + Qt5::Widgets # QAction include Qt5::Quick KF5::ConfigCore ) diff --git a/autotests/onscreennotificationtest.cpp b/autotests/onscreennotificationtest.cpp --- a/autotests/onscreennotificationtest.cpp +++ b/autotests/onscreennotificationtest.cpp @@ -21,6 +21,7 @@ #include "onscreennotificationtest.h" #include "../onscreennotification.h" +#include "../input.h" #include #include @@ -31,6 +32,23 @@ QTEST_MAIN(OnScreenNotificationTest); +namespace KWin +{ + +void InputRedirection::installInputEventSpy(InputEventSpy *spy) +{ + Q_UNUSED(spy); +} + +void InputRedirection::uninstallInputEventSpy(InputEventSpy *spy) +{ + Q_UNUSED(spy); +} + +InputRedirection *InputRedirection::s_self = nullptr; + +} + using KWin::OnScreenNotification; void OnScreenNotificationTest::show() diff --git a/onscreennotification.h b/onscreennotification.h --- a/onscreennotification.h +++ b/onscreennotification.h @@ -26,13 +26,16 @@ #include +class QPropertyAnimation; class QTimer; class QQmlContext; class QQmlComponent; class QQmlEngine; namespace KWin { +class OnScreenNotificationInputEventSpy; + class OnScreenNotification : public QObject { Q_OBJECT @@ -49,14 +52,18 @@ QString iconName() const; int timeout() const; + QRect geometry() const; + void setVisible(bool m_visible); void setMessage(const QString &message); void setIconName(const QString &iconName); void setTimeout(int timeout); void setConfig(KSharedConfigPtr config); void setEngine(QQmlEngine *engine); + void setContainsPointer(bool contains); + Q_SIGNALS: void visibleChanged(); void messageChanged(); @@ -67,6 +74,7 @@ void show(); void ensureQmlContext(); void ensureQmlComponent(); + void createInputSpy(); bool m_visible = false; QString m_message; QString m_iconName; @@ -76,6 +84,9 @@ QScopedPointer m_qmlComponent; QQmlEngine *m_qmlEngine = nullptr; QScopedPointer m_mainItem; + QScopedPointer m_spy; + QPropertyAnimation *m_animation = nullptr; + bool m_containsPointer = false; }; } diff --git a/onscreennotification.cpp b/onscreennotification.cpp --- a/onscreennotification.cpp +++ b/onscreennotification.cpp @@ -20,8 +20,12 @@ */ #include "onscreennotification.h" +#include "input.h" +#include "input_event.h" +#include "input_event_spy.h" #include +#include #include #include #include @@ -35,6 +39,31 @@ using namespace KWin; +class KWin::OnScreenNotificationInputEventSpy : public InputEventSpy +{ +public: + explicit OnScreenNotificationInputEventSpy(OnScreenNotification *parent); + + void pointerEvent(MouseEvent *event) override; +private: + OnScreenNotification *m_parent; +}; + +OnScreenNotificationInputEventSpy::OnScreenNotificationInputEventSpy(OnScreenNotification *parent) + : m_parent(parent) +{ +} + +void OnScreenNotificationInputEventSpy::pointerEvent(MouseEvent *event) +{ + if (event->type() != QEvent::MouseMove) { + return; + } + + m_parent->setContainsPointer(m_parent->geometry().contains(event->globalPos())); +} + + OnScreenNotification::OnScreenNotification(QObject *parent) : QObject(parent) , m_timer(new QTimer(this)) @@ -47,6 +76,8 @@ show(); } else { m_timer->stop(); + m_spy.reset(); + m_containsPointer = false; } } ); @@ -131,6 +162,7 @@ Q_ASSERT(m_visible); ensureQmlContext(); ensureQmlComponent(); + createInputSpy(); if (m_timer->interval() != 0) { m_timer->start(); } @@ -167,4 +199,41 @@ } } +void OnScreenNotification::createInputSpy() +{ + Q_ASSERT(m_spy.isNull()); + if (auto w = qobject_cast(m_mainItem.data())) { + m_spy.reset(new OnScreenNotificationInputEventSpy(this)); + input()->installInputEventSpy(m_spy.data()); + if (!m_animation) { + m_animation = new QPropertyAnimation(w, "opacity", this); + m_animation->setStartValue(1.0); + m_animation->setEndValue(0.0); + m_animation->setDuration(250); + m_animation->setEasingCurve(QEasingCurve::InOutQuad); + } + } +} + +QRect OnScreenNotification::geometry() const +{ + if (QQuickWindow *w = qobject_cast(m_mainItem.data())) { + return w->geometry(); + } + return QRect(); +} + +void OnScreenNotification::setContainsPointer(bool contains) +{ + if (m_containsPointer == contains) { + return; + } + m_containsPointer = contains; + if (!m_animation) { + return; + } + m_animation->setDirection(m_containsPointer ? QAbstractAnimation::Forward : QAbstractAnimation::Backward); + m_animation->start(); +} + #include "onscreennotification.moc"