From 1edd6892931745f15e5c8531f2dae8b13e3131d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 3 Jun 2015 18:09:54 +0200 Subject: [PATCH] Handle interaction with window decoration directly in InputRedirection So far input events were sent through Xwayland which is not needed as we have all information available. Even more it had the pointer surface on the wrong window when interacting with decorations as it was on the window and not on the decoration. --- client.cpp | 40 +++++++++++++++++++++++++++++ client.h | 3 +++ input.cpp | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ input.h | 12 +++++++++ 4 files changed, 129 insertions(+) diff --git a/client.cpp b/client.cpp index 038bafd979..ea2f560eaa 100644 --- a/client.cpp +++ b/client.cpp @@ -45,6 +45,7 @@ along with this program. If not, see . #include #include #include +#include #include #include #include @@ -2257,6 +2258,45 @@ bool Client::belongsToSameApplication(const AbstractClient *other, bool active_h return Client::belongToSameApplication(this, c2, active_hack); } +bool Client::processDecorationButtonPress(QMouseEvent *event) +{ + return processDecorationButtonPress(qtToX11Button(event->button()), 0, + event->x(), event->y(), + event->globalX(), event->globalY()); +} + +void Client::processDecorationButtonRelease(QMouseEvent *event) +{ + if (m_decoration) { + if (!event->isAccepted() && m_decoration->titleBar().contains(event->pos()) && event->button() == Qt::LeftButton) { + m_decorationDoubleClickTimer.start(); + } + } + + if (event->buttons() == Qt::NoButton) { + buttonDown = false; + stopDelayedMoveResize(); + if (moveResizeMode) { + finishMoveResize(false); + mode = mousePosition(); + } + updateCursor(); + } +} + +void Client::processDecorationMove() +{ + if (buttonDown) { + return; + } + // TODO: handle modifiers + Position newmode = mousePosition(); + if (newmode != mode) { + mode = newmode; + updateCursor(); + } +} + } // namespace #include "client.moc" diff --git a/client.h b/client.h index ec40e052aa..6003ea926f 100644 --- a/client.h +++ b/client.h @@ -231,6 +231,9 @@ public: bool windowEvent(xcb_generic_event_t *e); void syncEvent(xcb_sync_alarm_notify_event_t* e); NET::WindowType windowType(bool direct = false, int supported_types = 0) const; + bool processDecorationButtonPress(QMouseEvent *event); + void processDecorationButtonRelease(QMouseEvent *event); + void processDecorationMove(); bool manage(xcb_window_t w, bool isMapped); void releaseWindow(bool on_shutdown = false); diff --git a/input.cpp b/input.cpp index ab627cd008..e4f7abcf81 100644 --- a/input.cpp +++ b/input.cpp @@ -38,6 +38,8 @@ along with this program. If not, see . #include "virtual_terminal.h" #include #endif +#include +#include // Qt #include #include @@ -375,6 +377,10 @@ void InputRedirection::updatePointerWindow() { // TODO: handle pointer grab aka popups Toplevel *t = findToplevel(m_globalPointer.toPoint()); + updatePointerDecoration(t); + if (m_pointerDecoration) { + t = nullptr; + } auto oldWindow = m_pointerWindow; if (!oldWindow.isNull() && t == m_pointerWindow.data()) { return; @@ -416,6 +422,38 @@ void InputRedirection::updatePointerWindow() m_pointerWindow = QWeakPointer(t); } +void InputRedirection::updatePointerDecoration(Toplevel *t) +{ + const auto oldDeco = m_pointerDecoration; + if (Client *c = dynamic_cast(t)) { + // check whether it's on a Decoration + if (c->decoratedClient()) { + const QRect clientRect = QRect(c->clientPos(), c->clientSize()).translated(c->pos()); + if (!clientRect.contains(m_globalPointer.toPoint())) { + m_pointerDecoration = c->decoratedClient(); + } else { + m_pointerDecoration.clear(); + } + } else { + m_pointerDecoration.clear(); + } + } else { + m_pointerDecoration.clear(); + } + + if (oldDeco && oldDeco != m_pointerDecoration) { + // send leave + QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF()); + QCoreApplication::instance()->sendEvent(oldDeco->decoration(), &event); + } + if (m_pointerDecoration) { + const QPointF p = m_globalPointer - t->pos(); + QHoverEvent event(QEvent::HoverMove, p, p); + QCoreApplication::instance()->sendEvent(m_pointerDecoration->decoration(), &event); + m_pointerDecoration->client()->processDecorationMove(); + } +} + void InputRedirection::updateFocusedPointerPosition() { #if HAVE_WAYLAND @@ -496,6 +534,23 @@ void InputRedirection::processPointerButton(uint32_t button, InputRedirection::P } } #endif + if (m_pointerDecoration) { + const QPoint localPos = m_globalPointer.toPoint() - m_pointerDecoration->client()->pos(); + QMouseEvent event(buttonStateToEvent(state), + localPos, + m_globalPointer.toPoint(), + buttonToQtMouseButton(button), qtButtonStates(), keyboardModifiers()); + event.setAccepted(false); + QCoreApplication::sendEvent(m_pointerDecoration->decoration(), &event); + if (!event.isAccepted()) { + if (state == PointerButtonPressed) { + m_pointerDecoration->client()->processDecorationButtonPress(&event); + } + } + if (state == PointerButtonReleased) { + m_pointerDecoration->client()->processDecorationButtonRelease(&event); + } + } // TODO: check which part of KWin would like to intercept the event #if HAVE_WAYLAND if (auto seat = findSeat()) { @@ -536,6 +591,25 @@ void InputRedirection::processPointerAxis(InputRedirection::PointerAxis axis, qr } #endif + if (m_pointerDecoration) { + const QPointF localPos = m_globalPointer - m_pointerDecoration->client()->pos(); + // TODO: add modifiers and buttons + QWheelEvent event(localPos, m_globalPointer, QPoint(), + (axis == PointerAxisHorizontal) ? QPoint(delta, 0) : QPoint(0, delta), + delta, + (axis == PointerAxisHorizontal) ? Qt::Horizontal : Qt::Vertical, + 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())) { + m_pointerDecoration->client()->performMouseCommand(options->operationTitlebarMouseWheel(delta * -1), + m_globalPointer.toPoint()); + } + } + } + // TODO: check which part of KWin would like to intercept the event // TODO: Axis support for effect redirection #if HAVE_WAYLAND diff --git a/input.h b/input.h index 2a33e10945..ab10e8b697 100644 --- a/input.h +++ b/input.h @@ -24,6 +24,7 @@ along with this program. If not, see . #include #include #include +#include #include #include #include @@ -42,6 +43,11 @@ class GlobalShortcutsManager; class Toplevel; class Xkb; +namespace Decoration +{ +class DecoratedClientImpl; +} + namespace LibInput { class Connection; @@ -183,6 +189,7 @@ private: void updateFocusedPointerPosition(); void updateFocusedTouchPosition(); void updateTouchWindow(const QPointF &pos); + void updatePointerDecoration(Toplevel *t); bool areButtonsPressed() const; QPointF m_globalPointer; QHash m_pointerButtons; @@ -193,6 +200,11 @@ private: * @brief The Toplevel which currently receives pointer events */ QWeakPointer m_pointerWindow; + /** + * @brief The Decoration which currently receives pointer events. + * Decoration belongs to the pointerWindow + **/ + QPointer m_pointerDecoration; /** * @brief The Toplevel which currently receives touch events */