From e71fe9ba79706c913a13414d0eb99271c5f715c2 Mon Sep 17 00:00:00 2001 From: Weng Xuetian Date: Mon, 13 Dec 2021 09:31:08 -0800 Subject: [PATCH] Support text-input-v3 cursor position and position the overlay mode input panel within the screen. --- src/inputpanelv1client.cpp | 40 ++++++++++++++++++++++++---- src/utils.cpp | 52 +++++++++++++++++++++++++++++++++++++ src/utils.h | 2 ++ src/xdgshellclient.cpp | 53 -------------------------------------- 4 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/inputpanelv1client.cpp b/src/inputpanelv1client.cpp index 7883df1fe0..57089dbf7c 100644 --- a/src/inputpanelv1client.cpp +++ b/src/inputpanelv1client.cpp @@ -18,6 +18,7 @@ #include #include #include +#include using namespace KWaylandServer; @@ -90,11 +91,40 @@ void KWin::InputPanelV1Client::reposition() } } break; case Overlay: { - auto textClient = waylandServer()->findClient(waylandServer()->seat()->focusedTextInputSurface()); - auto textInput = waylandServer()->seat()->textInputV2(); - if (textClient && textInput) { - const auto cursorRectangle = textInput->cursorRectangle(); - moveResize({textClient->pos() + textClient->clientPos() + cursorRectangle.bottomLeft(), surface()->size()}); + auto textInputSurface = waylandServer()->seat()->focusedTextInputSurface(); + auto textClient = waylandServer()->findClient(textInputSurface); + QRect cursorRectangle; + auto textInputV2 = waylandServer()->seat()->textInputV2(); + if (textInputV2 && textInputV2->isEnabled() && textInputV2->surface() == textInputSurface) { + cursorRectangle = textInputV2->cursorRectangle(); + } + auto textInputV3 = waylandServer()->seat()->textInputV3(); + if (textInputV3 && textInputV3->isEnabled() && textInputV3->surface() == textInputSurface) { + cursorRectangle = textInputV3->cursorRectangle(); + } + if (textClient) { + cursorRectangle.translate(textClient->pos() + textClient->clientPos()); + const QRect screen = Workspace::self()->clientArea(PlacementArea, cursorRectangle.bottomLeft(), 0); + + // Reuse the similar logic like xdg popup + QRect popupRect(popupOffset(cursorRectangle, Qt::TopEdge | Qt::LeftEdge, Qt::RightEdge | Qt::BottomEdge, surface()->size()), surface()->size()); + + if (popupRect.left() < screen.left()) { + popupRect.moveLeft(screen.left()); + } + if (popupRect.right() > screen.right()) { + popupRect.moveRight(screen.right()); + } + if (popupRect.top() < screen.top() || popupRect.bottom() > screen.bottom()) { + auto flippedPopupRect = + QRect(popupOffset(cursorRectangle, Qt::BottomEdge | Qt::LeftEdge, Qt::RightEdge | Qt::TopEdge, surface()->size()), surface()->size()); + + // if it still doesn't fit we should continue with the unflipped version + if (flippedPopupRect.top() >= screen.top() || flippedPopupRect.bottom() <= screen.bottom()) { + popupRect.moveTop(flippedPopupRect.top()); + } + } + moveResize(popupRect); } } break; } diff --git a/src/utils.cpp b/src/utils.cpp index 859087c00f..9d09532024 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -203,6 +203,58 @@ qreal qPainterEffectiveDevicePixelRatio(const QPainter *painter) return std::max(qreal(1), painter->device()->devicePixelRatioF()); } +QPoint popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize) +{ + QPoint anchorPoint; + switch (anchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { + case Qt::LeftEdge: + anchorPoint.setX(anchorRect.x()); + break; + case Qt::RightEdge: + anchorPoint.setX(anchorRect.x() + anchorRect.width()); + break; + default: + anchorPoint.setX(qRound(anchorRect.x() + anchorRect.width() / 2.0)); + } + switch (anchorEdge & (Qt::TopEdge | Qt::BottomEdge)) { + case Qt::TopEdge: + anchorPoint.setY(anchorRect.y()); + break; + case Qt::BottomEdge: + anchorPoint.setY(anchorRect.y() + anchorRect.height()); + break; + default: + anchorPoint.setY(qRound(anchorRect.y() + anchorRect.height() / 2.0)); + } + + // calculate where the top left point of the popup will end up with the applied gravity + // gravity indicates direction. i.e if gravitating towards the top the popup's bottom edge + // will next to the anchor point + QPoint popupPosAdjust; + switch (gravity & (Qt::LeftEdge | Qt::RightEdge)) { + case Qt::LeftEdge: + popupPosAdjust.setX(-popupSize.width()); + break; + case Qt::RightEdge: + popupPosAdjust.setX(0); + break; + default: + popupPosAdjust.setX(qRound(-popupSize.width() / 2.0)); + } + switch (gravity & (Qt::TopEdge | Qt::BottomEdge)) { + case Qt::TopEdge: + popupPosAdjust.setY(-popupSize.height()); + break; + case Qt::BottomEdge: + popupPosAdjust.setY(0); + break; + default: + popupPosAdjust.setY(qRound(-popupSize.height() / 2.0)); + } + + return anchorPoint + popupPosAdjust; +} + } // namespace #ifndef KCMRULES diff --git a/src/utils.h b/src/utils.h index 76a91ff56b..a2ced91585 100644 --- a/src/utils.h +++ b/src/utils.h @@ -280,6 +280,8 @@ private: int m_capacity = 10; }; +KWIN_EXPORT QPoint popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize); + } // namespace // Must be outside namespace diff --git a/src/xdgshellclient.cpp b/src/xdgshellclient.cpp index fa2b6a0719..d23367c6b8 100644 --- a/src/xdgshellclient.cpp +++ b/src/xdgshellclient.cpp @@ -1865,59 +1865,6 @@ bool XdgPopupClient::hasTransientPlacementHint() const return true; } -static QPoint popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, - const Qt::Edges gravity, const QSize popupSize) -{ - QPoint anchorPoint; - switch (anchorEdge & (Qt::LeftEdge | Qt::RightEdge)) { - case Qt::LeftEdge: - anchorPoint.setX(anchorRect.x()); - break; - case Qt::RightEdge: - anchorPoint.setX(anchorRect.x() + anchorRect.width()); - break; - default: - anchorPoint.setX(qRound(anchorRect.x() + anchorRect.width() / 2.0)); - } - switch (anchorEdge & (Qt::TopEdge | Qt::BottomEdge)) { - case Qt::TopEdge: - anchorPoint.setY(anchorRect.y()); - break; - case Qt::BottomEdge: - anchorPoint.setY(anchorRect.y() + anchorRect.height()); - break; - default: - anchorPoint.setY(qRound(anchorRect.y() + anchorRect.height() / 2.0)); - } - - // calculate where the top left point of the popup will end up with the applied gravity - // gravity indicates direction. i.e if gravitating towards the top the popup's bottom edge - // will next to the anchor point - QPoint popupPosAdjust; - switch (gravity & (Qt::LeftEdge | Qt::RightEdge)) { - case Qt::LeftEdge: - popupPosAdjust.setX(-popupSize.width()); - break; - case Qt::RightEdge: - popupPosAdjust.setX(0); - break; - default: - popupPosAdjust.setX(qRound(-popupSize.width() / 2.0)); - } - switch (gravity & (Qt::TopEdge | Qt::BottomEdge)) { - case Qt::TopEdge: - popupPosAdjust.setY(-popupSize.height()); - break; - case Qt::BottomEdge: - popupPosAdjust.setY(0); - break; - default: - popupPosAdjust.setY(qRound(-popupSize.height() / 2.0)); - } - - return anchorPoint + popupPosAdjust; -} - QRect XdgPopupClient::transientPlacement(const QRect &bounds) const { const XdgPositioner positioner = m_shellSurface->positioner();