diff --git a/input.cpp b/input.cpp index 1cb05b071c..73bb272bde 100644 --- a/input.cpp +++ b/input.cpp @@ -34,6 +34,7 @@ along with this program. If not, see . #endif #if HAVE_WAYLAND #include "abstract_backend.h" +#include "shell_client.h" #include "wayland_server.h" #include "virtual_terminal.h" #include @@ -378,8 +379,13 @@ void InputRedirection::updatePointerWindow() { // TODO: handle pointer grab aka popups Toplevel *t = findToplevel(m_globalPointer.toPoint()); - updatePointerDecoration(t); - if (m_pointerDecoration) { + updatePointerInternalWindow(); + if (!m_pointerInternalWindow) { + updatePointerDecoration(t); + } else { + m_pointerDecoration.clear(); + } + if (m_pointerDecoration || m_pointerInternalWindow) { t = nullptr; } auto oldWindow = m_pointerWindow; @@ -461,6 +467,67 @@ void InputRedirection::updatePointerDecoration(Toplevel *t) } } +void InputRedirection::updatePointerInternalWindow() +{ + const auto oldInternalWindow = m_pointerInternalWindow; +#if HAVE_WAYLAND + if (waylandServer()) { + bool found = false; + const auto &internalClients = waylandServer()->internalClients(); + if (!internalClients.isEmpty()) { + auto it = internalClients.end(); + do { + it--; + if (QWindow *w = (*it)->internalWindow()) { + if (!w->isVisible()) { + continue; + } + if (w->geometry().contains(m_globalPointer.toPoint())) { + m_pointerInternalWindow = QPointer(w); + found = true; + break; + } + } + } while (it != internalClients.begin()); + if (!found) { + m_pointerInternalWindow.clear(); + } + } + } +#endif + if (oldInternalWindow != m_pointerInternalWindow) { + // changed + if (oldInternalWindow) { + disconnect(oldInternalWindow.data(), &QWindow::visibleChanged, this, &InputRedirection::pointerInternalWindowVisibilityChanged); + QEvent event(QEvent::Leave); + QCoreApplication::sendEvent(oldInternalWindow.data(), &event); + } + if (m_pointerInternalWindow) { + connect(oldInternalWindow.data(), &QWindow::visibleChanged, this, &InputRedirection::pointerInternalWindowVisibilityChanged); + QEnterEvent event(m_globalPointer - m_pointerInternalWindow->position(), + m_globalPointer - m_pointerInternalWindow->position(), + m_globalPointer); + QCoreApplication::sendEvent(m_pointerInternalWindow.data(), &event); + return; + } + } + if (m_pointerInternalWindow) { + // send mouse move + QMouseEvent event(QEvent::MouseMove, + m_globalPointer.toPoint() - m_pointerInternalWindow->position(), + m_globalPointer.toPoint(), + Qt::NoButton, qtButtonStates(), keyboardModifiers()); + QCoreApplication::sendEvent(m_pointerInternalWindow.data(), &event); + } +} + +void InputRedirection::pointerInternalWindowVisibilityChanged(bool visible) +{ + if (!visible) { + updatePointerWindow(); + } +} + void InputRedirection::installCursorFromDecoration() { #if HAVE_WAYLAND @@ -506,6 +573,9 @@ void InputRedirection::updateFocusedTouchPosition() void InputRedirection::processPointerMotion(const QPointF &pos, uint32_t time) { + if (!workspace()) { + return; + } // first update to new mouse position // const QPointF oldPos = m_globalPointer; updatePointerPosition(pos); @@ -559,6 +629,15 @@ void InputRedirection::processPointerButton(uint32_t button, InputRedirection::P } } #endif + if (m_pointerInternalWindow) { + // send mouse move + QMouseEvent event(buttonStateToEvent(state), + m_globalPointer.toPoint() - m_pointerInternalWindow->position(), + m_globalPointer.toPoint(), + buttonToQtMouseButton(button), qtButtonStates(), keyboardModifiers()); + event.setAccepted(false); + QCoreApplication::sendEvent(m_pointerInternalWindow.data(), &event); + } if (m_pointerDecoration) { const QPoint localPos = m_globalPointer.toPoint() - m_pointerDecoration->client()->pos(); QMouseEvent event(buttonStateToEvent(state), @@ -617,8 +696,8 @@ void InputRedirection::processPointerAxis(InputRedirection::PointerAxis axis, qr } #endif - if (m_pointerDecoration) { - const QPointF localPos = m_globalPointer - m_pointerDecoration->client()->pos(); + auto sendWheelEvent = [this, delta, axis] (const QPoint targetPos, QObject *target) -> bool { + const QPointF localPos = m_globalPointer - targetPos; // TODO: add modifiers and buttons QWheelEvent event(localPos, m_globalPointer, QPoint(), (axis == PointerAxisHorizontal) ? QPoint(delta, 0) : QPoint(0, delta), @@ -627,14 +706,21 @@ void InputRedirection::processPointerAxis(InputRedirection::PointerAxis axis, qr Qt::NoButton, Qt::NoModifier); event.setAccepted(false); - QCoreApplication::sendEvent(m_pointerDecoration->decoration(), &event); - if (!event.isAccepted() && axis == PointerAxisVertical) { - if (m_pointerDecoration->decoration()->titleBar().contains(localPos.toPoint())) { + QCoreApplication::sendEvent(target, &event); + return event.isAccepted(); + }; + if (m_pointerDecoration) { + if (!sendWheelEvent(m_pointerDecoration->client()->pos(), m_pointerDecoration.data()) + && axis == PointerAxisVertical) { + if (m_pointerDecoration->decoration()->titleBar().contains(m_globalPointer.toPoint() - m_pointerDecoration->client()->pos())) { m_pointerDecoration->client()->performMouseCommand(options->operationTitlebarMouseWheel(delta * -1), m_globalPointer.toPoint()); } } } + if (m_pointerInternalWindow) { + sendWheelEvent(m_pointerInternalWindow->position(), m_pointerInternalWindow.data()); + } // TODO: check which part of KWin would like to intercept the event // TODO: Axis support for effect redirection diff --git a/input.h b/input.h index 01f32f470f..5a58e6e9c6 100644 --- a/input.h +++ b/input.h @@ -193,6 +193,8 @@ private: void updateFocusedTouchPosition(); void updateTouchWindow(const QPointF &pos); void updatePointerDecoration(Toplevel *t); + void updatePointerInternalWindow(); + void pointerInternalWindowVisibilityChanged(bool visible); void installCursorFromDecoration(); bool areButtonsPressed() const; QPointF m_globalPointer; @@ -209,6 +211,7 @@ private: * Decoration belongs to the pointerWindow **/ QPointer m_pointerDecoration; + QPointer m_pointerInternalWindow; /** * @brief The Toplevel which currently receives touch events */ diff --git a/shell_client.h b/shell_client.h index d751f75cb9..49d521434b 100644 --- a/shell_client.h +++ b/shell_client.h @@ -97,6 +97,9 @@ public: return m_windowId; } bool isInternal() const; + QWindow *internalWindow() const { + return m_internalWindow; + } protected: void addDamage(const QRegion &damage) override;