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