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 */