diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -456,6 +456,7 @@ 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.h b/effects.h --- a/effects.h +++ b/effects.h @@ -58,6 +58,7 @@ class Compositor; class Deleted; class EffectLoader; +class EffectsMouseInterceptionX11Filter; class Unmanaged; class KWIN_EXPORT EffectsHandlerImpl : public EffectsHandler @@ -319,6 +320,7 @@ QList m_grabbedMouseEffects; EffectLoader *m_effectLoader; int m_trackingCursorChanges; + std::unique_ptr m_x11MouseInterception; }; class EffectWindowImpl : public EffectWindow diff --git a/effects.cpp b/effects.cpp --- a/effects.cpp +++ b/effects.cpp @@ -22,6 +22,7 @@ #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 @@ } 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 @@ } if (m_grabbedMouseEffects.isEmpty()) { m_mouseInterceptionWindow.unmap(); + m_x11MouseInterception.reset(); Workspace::self()->stackScreenEdgesUnderOverrideRedirect(); } } diff --git a/effects_mouse_interception_x11_filter.h b/effects_mouse_interception_x11_filter.h new file mode 100644 --- /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/effects_mouse_interception_x11_filter.cpp b/effects_mouse_interception_x11_filter.cpp new file mode 100644 --- /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/events.cpp b/events.cpp --- a/events.cpp +++ b/events.cpp @@ -259,25 +259,6 @@ // 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();