x11: Move event filter logic to kwinApp()

This allows the X11 platform plugin to create event filters before the
workspace object is created.
This commit is contained in:
Vlad Zahorodnii 2021-01-31 14:12:02 +02:00
parent 7c55f5ed7d
commit 9e999fe2a1
6 changed files with 158 additions and 151 deletions

View file

@ -141,129 +141,12 @@ static xcb_window_t findEventWindow(xcb_generic_event_t *event)
}
}
QVector<QByteArray> s_xcbEerrors({
QByteArrayLiteral("Success"),
QByteArrayLiteral("BadRequest"),
QByteArrayLiteral("BadValue"),
QByteArrayLiteral("BadWindow"),
QByteArrayLiteral("BadPixmap"),
QByteArrayLiteral("BadAtom"),
QByteArrayLiteral("BadCursor"),
QByteArrayLiteral("BadFont"),
QByteArrayLiteral("BadMatch"),
QByteArrayLiteral("BadDrawable"),
QByteArrayLiteral("BadAccess"),
QByteArrayLiteral("BadAlloc"),
QByteArrayLiteral("BadColor"),
QByteArrayLiteral("BadGC"),
QByteArrayLiteral("BadIDChoice"),
QByteArrayLiteral("BadName"),
QByteArrayLiteral("BadLength"),
QByteArrayLiteral("BadImplementation"),
QByteArrayLiteral("Unknown")});
void Workspace::registerEventFilter(X11EventFilter *filter)
{
if (filter->isGenericEvent()) {
m_genericEventFilters.append(new X11EventFilterContainer(filter));
} else {
m_eventFilters.append(new X11EventFilterContainer(filter));
}
}
static X11EventFilterContainer *takeEventFilter(X11EventFilter *eventFilter,
QList<QPointer<X11EventFilterContainer>> &list)
{
for (int i = 0; i < list.count(); ++i) {
X11EventFilterContainer *container = list.at(i);
if (container->filter() == eventFilter) {
return list.takeAt(i);
}
}
return nullptr;
}
void Workspace::unregisterEventFilter(X11EventFilter *filter)
{
X11EventFilterContainer *container = nullptr;
if (filter->isGenericEvent()) {
container = takeEventFilter(filter, m_genericEventFilters);
} else {
container = takeEventFilter(filter, m_eventFilters);
}
delete container;
}
/**
* Handles workspace specific XCB event
*/
bool Workspace::workspaceEvent(xcb_generic_event_t *e)
{
const uint8_t eventType = e->response_type & ~0x80;
if (!eventType) {
// let's check whether it's an error from one of the extensions KWin uses
xcb_generic_error_t *error = reinterpret_cast<xcb_generic_error_t*>(e);
const QVector<Xcb::ExtensionData> extensions = Xcb::Extensions::self()->extensions();
for (const auto &extension : extensions) {
if (error->major_code == extension.majorOpcode) {
QByteArray errorName;
if (error->error_code < s_xcbEerrors.size()) {
errorName = s_xcbEerrors.at(error->error_code);
} else if (error->error_code >= extension.errorBase) {
const int index = error->error_code - extension.errorBase;
if (index >= 0 && index < extension.errorCodes.size()) {
errorName = extension.errorCodes.at(index);
}
}
if (errorName.isEmpty()) {
errorName = QByteArrayLiteral("Unknown");
}
qCWarning(KWIN_CORE, "XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d (%s)",
int(error->error_code), errorName.constData(),
int(error->sequence), int(error->resource_id),
int(error->major_code), extension.name.constData(),
int(error->minor_code),
extension.opCodes.size() > error->minor_code ? extension.opCodes.at(error->minor_code).constData() : "Unknown");
return true;
}
}
return false;
}
if (eventType == XCB_GE_GENERIC) {
xcb_ge_generic_event_t *ge = reinterpret_cast<xcb_ge_generic_event_t *>(e);
// We need to make a shadow copy of the event filter list because an activated event
// filter may mutate it by removing or installing another event filter.
const auto eventFilters = m_genericEventFilters;
for (X11EventFilterContainer *container : eventFilters) {
if (!container) {
continue;
}
X11EventFilter *filter = container->filter();
if (filter->extension() == ge->extension && filter->genericEventTypes().contains(ge->event_type) && filter->event(e)) {
return true;
}
}
} else {
// We need to make a shadow copy of the event filter list because an activated event
// filter may mutate it by removing or installing another event filter.
const auto eventFilters = m_eventFilters;
for (X11EventFilterContainer *container : eventFilters) {
if (!container) {
continue;
}
X11EventFilter *filter = container->filter();
if (filter->eventTypes().contains(eventType) && filter->event(e)) {
return true;
}
}
}
if (effects && static_cast< EffectsHandlerImpl* >(effects)->hasKeyboardGrab()
&& (eventType == XCB_KEY_PRESS || eventType == XCB_KEY_RELEASE))
return false; // let Qt process it, it'll be intercepted again in eventFilter()

View file

@ -25,6 +25,7 @@
#include "screenlockerwatcher.h"
#include "sm.h"
#include "workspace.h"
#include "x11eventfilter.h"
#include "xcbutils.h"
#include <kwineffects.h>
@ -357,6 +358,134 @@ void Application::destroyColorManager()
#endif
}
void Application::registerEventFilter(X11EventFilter *filter)
{
if (filter->isGenericEvent()) {
m_genericEventFilters.append(new X11EventFilterContainer(filter));
} else {
m_eventFilters.append(new X11EventFilterContainer(filter));
}
}
static X11EventFilterContainer *takeEventFilter(X11EventFilter *eventFilter,
QList<QPointer<X11EventFilterContainer>> &list)
{
for (int i = 0; i < list.count(); ++i) {
X11EventFilterContainer *container = list.at(i);
if (container->filter() == eventFilter) {
return list.takeAt(i);
}
}
return nullptr;
}
void Application::unregisterEventFilter(X11EventFilter *filter)
{
X11EventFilterContainer *container = nullptr;
if (filter->isGenericEvent()) {
container = takeEventFilter(filter, m_genericEventFilters);
} else {
container = takeEventFilter(filter, m_eventFilters);
}
delete container;
}
bool Application::dispatchEvent(xcb_generic_event_t *event)
{
static const QVector<QByteArray> s_xcbEerrors({
QByteArrayLiteral("Success"),
QByteArrayLiteral("BadRequest"),
QByteArrayLiteral("BadValue"),
QByteArrayLiteral("BadWindow"),
QByteArrayLiteral("BadPixmap"),
QByteArrayLiteral("BadAtom"),
QByteArrayLiteral("BadCursor"),
QByteArrayLiteral("BadFont"),
QByteArrayLiteral("BadMatch"),
QByteArrayLiteral("BadDrawable"),
QByteArrayLiteral("BadAccess"),
QByteArrayLiteral("BadAlloc"),
QByteArrayLiteral("BadColor"),
QByteArrayLiteral("BadGC"),
QByteArrayLiteral("BadIDChoice"),
QByteArrayLiteral("BadName"),
QByteArrayLiteral("BadLength"),
QByteArrayLiteral("BadImplementation"),
QByteArrayLiteral("Unknown")
});
kwinApp()->updateX11Time(event);
const uint8_t x11EventType = event->response_type & ~0x80;
if (!x11EventType) {
// let's check whether it's an error from one of the extensions KWin uses
xcb_generic_error_t *error = reinterpret_cast<xcb_generic_error_t*>(event);
const QVector<Xcb::ExtensionData> extensions = Xcb::Extensions::self()->extensions();
for (const auto &extension : extensions) {
if (error->major_code == extension.majorOpcode) {
QByteArray errorName;
if (error->error_code < s_xcbEerrors.size()) {
errorName = s_xcbEerrors.at(error->error_code);
} else if (error->error_code >= extension.errorBase) {
const int index = error->error_code - extension.errorBase;
if (index >= 0 && index < extension.errorCodes.size()) {
errorName = extension.errorCodes.at(index);
}
}
if (errorName.isEmpty()) {
errorName = QByteArrayLiteral("Unknown");
}
qCWarning(KWIN_CORE, "XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d (%s)",
int(error->error_code), errorName.constData(),
int(error->sequence), int(error->resource_id),
int(error->major_code), extension.name.constData(),
int(error->minor_code),
extension.opCodes.size() > error->minor_code ? extension.opCodes.at(error->minor_code).constData() : "Unknown");
return true;
}
}
return false;
}
if (x11EventType == XCB_GE_GENERIC) {
xcb_ge_generic_event_t *ge = reinterpret_cast<xcb_ge_generic_event_t *>(event);
// We need to make a shadow copy of the event filter list because an activated event
// filter may mutate it by removing or installing another event filter.
const auto eventFilters = m_genericEventFilters;
for (X11EventFilterContainer *container : eventFilters) {
if (!container) {
continue;
}
X11EventFilter *filter = container->filter();
if (filter->extension() == ge->extension && filter->genericEventTypes().contains(ge->event_type) && filter->event(event)) {
return true;
}
}
} else {
// We need to make a shadow copy of the event filter list because an activated event
// filter may mutate it by removing or installing another event filter.
const auto eventFilters = m_eventFilters;
for (X11EventFilterContainer *container : eventFilters) {
if (!container) {
continue;
}
X11EventFilter *filter = container->filter();
if (filter->eventTypes().contains(x11EventType) && filter->event(event)) {
return true;
}
}
}
if (workspace()) {
return workspace()->workspaceEvent(event);
}
return false;
}
void Application::updateX11Time(xcb_generic_event_t *event)
{
xcb_timestamp_t time = XCB_TIME_CURRENT_TIME;
@ -434,16 +563,10 @@ void Application::updateX11Time(xcb_generic_event_t *event)
bool XcbEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long int *result)
{
Q_UNUSED(result)
if (eventType != "xcb_generic_event_t") {
return false;
if (eventType == "xcb_generic_event_t") {
return kwinApp()->dispatchEvent(static_cast<xcb_generic_event_t *>(message));
}
auto event = static_cast<xcb_generic_event_t *>(message);
kwinApp()->updateX11Time(event);
if (!Workspace::self()) {
// Workspace not yet created
return false;
}
return Workspace::self()->workspaceEvent(event);
return false;
}
static bool s_useLibinput = false;

View file

@ -27,6 +27,7 @@ namespace KWin
{
class Platform;
class X11EventFilter;
class XcbEventFilter : public QAbstractNativeEventFilter
{
@ -34,6 +35,19 @@ public:
bool nativeEventFilter(const QByteArray &eventType, void *message, long int *result) override;
};
class X11EventFilterContainer : public QObject
{
Q_OBJECT
public:
explicit X11EventFilterContainer(X11EventFilter *filter);
X11EventFilter *filter() const;
private:
X11EventFilter *m_filter;
};
class KWIN_EXPORT Application : public QApplication
{
Q_OBJECT
@ -96,6 +110,10 @@ public:
void setupCommandLine(QCommandLineParser *parser);
void processCommandLine(QCommandLineParser *parser);
void registerEventFilter(X11EventFilter *filter);
void unregisterEventFilter(X11EventFilter *filter);
bool dispatchEvent(xcb_generic_event_t *event);
xcb_timestamp_t x11Time() const {
return m_x11Time;
}
@ -255,6 +273,8 @@ protected:
static int crashes;
private:
QList<QPointer<X11EventFilterContainer>> m_eventFilters;
QList<QPointer<X11EventFilterContainer>> m_genericEventFilters;
QScopedPointer<XcbEventFilter> m_eventFilter;
bool m_configLock;
KSharedConfigPtr m_config;

View file

@ -194,6 +194,7 @@ void ApplicationX11::lostSelection()
destroyWorkspace();
// Remove windowmanager privileges
Xcb::selectInput(rootWindow(), XCB_EVENT_MASK_PROPERTY_CHANGE);
removeNativeX11EventFilter();
quit();
}

View file

@ -56,19 +56,6 @@ class X11Client;
class X11EventFilter;
enum class Predicate;
class X11EventFilterContainer : public QObject
{
Q_OBJECT
public:
explicit X11EventFilterContainer(X11EventFilter *filter);
X11EventFilter *filter() const;
private:
X11EventFilter *m_filter;
};
class KWIN_EXPORT Workspace : public QObject
{
Q_OBJECT
@ -384,10 +371,6 @@ public:
* @returns Whether we have a Compositor and it is active (Scene created)
*/
bool compositing() const;
void registerEventFilter(X11EventFilter *filter);
void unregisterEventFilter(X11EventFilter *filter);
void markXStackingOrderAsDirty();
void quickTileWindow(QuickTileMode mode);
@ -669,9 +652,6 @@ private:
friend class StackingUpdatesBlocker;
QScopedPointer<KillWindow> m_windowKiller;
QList<QPointer<X11EventFilterContainer>> m_eventFilters;
QList<QPointer<X11EventFilterContainer>> m_genericEventFilters;
QScopedPointer<X11EventFilter> m_movingClientFilter;
QScopedPointer<X11EventFilter> m_syncAlarmFilter;

View file

@ -8,7 +8,7 @@
*/
#include "x11eventfilter.h"
#include <workspace.h>
#include "main.h"
namespace KWin
{
@ -17,7 +17,7 @@ X11EventFilter::X11EventFilter(const QVector<int> &eventTypes)
: m_eventTypes(eventTypes)
, m_extension(0)
{
Workspace::self()->registerEventFilter(this);
kwinApp()->registerEventFilter(this);
}
@ -29,13 +29,13 @@ X11EventFilter::X11EventFilter(int eventType, int opcode, int genericEventType)
X11EventFilter::X11EventFilter(int eventType, int opcode, const QVector< int > &genericEventTypes)
: m_eventTypes(QVector<int>{eventType}), m_extension(opcode), m_genericEventTypes(genericEventTypes)
{
Workspace::self()->registerEventFilter(this);
kwinApp()->registerEventFilter(this);
}
X11EventFilter::~X11EventFilter()
{
if (auto w = Workspace::self()) {
w->unregisterEventFilter(this);
if (kwinApp()) {
kwinApp()->unregisterEventFilter(this);
}
}