wayland: Interpret input panel's input shape as the window geometry

maliit creates a fullscreen overlay window which doesn't go along well
with out geometry abstractions. For example, raw frame geometry can't be
used to displace normal windows otherwise they will be pushed offscreen.

Some of the maliit quirks are leaked in the InputMethod class. After
extending the lifetime of the InputPanelV1Window, they can cause
problems.

In order to make code in InputMethod more intuitive and encapsulate
maliit quirks, this change makes InputPanelV1Window interpret the
bounding rectangle of the input shape as the window geometry. This
lets us get rid of the hack in inputGeometry() too.

The size checks in Mode::VirtualKeyboard case have been removed because
they should be irrelevant. When reposition() is called, the wl_surface
is mapped, so its size cannot be 0x0.
This commit is contained in:
Vlad Zahorodnii 2023-03-31 17:07:01 +03:00
parent 4e8214e69e
commit 3763e4f84b
3 changed files with 18 additions and 17 deletions

View file

@ -234,7 +234,6 @@ void InputMethod::setPanel(InputPanelV1Window *panel)
}
m_panel = panel;
connect(panel->surface(), &SurfaceInterface::inputChanged, this, &InputMethod::updateInputPanelState);
connect(panel, &Window::closed, this, [this]() {
if (m_trackedWindow) {
m_trackedWindow->setVirtualKeyboardGeometry({});
@ -825,10 +824,10 @@ void InputMethod::updateInputPanelState()
QRectF overlap = QRectF(0, 0, 0, 0);
if (m_trackedWindow) {
const bool bottomKeyboard = m_panel && m_panel->mode() != InputPanelV1Window::Mode::Overlay && m_panel->isShown();
m_trackedWindow->setVirtualKeyboardGeometry(bottomKeyboard ? m_panel->inputGeometry() : QRectF());
m_trackedWindow->setVirtualKeyboardGeometry(bottomKeyboard ? m_panel->frameGeometry() : QRectF());
if (m_panel && m_panel->mode() != InputPanelV1Window::Mode::Overlay) {
overlap = m_trackedWindow->frameGeometry() & m_panel->inputGeometry();
overlap = m_trackedWindow->frameGeometry() & m_panel->frameGeometry();
overlap.moveTo(m_trackedWindow->mapToLocal(overlap.topLeft()));
}
}

View file

@ -34,6 +34,7 @@ InputPanelV1Window::InputPanelV1Window(InputPanelSurfaceV1Interface *panelSurfac
connect(surface(), &SurfaceInterface::aboutToBeDestroyed, this, &InputPanelV1Window::destroyWindow);
connect(surface(), &SurfaceInterface::sizeChanged, this, &InputPanelV1Window::reposition);
connect(surface(), &SurfaceInterface::inputChanged, this, &InputPanelV1Window::reposition);
connect(surface(), &SurfaceInterface::mapped, this, &InputPanelV1Window::handleMapped);
connect(panelSurface, &InputPanelSurfaceV1Interface::topLevel, this, &InputPanelV1Window::showTopLevel);
@ -88,23 +89,21 @@ void KWin::InputPanelV1Window::reposition()
// should never happen
}; break;
case Mode::VirtualKeyboard: {
QSizeF panelSize = surface()->size();
if (!panelSize.isValid() || panelSize.isEmpty()) {
return;
}
// maliit creates a fullscreen overlay so use the input shape as the window geometry.
m_windowGeometry = surface()->input().boundingRect();
const auto activeOutput = workspace()->activeOutput();
const QRectF outputArea = activeOutput->geometry();
QRectF availableArea;
if (waylandServer()->isScreenLocked()) {
availableArea = outputArea;
availableArea = workspace()->clientArea(FullScreenArea, this, activeOutput);
} else {
availableArea = workspace()->clientArea(MaximizeArea, this, activeOutput);
}
panelSize = panelSize.boundedTo(availableArea.size());
QRectF geo(QPointF(availableArea.left(), availableArea.top() + availableArea.height() - panelSize.height()), panelSize);
geo.translate((availableArea.width() - panelSize.width()) / 2, availableArea.height() - outputArea.height());
QRectF geo = m_windowGeometry;
geo.moveLeft(availableArea.left() + (availableArea.width() - geo.width()) / 2);
geo.moveBottom(availableArea.bottom());
moveResize(geo);
} break;
case Mode::Overlay: {
@ -127,8 +126,10 @@ void KWin::InputPanelV1Window::reposition()
cursorRectangle.translate(textWindow->bufferGeometry().topLeft().toPoint());
const QRectF screen = Workspace::self()->clientArea(PlacementArea, this, cursorRectangle.bottomLeft());
m_windowGeometry = QRectF(QPointF(0, 0), surface()->size());
// Reuse the similar logic like xdg popup
QRectF popupRect(popupOffset(cursorRectangle, Qt::BottomEdge | Qt::LeftEdge, Qt::RightEdge | Qt::BottomEdge, surface()->size()), surface()->size());
QRectF popupRect(popupOffset(cursorRectangle, Qt::BottomEdge | Qt::LeftEdge, Qt::RightEdge | Qt::BottomEdge, m_windowGeometry.size()), m_windowGeometry.size());
if (popupRect.left() < screen.left()) {
popupRect.moveLeft(screen.left());
@ -138,7 +139,7 @@ void KWin::InputPanelV1Window::reposition()
}
if (popupRect.top() < screen.top() || popupRect.bottom() > screen.bottom()) {
auto flippedPopupRect =
QRectF(popupOffset(cursorRectangle, Qt::TopEdge | Qt::LeftEdge, Qt::RightEdge | Qt::TopEdge, surface()->size()), surface()->size());
QRectF(popupOffset(cursorRectangle, Qt::TopEdge | Qt::LeftEdge, Qt::RightEdge | Qt::TopEdge, m_windowGeometry.size()), m_windowGeometry.size());
// if it still doesn't fit we should continue with the unflipped version
if (flippedPopupRect.top() >= screen.top() || flippedPopupRect.bottom() <= screen.bottom()) {
@ -170,9 +171,9 @@ NET::WindowType InputPanelV1Window::windowType(bool direct) const
return NET::Utility;
}
QRectF InputPanelV1Window::inputGeometry() const
QRectF InputPanelV1Window::frameRectToBufferRect(const QRectF &rect) const
{
return readyForPainting() ? QRectF(surface()->input().boundingRect()).translated(pos()) : QRectF();
return QRectF(rect.topLeft() - m_windowGeometry.topLeft(), surface()->size());
}
void InputPanelV1Window::moveResizeInternal(const QRectF &rect, MoveResizeMode mode)

View file

@ -71,7 +71,7 @@ public:
return true;
}
NET::WindowType windowType(bool direct = false) const override;
QRectF inputGeometry() const override;
QRectF frameRectToBufferRect(const QRectF &rect) const override;
Mode mode() const
{
@ -91,6 +91,7 @@ private:
void handleMapped();
void maybeShow();
QRectF m_windowGeometry;
Mode m_mode = Mode::None;
bool m_allowed = false;
bool m_virtualKeyboardShouldBeShown = false;