Commit 833f933c authored by Martin Flöser's avatar Martin Flöser

Move X11 specific event filtering for ScreenEdges into x11 standalone platform

Summary:
This change splits out the X11 specific event filtering into a dedicated
X11EventFilter. It is created in the x11 standalone platform plugin when
the first Edge is being created.

Some of the X11 specific code is removed from ScreenEdges, though more
refactoring is possible in ScreenEdges to share more code between X11
specific and generic implementation.

Test Plan: Run KWin on Xephyr, screen edge approach effect still shows

Reviewers: #kwin, #plasma

Subscribers: plasma-devel, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D7406
parent 76ee4715
......@@ -466,7 +466,10 @@ void TestScreenEdges::testCallback()
event.same_screen_focus = 1;
event.time = QDateTime::currentMSecsSinceEpoch();
setPos(QPoint(0, 50));
QVERIFY(s->isEntered(&event));
auto isEntered = [s] (xcb_enter_notify_event_t *event) {
return s->handleEnterNotifiy(event->event, QPoint(event->root_x, event->root_y), QDateTime::fromMSecsSinceEpoch(event->time));
};
QVERIFY(isEntered(&event));
// doesn't trigger as the edge was not triggered yet
QVERIFY(spy.isEmpty());
QCOMPARE(Cursor::pos(), QPoint(1, 50));
......@@ -475,7 +478,7 @@ void TestScreenEdges::testCallback()
QTest::qWait(160);
setPos(QPoint(0, 100));
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
QCOMPARE(Cursor::pos(), QPoint(1, 100));
......@@ -483,7 +486,7 @@ void TestScreenEdges::testCallback()
QTest::qWait(200);
setPos(QPoint(0, 101));
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
QCOMPARE(Cursor::pos(), QPoint(1, 101));
......@@ -491,7 +494,7 @@ void TestScreenEdges::testCallback()
QTest::qWait(50);
setPos(QPoint(0, 100));
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
QCOMPARE(Cursor::pos(), QPoint(1, 100));
......@@ -499,7 +502,7 @@ void TestScreenEdges::testCallback()
QTest::qWait(110);
setPos(QPoint(0, 101));
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(!spy.isEmpty());
QCOMPARE(Cursor::pos(), QPoint(1, 101));
......@@ -507,21 +510,21 @@ void TestScreenEdges::testCallback()
QTest::qWait(351);
setPos(QPoint(0, 100));
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QCOMPARE(spy.count(), 1);
QCOMPARE(Cursor::pos(), QPoint(1, 100));
// it's still under the reactivation
QTest::qWait(50);
setPos(QPoint(0, 100));
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QCOMPARE(spy.count(), 1);
QCOMPARE(Cursor::pos(), QPoint(1, 100));
// now it should trigger again
QTest::qWait(250);
setPos(QPoint(0, 100));
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QCOMPARE(spy.count(), 2);
QCOMPARE(spy.first().first().value<ElectricBorder>(), ElectricLeft);
QCOMPARE(spy.last().first().value<ElectricBorder>(), ElectricLeft);
......@@ -536,7 +539,7 @@ void TestScreenEdges::testCallback()
// it should trigger directly
QTest::qWait(350);
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QCOMPARE(spy.count(), 3);
QCOMPARE(spy.at(0).first().value<ElectricBorder>(), ElectricLeft);
QCOMPARE(spy.at(1).first().value<ElectricBorder>(), ElectricLeft);
......@@ -645,7 +648,10 @@ void TestScreenEdges::testPushBack()
event.event = s->windows().first();
event.same_screen_focus = 1;
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
auto isEntered = [s] (xcb_enter_notify_event_t *event) {
return s->handleEnterNotifiy(event->event, QPoint(event->root_x, event->root_y), QDateTime::fromMSecsSinceEpoch(event->time));
};
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
QTEST(Cursor::pos(), "expected");
......@@ -692,7 +698,10 @@ void TestScreenEdges::testFullScreenBlocking()
event.event = s->windows().first();
event.same_screen_focus = 1;
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
auto isEntered = [s] (xcb_enter_notify_event_t *event) {
return s->handleEnterNotifiy(event->event, QPoint(event->root_x, event->root_y), QDateTime::fromMSecsSinceEpoch(event->time));
};
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
QCOMPARE(Cursor::pos(), QPoint(1, 50));
......@@ -710,7 +719,7 @@ void TestScreenEdges::testFullScreenBlocking()
QTest::qWait(160);
Cursor::setPos(0, 50);
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
// and no pushback
QCOMPARE(Cursor::pos(), QPoint(0, 50));
......@@ -722,7 +731,7 @@ void TestScreenEdges::testFullScreenBlocking()
QCOMPARE(e->activatesForTouchGesture(), e->border() == KWin::ElectricRight);
}
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(!spy.isEmpty());
QCOMPARE(Cursor::pos(), QPoint(1, 50));
......@@ -734,7 +743,7 @@ void TestScreenEdges::testFullScreenBlocking()
spy.clear();
Cursor::setPos(0, 50);
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
// and a pushback
QCOMPARE(Cursor::pos(), QPoint(1, 50));
......@@ -743,7 +752,7 @@ void TestScreenEdges::testFullScreenBlocking()
client.setGeometry(screens()->geometry());
emit s->checkBlocking();
Cursor::setPos(0, 50);
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
// and no pushback
QCOMPARE(Cursor::pos(), QPoint(0, 50));
......@@ -757,14 +766,14 @@ void TestScreenEdges::testFullScreenBlocking()
event.event = s->windows().first();
event.time = QDateTime::currentMSecsSinceEpoch();
Cursor::setPos(99, 99);
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(spy.isEmpty());
// and pushback
QCOMPARE(Cursor::pos(), QPoint(98, 98));
QTest::qWait(160);
event.time = QDateTime::currentMSecsSinceEpoch();
Cursor::setPos(99, 99);
QVERIFY(s->isEntered(&event));
QVERIFY(isEntered(&event));
QVERIFY(!spy.isEmpty());
}
......@@ -812,7 +821,10 @@ void TestScreenEdges::testClientEdge()
event.event = s->windows().first();
event.same_screen_focus = 1;
event.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event));
auto isEntered = [s] (xcb_enter_notify_event_t *event) {
return s->handleEnterNotifiy(event->event, QPoint(event->root_x, event->root_y), QDateTime::fromMSecsSinceEpoch(event->time));
};
QVERIFY(isEntered(&event));
// autohiding panels shall activate instantly
QCOMPARE(client.isHiddenInternal(), false);
QCOMPARE(Cursor::pos(), QPoint(1, 50));
......@@ -882,7 +894,7 @@ void TestScreenEdges::testClientEdge()
event2.event = s->windows().first();
event2.same_screen_focus = 1;
event2.time = QDateTime::currentMSecsSinceEpoch();
QVERIFY(s->isEntered(&event2));
QVERIFY(isEntered(&event2));
QCOMPARE(client.keepBelow(), false);
QCOMPARE(client.isHiddenInternal(), false);
QCOMPARE(Cursor::pos(), QPoint(1, 50));
......@@ -946,7 +958,10 @@ void TestScreenEdges::testTouchEdge()
event.same_screen_focus = 1;
event.time = QDateTime::currentMSecsSinceEpoch();
setPos(QPoint(0, 50));
QCOMPARE(s->isEntered(&event), false);
auto isEntered = [s] (xcb_enter_notify_event_t *event) {
return s->handleEnterNotifiy(event->event, QPoint(event->root_x, event->root_y), QDateTime::fromMSecsSinceEpoch(event->time));
};
QCOMPARE(isEntered(&event), false);
QVERIFY(approachingSpy.isEmpty());
// let's also verify the check
s->check(QPoint(0, 50), QDateTime::currentDateTime(), false);
......
......@@ -39,7 +39,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "unmanaged.h"
#include "useractions.h"
#include "effects.h"
#include "screenedge.h"
#include "screens.h"
#include "xcbutils.h"
......@@ -276,15 +275,9 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
return true;
}
auto *mouseEvent = reinterpret_cast<xcb_motion_notify_event_t*>(e);
const QPoint rootPos(mouseEvent->root_x, mouseEvent->root_y);
if (effects && static_cast<EffectsHandlerImpl*>(effects)->checkInputWindowEvent(mouseEvent)) {
return true;
}
if (QWidget::mouseGrabber()) {
ScreenEdges::self()->check(rootPos, QDateTime::fromMSecsSinceEpoch(xTime()), true);
} else {
ScreenEdges::self()->check(rootPos, QDateTime::fromMSecsSinceEpoch(mouseEvent->time));
}
break;
}
case XCB_CONFIGURE_NOTIFY:
......@@ -383,11 +376,6 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
return (event->event != event->window); // hide wm typical event from Qt
}
case XCB_ENTER_NOTIFY: {
if (ScreenEdges::self()->isEntered(reinterpret_cast<xcb_enter_notify_event_t*>(e)))
return true;
break;
}
case XCB_CONFIGURE_REQUEST: {
const auto *event = reinterpret_cast<xcb_configure_request_event_t*>(e);
if (event->parent == rootWindow()) {
......@@ -439,10 +427,6 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e)
// fall through
case XCB_FOCUS_OUT:
return true; // always eat these, they would tell Qt that KWin is the active app
case XCB_CLIENT_MESSAGE:
if (ScreenEdges::self()->isEntered(reinterpret_cast<xcb_client_message_event_t*>(e)))
return true;
break;
default:
if (eventType == Xcb::Extensions::self()->randrNotifyEvent() && Xcb::Extensions::self()->isRandrAvailable()) {
auto *event = reinterpret_cast<xcb_randr_screen_change_notify_event_t*>(e);
......
......@@ -6,6 +6,7 @@ set(X11PLATFORM_SOURCES
screens_xrandr.cpp
windowselector.cpp
overlaywindow_x11.cpp
screenedges_filter.cpp
)
if(X11_Xinput_FOUND)
......
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "screenedges_filter.h"
#include "atoms.h"
#include "screenedge.h"
#include <QWidget>
#include <xcb/xcb.h>
namespace KWin
{
ScreenEdgesFilter::ScreenEdgesFilter()
: X11EventFilter(QVector<int>{XCB_MOTION_NOTIFY, XCB_ENTER_NOTIFY, XCB_CLIENT_MESSAGE})
{
}
bool ScreenEdgesFilter::event(xcb_generic_event_t *event)
{
const uint8_t eventType = event->response_type & ~0x80;
switch (eventType) {
case XCB_MOTION_NOTIFY: {
const auto mouseEvent = reinterpret_cast<xcb_motion_notify_event_t*>(event);
const QPoint rootPos(mouseEvent->root_x, mouseEvent->root_y);
if (QWidget::mouseGrabber()) {
ScreenEdges::self()->check(rootPos, QDateTime::fromMSecsSinceEpoch(xTime()), true);
} else {
ScreenEdges::self()->check(rootPos, QDateTime::fromMSecsSinceEpoch(mouseEvent->time));
}
// not filtered out
break;
}
case XCB_ENTER_NOTIFY: {
const auto enter = reinterpret_cast<xcb_enter_notify_event_t*>(event);
return ScreenEdges::self()->handleEnterNotifiy(enter->event, QPoint(enter->root_x, enter->root_y), QDateTime::fromMSecsSinceEpoch(enter->time));
}
case XCB_CLIENT_MESSAGE: {
const auto ce = reinterpret_cast<xcb_client_message_event_t*>(event);
if (ce->type != atoms->xdnd_position) {
return false;
}
return ScreenEdges::self()->handleDndNotify(ce->window, QPoint(ce->data.data32[2] >> 16, ce->data.data32[2] & 0xffff));
}
}
return false;
}
}
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_SCREENEDGES_FILTER_H
#define KWIN_SCREENEDGES_FILTER_H
#include "x11eventfilter.h"
namespace KWin
{
class ScreenEdgesFilter : public X11EventFilter
{
public:
explicit ScreenEdgesFilter();
bool event(xcb_generic_event_t *event) override;
};
}
#endif
......@@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "keyboard_input.h"
#include "logging.h"
#include "screens_xrandr.h"
#include "screenedges_filter.h"
#include "options.h"
#include "overlaywindow_x11.h"
......@@ -113,6 +114,9 @@ OpenGLBackend *X11StandalonePlatform::createOpenGLBackend()
Edge *X11StandalonePlatform::createScreenEdge(ScreenEdges *edges)
{
if (m_screenEdgesFilter.isNull()) {
m_screenEdgesFilter.reset(new ScreenEdgesFilter);
}
return new WindowBasedEdge(edges);
}
......
......@@ -29,6 +29,7 @@ namespace KWin
{
class XInputIntegration;
class WindowSelector;
class X11EventFilter;
class KWIN_EXPORT X11StandalonePlatform : public Platform
{
......@@ -80,6 +81,7 @@ private:
QTimer *m_openGLFreezeProtection = nullptr;
Display *m_x11Display;
QScopedPointer<WindowSelector> m_windowSelector;
QScopedPointer<X11EventFilter> m_screenEdgesFilter;
};
......
......@@ -30,7 +30,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "screenedge.h"
// KWin
#include "atoms.h"
#include "gestures.h"
#include <client.h>
#include "cursor.h"
......@@ -1367,22 +1366,6 @@ void ScreenEdges::check(const QPoint &pos, const QDateTime &now, bool forceNoPus
}
}
bool ScreenEdges::isEntered(xcb_enter_notify_event_t *event)
{
return handleEnterNotifiy(event->event,
QPoint(event->root_x, event->root_y),
QDateTime::fromMSecsSinceEpoch(event->time));
}
bool ScreenEdges::isEntered(xcb_client_message_event_t *event)
{
if (event->type != atoms->xdnd_position) {
return false;
}
return handleDndNotify(event->window,
QPoint(event->data.data32[2] >> 16, event->data.data32[2] & 0xffff));
}
bool ScreenEdges::isEntered(QMouseEvent *event)
{
if (event->type() != QEvent::MouseMove) {
......
......@@ -312,14 +312,6 @@ public:
* to do this if an effect input window is active.
*/
void ensureOnTop();
/**
* Called when the user entered an electric border with the mouse.
* It may switch to another virtual desktop.
* @param e the X event which is passed to this method.
*/
bool isEntered(xcb_generic_event_t *e);
bool isEntered(xcb_enter_notify_event_t *e);
bool isEntered(xcb_client_message_event_t *e);
bool isEntered(QMouseEvent *event);
/**
......@@ -352,6 +344,9 @@ public:
return m_gestureRecognizer;
}
bool handleDndNotify(xcb_window_t window, const QPoint &point);
bool handleEnterNotifiy(xcb_window_t window, const QPoint &point, const QDateTime &timestamp);
public Q_SLOTS:
void reconfigure();
/**
......@@ -387,8 +382,6 @@ private:
void setActionForTouchBorder(ElectricBorder border, ElectricBorderAction newValue);
ElectricBorderAction actionForEdge(Edge *edge) const;
ElectricBorderAction actionForTouchEdge(Edge *edge) const;
bool handleEnterNotifiy(xcb_window_t window, const QPoint &point, const QDateTime &timestamp);
bool handleDndNotify(xcb_window_t window, const QPoint &point);
void createEdgeForClient(AbstractClient *client, ElectricBorder border);
void deleteEdgeForClient(AbstractClient *client);
bool m_desktopSwitching;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment