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
icc-effect-5.14.5
Martin Flöser 2017-08-19 10:58:05 +02:00
parent 76ee47151a
commit 833f933c5c
9 changed files with 147 additions and 63 deletions

View File

@ -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);

View File

@ -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);

View File

@ -6,6 +6,7 @@ set(X11PLATFORM_SOURCES
screens_xrandr.cpp
windowselector.cpp
overlaywindow_x11.cpp
screenedges_filter.cpp
)
if(X11_Xinput_FOUND)

View File

@ -0,0 +1,65 @@
/********************************************************************
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;
}
}

View File

@ -0,0 +1,37 @@
/********************************************************************
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

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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) {

View File

@ -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;