diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -466,7 +466,6 @@ egl_context_attribute_builder.cpp was_user_interaction_x11_filter.cpp moving_client_x11_filter.cpp - effects_mouse_interception_x11_filter.cpp window_property_notify_x11_filter.cpp rootinfo_filter.cpp ) diff --git a/composite.cpp b/composite.cpp --- a/composite.cpp +++ b/composite.cpp @@ -296,7 +296,7 @@ vBlankInterval = milliToNano(1); // no sync - DO NOT set "0", would cause div-by-zero segfaults. m_timeSinceLastVBlank = fpsInterval - (options->vBlankTime() + 1); // means "start now" - we don't have even a slight idea when the first vsync will occur scheduleRepaint(); - new EffectsHandlerImpl(this, m_scene); // sets also the 'effects' pointer + kwinApp()->platform()->createEffectsHandler(this, m_scene); // sets also the 'effects' pointer connect(Workspace::self(), &Workspace::deletedRemoved, m_scene, &Scene::windowDeleted); connect(effects, SIGNAL(screenGeometryChanged(QSize)), SLOT(addRepaintFull())); addRepaintFull(); diff --git a/effects.h b/effects.h --- a/effects.h +++ b/effects.h @@ -26,7 +26,6 @@ #include "client.h" #include "scene.h" -#include "xcbutils.h" #include #include @@ -58,7 +57,6 @@ class Compositor; class Deleted; class EffectLoader; -class EffectsMouseInterceptionX11Filter; class Unmanaged; class WindowPropertyNotifyX11Filter; @@ -294,6 +292,30 @@ void setupClientConnections(KWin::Client *c); void setupUnmanagedConnections(KWin::Unmanaged *u); + /** + * Default implementation does nothing and returns @c true. + **/ + virtual bool doGrabKeyboard(); + /** + * Default implementation does nothing. + **/ + virtual void doUngrabKeyboard(); + + /** + * Default implementation sets Effects override cursor on the PointerInputRedirection. + **/ + virtual void doStartMouseInterception(Qt::CursorShape shape); + + /** + * Default implementation removes the Effects override cursor on the PointerInputRedirection. + **/ + virtual void doStopMouseInterception(); + + /** + * Default implementation does nothing + **/ + virtual void doCheckInputWindowStacking(); + Effect* keyboard_grab_effect; Effect* fullscreen_effect; QList elevated_windows; @@ -318,11 +340,9 @@ Scene *m_scene; bool m_desktopRendering; int m_currentRenderedDesktop; - Xcb::Window m_mouseInterceptionWindow; QList m_grabbedMouseEffects; EffectLoader *m_effectLoader; int m_trackingCursorChanges; - std::unique_ptr m_x11MouseInterception; std::unique_ptr m_x11WindowPropertyNotify; }; diff --git a/effects.cpp b/effects.cpp --- a/effects.cpp +++ b/effects.cpp @@ -22,7 +22,6 @@ #include "effects.h" #include "effectsadaptor.h" -#include "effects_mouse_interception_x11_filter.h" #include "effectloader.h" #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" @@ -633,29 +632,29 @@ { if (keyboard_grab_effect != NULL) return false; - if (kwinApp()->operationMode() == Application::OperationModeX11) { - bool ret = grabXKeyboard(); - if (!ret) - return false; - // Workaround for Qt 5.9 regression introduced with 2b34aefcf02f09253473b096eb4faffd3e62b5f4 - // we no longer get any events for the root window, one needs to call winId() on the desktop window - // TODO: change effects event handling to create the appropriate QKeyEvent without relying on Qt - // as it's done already in the Wayland case. - qApp->desktop()->winId(); + if (!doGrabKeyboard()) { + return false; } keyboard_grab_effect = effect; return true; } +bool EffectsHandlerImpl::doGrabKeyboard() +{ + return true; +} + void EffectsHandlerImpl::ungrabKeyboard() { assert(keyboard_grab_effect != NULL); - if (kwinApp()->operationMode() == Application::OperationModeX11) { - ungrabXKeyboard(); - } + doUngrabKeyboard(); keyboard_grab_effect = NULL; } +void EffectsHandlerImpl::doUngrabKeyboard() +{ +} + void EffectsHandlerImpl::grabbedKeyboardEvent(QKeyEvent* e) { if (keyboard_grab_effect != NULL) @@ -671,31 +670,12 @@ if (m_grabbedMouseEffects.size() != 1) { return; } - if (kwinApp()->operationMode() != Application::OperationModeX11) { - input()->pointer()->setEffectsOverrideCursor(shape); - return; - } - // NOTE: it is intended to not perform an XPointerGrab on X11. See documentation in kwineffects.h - // The mouse grab is implemented by using a full screen input only window - if (!m_mouseInterceptionWindow.isValid()) { - const QSize &s = screens()->size(); - const QRect geo(0, 0, s.width(), s.height()); - const uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; - const uint32_t values[] = { - true, - XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION - }; - m_mouseInterceptionWindow.reset(Xcb::createInputWindow(geo, mask, values)); - defineCursor(shape); - } else { - defineCursor(shape); - } - 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(); + doStartMouseInterception(shape); +} + +void EffectsHandlerImpl::doStartMouseInterception(Qt::CursorShape shape) +{ + input()->pointer()->setEffectsOverrideCursor(shape); } void EffectsHandlerImpl::stopMouseInterception(Effect *effect) @@ -705,16 +685,15 @@ } m_grabbedMouseEffects.removeAll(effect); if (m_grabbedMouseEffects.isEmpty()) { - if (kwinApp()->operationMode() != Application::OperationModeX11) { - input()->pointer()->removeEffectsOverrideCursor(); - return; - } - m_mouseInterceptionWindow.unmap(); - m_x11MouseInterception.reset(); - Workspace::self()->stackScreenEdgesUnderOverrideRedirect(); + doStopMouseInterception(); } } +void EffectsHandlerImpl::doStopMouseInterception() +{ + input()->pointer()->removeEffectsOverrideCursor(); +} + bool EffectsHandlerImpl::isMouseInterception() const { return m_grabbedMouseEffects.count() > 0; @@ -803,9 +782,6 @@ void EffectsHandlerImpl::desktopResized(const QSize &size) { m_scene->screenGeometryChanged(size); - if (m_mouseInterceptionWindow.isValid()) { - m_mouseInterceptionWindow.setGeometry(QRect(0, 0, size.width(), size.height())); - } emit screenGeometryChanged(size); } @@ -1220,14 +1196,7 @@ void EffectsHandlerImpl::defineCursor(Qt::CursorShape shape) { - if (!m_mouseInterceptionWindow.isValid()) { - input()->pointer()->setEffectsOverrideCursor(shape); - return; - } - const xcb_cursor_t c = Cursor::x11Cursor(shape); - if (c != XCB_CURSOR_NONE) { - m_mouseInterceptionWindow.defineCursor(c); - } + input()->pointer()->setEffectsOverrideCursor(shape); } bool EffectsHandlerImpl::checkInputWindowEvent(QMouseEvent *e) @@ -1282,13 +1251,11 @@ if (m_grabbedMouseEffects.isEmpty()) { return; } - if (kwinApp()->operationMode() != Application::OperationModeX11) { - return; - } - m_mouseInterceptionWindow.raise(); - // Raise electric border windows above the input windows - // so they can still be triggered. TODO: Do both at once. - ScreenEdges::self()->ensureOnTop(); + doCheckInputWindowStacking(); +} + +void EffectsHandlerImpl::doCheckInputWindowStacking() +{ } QPoint EffectsHandlerImpl::cursorPos() const diff --git a/platform.h b/platform.h --- a/platform.h +++ b/platform.h @@ -40,11 +40,13 @@ { class Edge; +class Compositor; class OverlayWindow; class OpenGLBackend; class Outline; class OutlineVisual; class QPainterBackend; +class Scene; class Screens; class ScreenEdges; class Toplevel; @@ -370,6 +372,11 @@ **/ virtual void invertScreen(); + /** + * Default implementation creates an EffectsHandlerImp; + **/ + virtual void createEffectsHandler(Compositor *compositor, Scene *scene); + public Q_SLOTS: void pointerMotion(const QPointF &position, quint32 time); void pointerButtonPressed(quint32 button, quint32 time); diff --git a/platform.cpp b/platform.cpp --- a/platform.cpp +++ b/platform.cpp @@ -472,4 +472,9 @@ } } +void Platform::createEffectsHandler(Compositor *compositor, Scene *scene) +{ + new EffectsHandlerImpl(compositor, scene); +} + } diff --git a/plugins/platforms/wayland/wayland_backend.cpp b/plugins/platforms/wayland/wayland_backend.cpp --- a/plugins/platforms/wayland/wayland_backend.cpp +++ b/plugins/platforms/wayland/wayland_backend.cpp @@ -337,7 +337,7 @@ , m_display(nullptr) , m_eventQueue(new EventQueue(this)) , m_registry(new Registry(this)) - , m_compositor(new Compositor(this)) + , m_compositor(new KWayland::Client::Compositor(this)) , m_shell(new Shell(this)) , m_surface(nullptr) , m_shellSurface(NULL) diff --git a/plugins/platforms/x11/standalone/CMakeLists.txt b/plugins/platforms/x11/standalone/CMakeLists.txt --- a/plugins/platforms/x11/standalone/CMakeLists.txt +++ b/plugins/platforms/x11/standalone/CMakeLists.txt @@ -10,6 +10,8 @@ non_composited_outline.cpp x11_decoration_renderer.cpp xfixes_cursor_event_filter.cpp + effects_x11.cpp + effects_mouse_interception_x11_filter.cpp ) if(X11_Xinput_FOUND) diff --git a/effects_mouse_interception_x11_filter.h b/plugins/platforms/x11/standalone/effects_mouse_interception_x11_filter.h rename from effects_mouse_interception_x11_filter.h rename to plugins/platforms/x11/standalone/effects_mouse_interception_x11_filter.h diff --git a/effects_mouse_interception_x11_filter.cpp b/plugins/platforms/x11/standalone/effects_mouse_interception_x11_filter.cpp rename from effects_mouse_interception_x11_filter.cpp rename to plugins/platforms/x11/standalone/effects_mouse_interception_x11_filter.cpp diff --git a/plugins/platforms/x11/standalone/effects_x11.h b/plugins/platforms/x11/standalone/effects_x11.h new file mode 100644 --- /dev/null +++ b/plugins/platforms/x11/standalone/effects_x11.h @@ -0,0 +1,58 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2010, 2011, 2017 Martin Gräßlin + +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_X11_H +#define KWIN_EFFECTS_X11_H + +#include "effects.h" +#include "xcbutils.h" + +#include + +namespace KWin +{ +class EffectsMouseInterceptionX11Filter; + +class EffectsHandlerImplX11 : public EffectsHandlerImpl +{ + Q_OBJECT +public: + explicit EffectsHandlerImplX11(Compositor *compositor, Scene *scene); + virtual ~EffectsHandlerImplX11(); + + void defineCursor(Qt::CursorShape shape) override; + +protected: + bool doGrabKeyboard() override; + void doUngrabKeyboard() override; + + void doStartMouseInterception(Qt::CursorShape shape) override; + void doStopMouseInterception() override; + + void doCheckInputWindowStacking() override; + +private: + Xcb::Window m_mouseInterceptionWindow; + std::unique_ptr m_x11MouseInterception; +}; + +} + +#endif diff --git a/plugins/platforms/x11/standalone/effects_x11.cpp b/plugins/platforms/x11/standalone/effects_x11.cpp new file mode 100644 --- /dev/null +++ b/plugins/platforms/x11/standalone/effects_x11.cpp @@ -0,0 +1,114 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2010, 2011, 2017 Martin Gräßlin + +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_x11.h" +#include "effects_mouse_interception_x11_filter.h" +#include "cursor.h" +#include "screenedge.h" +#include "screens.h" +#include "utils.h" +#include "workspace.h" + +#include + +namespace KWin +{ + +EffectsHandlerImplX11::EffectsHandlerImplX11(Compositor *compositor, Scene *scene) + : EffectsHandlerImpl(compositor, scene) +{ + connect(this, &EffectsHandlerImpl::screenGeometryChanged, this, + [this] (const QSize &size) { + if (m_mouseInterceptionWindow.isValid()) { + m_mouseInterceptionWindow.setGeometry(QRect(0, 0, size.width(), size.height())); + } + } + ); +} + +EffectsHandlerImplX11::~EffectsHandlerImplX11() = default; + +bool EffectsHandlerImplX11::doGrabKeyboard() +{ + bool ret = grabXKeyboard(); + if (!ret) + return false; + // Workaround for Qt 5.9 regression introduced with 2b34aefcf02f09253473b096eb4faffd3e62b5f4 + // we no longer get any events for the root window, one needs to call winId() on the desktop window + // TODO: change effects event handling to create the appropriate QKeyEvent without relying on Qt + // as it's done already in the Wayland case. + qApp->desktop()->winId(); + return ret; +} + +void EffectsHandlerImplX11::doUngrabKeyboard() +{ + ungrabXKeyboard(); +} + +void EffectsHandlerImplX11::doStartMouseInterception(Qt::CursorShape shape) +{ + // NOTE: it is intended to not perform an XPointerGrab on X11. See documentation in kwineffects.h + // The mouse grab is implemented by using a full screen input only window + if (!m_mouseInterceptionWindow.isValid()) { + const QSize &s = screens()->size(); + const QRect geo(0, 0, s.width(), s.height()); + const uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; + const uint32_t values[] = { + true, + XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION + }; + m_mouseInterceptionWindow.reset(Xcb::createInputWindow(geo, mask, values)); + defineCursor(shape); + } else { + defineCursor(shape); + } + 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(); +} + +void EffectsHandlerImplX11::doStopMouseInterception() +{ + m_mouseInterceptionWindow.unmap(); + m_x11MouseInterception.reset(); + Workspace::self()->stackScreenEdgesUnderOverrideRedirect(); +} + +void EffectsHandlerImplX11::defineCursor(Qt::CursorShape shape) +{ + const xcb_cursor_t c = Cursor::x11Cursor(shape); + if (c != XCB_CURSOR_NONE) { + m_mouseInterceptionWindow.defineCursor(c); + } +} + +void EffectsHandlerImplX11::doCheckInputWindowStacking() +{ + m_mouseInterceptionWindow.raise(); + // Raise electric border windows above the input windows + // so they can still be triggered. TODO: Do both at once. + ScreenEdges::self()->ensureOnTop(); +} + +} diff --git a/plugins/platforms/x11/standalone/x11_platform.h b/plugins/platforms/x11/standalone/x11_platform.h --- a/plugins/platforms/x11/standalone/x11_platform.h +++ b/plugins/platforms/x11/standalone/x11_platform.h @@ -64,6 +64,8 @@ void invertScreen() override; + void createEffectsHandler(Compositor *compositor, Scene *scene) override; + protected: void doHideCursor() override; void doShowCursor() override; diff --git a/plugins/platforms/x11/standalone/x11_platform.cpp b/plugins/platforms/x11/standalone/x11_platform.cpp --- a/plugins/platforms/x11/standalone/x11_platform.cpp +++ b/plugins/platforms/x11/standalone/x11_platform.cpp @@ -30,6 +30,7 @@ #include "xinputintegration.h" #endif #include "abstract_client.h" +#include "effects_x11.h" #include "eglonxbackend.h" #include "keyboard_input.h" #include "logging.h" @@ -404,4 +405,9 @@ } } +void X11StandalonePlatform::createEffectsHandler(Compositor *compositor, Scene *scene) +{ + new EffectsHandlerImplX11(compositor, scene); +} + } diff --git a/utils.h b/utils.h --- a/utils.h +++ b/utils.h @@ -188,6 +188,7 @@ // converting between X11 mouse/keyboard state mask and Qt button/keyboard states Qt::MouseButton x11ToQtMouseButton(int button); +Qt::MouseButton KWIN_EXPORT x11ToQtMouseButton(int button); Qt::MouseButtons KWIN_EXPORT x11ToQtMouseButtons(int state); Qt::KeyboardModifiers KWIN_EXPORT x11ToQtKeyboardModifiers(int state);