From 844c4511561102ad55e425fff9ef4fea1cba299f Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 9 Feb 2022 14:53:59 +0100 Subject: [PATCH] slidingpopups: Support animating show/hide of input method panel This adds support for animating showing/hiding of the input method panel to the sliding popup effect, if the input panel is of type "Toplevel". This is mainly intended to animate showing the virtual keyboard and has been primarily tested with Maliit. It replaces the client-side animation that Maliit would do, instead doing the animation on the KWin side which provides a significantly smoother experience. --- src/effects.cpp | 23 +++++++++++++++++ src/effects.h | 3 +++ src/effects/slidingpopups/slidingpopups.cpp | 28 +++++++++++++++++++++ src/effects/slidingpopups/slidingpopups.h | 2 ++ src/inputmethod.cpp | 6 +++++ src/inputmethod.h | 2 ++ src/libkwineffects/kwineffects.h | 7 ++++++ 7 files changed, 71 insertions(+) diff --git a/src/effects.cpp b/src/effects.cpp index 79787ae879..b12b214885 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -43,6 +43,9 @@ #include "kwinglutils.h" #include "kwinoffscreenquickview.h" +#include "inputmethod.h" +#include "inputpanelv1client.h" + #include #include #include @@ -266,6 +269,8 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene) slotOutputEnabled(output); } + connect(InputMethod::self(), &InputMethod::panelChanged, this, &EffectsHandlerImpl::inputPanelChanged); + reconfigure(); } @@ -1807,6 +1812,24 @@ qreal EffectsHandlerImpl::renderTargetScale() const return m_scene->renderTargetScale(); } +KWin::EffectWindow *EffectsHandlerImpl::inputPanel() const +{ + auto panel = InputMethod::self()->panel(); + if (panel) { + return panel->effectWindow(); + } + return nullptr; +} + +bool EffectsHandlerImpl::isInputPanelOverlay() const +{ + auto panel = InputMethod::self()->panel(); + if (panel) { + return panel->mode() == InputPanelV1Client::Overlay; + } + return true; +} + //**************************************** // EffectScreenImpl //**************************************** diff --git a/src/effects.h b/src/effects.h index ecb86867d5..3bcac9c761 100644 --- a/src/effects.h +++ b/src/effects.h @@ -277,6 +277,9 @@ public: QRect renderTargetRect() const override; qreal renderTargetScale() const override; + KWin::EffectWindow *inputPanel() const override; + bool isInputPanelOverlay() const override; + public Q_SLOTS: void slotCurrentTabAboutToChange(EffectWindow* from, EffectWindow* to); void slotTabAdded(EffectWindow* from, EffectWindow* to); diff --git a/src/effects/slidingpopups/slidingpopups.cpp b/src/effects/slidingpopups/slidingpopups.cpp index edd63fb160..7fd4ce21ac 100644 --- a/src/effects/slidingpopups/slidingpopups.cpp +++ b/src/effects/slidingpopups/slidingpopups.cpp @@ -67,6 +67,7 @@ SlidingPopupsEffect::SlidingPopupsEffect() this, &SlidingPopupsEffect::stopAnimations); connect(effects, &EffectsHandler::activeFullScreenEffectChanged, this, &SlidingPopupsEffect::stopAnimations); + connect(effects, &EffectsHandler::windowFrameGeometryChanged, this, &SlidingPopupsEffect::slotWindowFrameGeometryChanged); reconfigure(ReconfigureAll); @@ -319,6 +320,13 @@ void SlidingPopupsEffect::slotPropertyNotify(EffectWindow *w, long atom) setupAnimData(w); } +void SlidingPopupsEffect::slotWindowFrameGeometryChanged(EffectWindow *w, const QRect &) +{ + if (w == effects->inputPanel()) { + setupInputPanelSlide(); + } +} + void SlidingPopupsEffect::setupAnimData(EffectWindow *w) { const QRect screenRect = effects->clientArea(FullScreenArea, w->screen(), effects->currentDesktop()); @@ -454,6 +462,26 @@ void SlidingPopupsEffect::setupInternalWindowSlide(EffectWindow *w) setupAnimData(w); } +void SlidingPopupsEffect::setupInputPanelSlide() +{ + auto w = effects->inputPanel(); + + if (!w || effects->isInputPanelOverlay()) { + return; + } + + AnimationData &animData = m_animationsData[w]; + animData.location = Location::Bottom; + animData.offset = 0; + animData.slideLength = 0; + animData.slideInDuration = m_slideInDuration; + animData.slideOutDuration = m_slideOutDuration; + + setupAnimData(w); + + slideIn(w); +} + bool SlidingPopupsEffect::eventFilter(QObject *watched, QEvent *event) { auto internal = qobject_cast(watched); diff --git a/src/effects/slidingpopups/slidingpopups.h b/src/effects/slidingpopups/slidingpopups.h index 12db409157..931e09aac3 100644 --- a/src/effects/slidingpopups/slidingpopups.h +++ b/src/effects/slidingpopups/slidingpopups.h @@ -51,6 +51,7 @@ private Q_SLOTS: void slotWindowDeleted(EffectWindow *w); void slotPropertyNotify(EffectWindow *w, long atom); void slotWaylandSlideOnShowChanged(EffectWindow *w); + void slotWindowFrameGeometryChanged(EffectWindow *w, const QRect &); void slideIn(EffectWindow *w); void slideOut(EffectWindow *w); @@ -60,6 +61,7 @@ private: void setupAnimData(EffectWindow *w); void setupInternalWindowSlide(EffectWindow *w); void setupSlideData(EffectWindow *w); + void setupInputPanelSlide(); static KWaylandServer::SlideManagerInterface *s_slideManager; static QTimer *s_slideManagerRemoveTimer; diff --git a/src/inputmethod.cpp b/src/inputmethod.cpp index 73e226de6b..8ac83f92bc 100644 --- a/src/inputmethod.cpp +++ b/src/inputmethod.cpp @@ -159,6 +159,11 @@ void InputMethod::setActive(bool active) } } +InputPanelV1Client *InputMethod::panel() const +{ + return m_inputClient; +} + void InputMethod::setPanel(InputPanelV1Client *client) { Q_ASSERT(client->isInputMethod()); @@ -182,6 +187,7 @@ void InputMethod::setPanel(InputPanelV1Client *client) connect(m_inputClient, &AbstractClient::windowClosed, this, &InputMethod::visibleChanged); Q_EMIT visibleChanged(); updateInputPanelState(); + Q_EMIT panelChanged(); } void InputMethod::setTrackedClient(AbstractClient* trackedClient) diff --git a/src/inputmethod.h b/src/inputmethod.h index 7b0aa135f6..7bcd299803 100644 --- a/src/inputmethod.h +++ b/src/inputmethod.h @@ -58,6 +58,7 @@ public: bool isVisible() const; bool isAvailable() const; + InputPanelV1Client *panel() const; void setPanel(InputPanelV1Client* client); void setInputMethodCommand(const QString &path); @@ -67,6 +68,7 @@ public: void forwardModifiers(ForwardModifiersForce force); Q_SIGNALS: + void panelChanged(); void activeChanged(bool active); void enabledChanged(bool enabled); void visibleChanged(); diff --git a/src/libkwineffects/kwineffects.h b/src/libkwineffects/kwineffects.h index 446dc29343..23b69d13be 100644 --- a/src/libkwineffects/kwineffects.h +++ b/src/libkwineffects/kwineffects.h @@ -871,6 +871,8 @@ class KWINEFFECTS_EXPORT EffectsHandler : public QObject */ Q_PROPERTY(KWin::SessionState sessionState READ sessionState NOTIFY sessionStateChanged) + Q_PROPERTY(KWin::EffectWindow *inputPanel READ inputPanel NOTIFY inputPanelChanged) + friend class Effect; public: explicit EffectsHandler(CompositingType type); @@ -1453,6 +1455,9 @@ public: */ QRegion mapToRenderTarget(const QRegion ®ion) const; + virtual KWin::EffectWindow *inputPanel() const = 0; + virtual bool isInputPanelOverlay() const = 0; + Q_SIGNALS: /** * This signal is emitted whenever a new @a screen is added to the system. @@ -1906,6 +1911,8 @@ Q_SIGNALS: void startupChanged(const QString &id, const QIcon &icon); void startupRemoved(const QString &id); + void inputPanelChanged(); + protected: QVector< EffectPair > loaded_effects; //QHash< QString, EffectFactory* > effect_factories;