From 0c6fdeef2db47f900c453cde673f97c60871f00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= Date: Fri, 15 Sep 2017 18:35:40 +0200 Subject: [PATCH] Split out the X11 mouse event filtering for EffectsHandlerImpl Summary: This change introduces a dedicated X11EventFilter for the mouse interception on X11. The filter gets created together with the start of mouse interception and destroyed again when the mouse interception ends. Thus we don't need to check for each event like it was the case so far. Unfortunately the existing methods cannot be removed (yet) as they are still used by TabBox. Needs investigation whether this is actually needed. Test Plan: Xephyr+kwin_x11+Present Windows Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D7842 --- CMakeLists.txt | 1 + effects.cpp | 3 ++ effects.h | 2 + effects_mouse_interception_x11_filter.cpp | 65 +++++++++++++++++++++++ effects_mouse_interception_x11_filter.h | 43 +++++++++++++++ events.cpp | 19 ------- 6 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 effects_mouse_interception_x11_filter.cpp create mode 100644 effects_mouse_interception_x11_filter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ba2ccd53..e03d5738ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -456,6 +456,7 @@ set(kwin_KDEINIT_SRCS egl_context_attribute_builder.cpp was_user_interaction_x11_filter.cpp moving_client_x11_filter.cpp + effects_mouse_interception_x11_filter.cpp ) if(KWIN_BUILD_TABBOX) diff --git a/effects.cpp b/effects.cpp index ed4adc1461..d5d06e2059 100644 --- a/effects.cpp +++ b/effects.cpp @@ -22,6 +22,7 @@ along with this program. If not, see . #include "effects.h" #include "effectsadaptor.h" +#include "effects_mouse_interception_x11_filter.h" #include "effectloader.h" #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" @@ -690,6 +691,7 @@ void EffectsHandlerImpl::startMouseInterception(Effect *effect, Qt::CursorShape } m_mouseInterceptionWindow.map(); m_mouseInterceptionWindow.raise(); + m_x11MouseInterception = std::make_unique(m_mouseInterceptionWindow, this); // Raise electric border windows above the input windows // so they can still be triggered. ScreenEdges::self()->ensureOnTop(); @@ -707,6 +709,7 @@ void EffectsHandlerImpl::stopMouseInterception(Effect *effect) } if (m_grabbedMouseEffects.isEmpty()) { m_mouseInterceptionWindow.unmap(); + m_x11MouseInterception.reset(); Workspace::self()->stackScreenEdgesUnderOverrideRedirect(); } } diff --git a/effects.h b/effects.h index b9eb3d36a7..92c28c13cb 100644 --- a/effects.h +++ b/effects.h @@ -58,6 +58,7 @@ class Client; class Compositor; class Deleted; class EffectLoader; +class EffectsMouseInterceptionX11Filter; class Unmanaged; class KWIN_EXPORT EffectsHandlerImpl : public EffectsHandler @@ -319,6 +320,7 @@ private: QList m_grabbedMouseEffects; EffectLoader *m_effectLoader; int m_trackingCursorChanges; + std::unique_ptr m_x11MouseInterception; }; class EffectWindowImpl : public EffectWindow diff --git a/effects_mouse_interception_x11_filter.cpp b/effects_mouse_interception_x11_filter.cpp new file mode 100644 index 0000000000..e33dedbaae --- /dev/null +++ b/effects_mouse_interception_x11_filter.cpp @@ -0,0 +1,65 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2017 Martin Flöser + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "effects_mouse_interception_x11_filter.h" +#include "effects.h" +#include "utils.h" + +#include + +namespace KWin +{ + +EffectsMouseInterceptionX11Filter::EffectsMouseInterceptionX11Filter(xcb_window_t window, EffectsHandlerImpl *effects) + : X11EventFilter(QVector{XCB_BUTTON_PRESS, XCB_BUTTON_RELEASE, XCB_MOTION_NOTIFY}) + , m_effects(effects) + , m_window(window) +{ +} + +bool EffectsMouseInterceptionX11Filter::event(xcb_generic_event_t *event) +{ + const uint8_t eventType = event->response_type & ~0x80; + if (eventType == XCB_BUTTON_PRESS || eventType == XCB_BUTTON_RELEASE) { + auto *me = reinterpret_cast(event); + if (m_window == me->event) { + const Qt::MouseButton button = x11ToQtMouseButton(me->detail); + Qt::MouseButtons buttons = x11ToQtMouseButtons(me->state); + const QEvent::Type type = (eventType == XCB_BUTTON_PRESS) ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease; + if (type == QEvent::MouseButtonPress) { + buttons |= button; + } else { + buttons &= ~button; + } + QMouseEvent ev(type, QPoint(me->event_x, me->event_y), QPoint(me->root_x, me->root_y), + button, buttons, x11ToQtKeyboardModifiers(me->state)); + return m_effects->checkInputWindowEvent(&ev); + } + } else if (eventType == XCB_MOTION_NOTIFY) { + const auto *me = reinterpret_cast(event); + if (m_window == me->event) { + QMouseEvent ev(QEvent::MouseMove, QPoint(me->event_x, me->event_y), QPoint(me->root_x, me->root_y), + Qt::NoButton, x11ToQtMouseButtons(me->state), x11ToQtKeyboardModifiers(me->state)); + return m_effects->checkInputWindowEvent(&ev); + } + } + return false; +} + +} diff --git a/effects_mouse_interception_x11_filter.h b/effects_mouse_interception_x11_filter.h new file mode 100644 index 0000000000..740a87a3e2 --- /dev/null +++ b/effects_mouse_interception_x11_filter.h @@ -0,0 +1,43 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2017 Martin Flöser + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_EFFECTS_MOUSE_INTERCEPTION_X11_FILTER_H +#define KWIN_EFFECTS_MOUSE_INTERCEPTION_X11_FILTER_H + +#include "x11eventfilter.h" + +namespace KWin +{ +class EffectsHandlerImpl; + +class EffectsMouseInterceptionX11Filter : public X11EventFilter +{ +public: + explicit EffectsMouseInterceptionX11Filter(xcb_window_t window, EffectsHandlerImpl *effects); + + bool event(xcb_generic_event_t *event) override; + +private: + EffectsHandlerImpl *m_effects; + xcb_window_t m_window; +}; + +} + +#endif diff --git a/events.cpp b/events.cpp index 5f8ea61a65..61527446db 100644 --- a/events.cpp +++ b/events.cpp @@ -259,25 +259,6 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e) // events that should be handled before Clients can get them switch (eventType) { - case XCB_BUTTON_PRESS: - case XCB_BUTTON_RELEASE: { - auto *mouseEvent = reinterpret_cast(e); - if (effects && static_cast(effects)->checkInputWindowEvent(mouseEvent)) { - return true; - } - break; - } - case XCB_MOTION_NOTIFY: { - if (kwinApp()->operationMode() != Application::OperationModeX11) { - // ignore X11 pointer events generated on X windows if we are not on X - return true; - } - auto *mouseEvent = reinterpret_cast(e); - if (effects && static_cast(effects)->checkInputWindowEvent(mouseEvent)) { - return true; - } - break; - } case XCB_CONFIGURE_NOTIFY: if (reinterpret_cast(e)->event == rootWindow()) markXStackingOrderAsDirty();