diff --git a/events.cpp b/events.cpp index f1f497e165..b2117489aa 100644 --- a/events.cpp +++ b/events.cpp @@ -165,18 +165,34 @@ QVector s_xcbEerrors({ void Workspace::registerEventFilter(X11EventFilter *filter) { - if (filter->isGenericEvent()) - m_genericEventFilters.append(filter); - else - m_eventFilters.append(filter); + if (filter->isGenericEvent()) { + m_genericEventFilters.append(new X11EventFilterContainer(filter)); + } else { + m_eventFilters.append(new X11EventFilterContainer(filter)); + } +} + +static X11EventFilterContainer *takeEventFilter(X11EventFilter *eventFilter, + QList> &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) { - if (filter->isGenericEvent()) - m_genericEventFilters.removeOne(filter); - else - m_eventFilters.removeOne(filter); + X11EventFilterContainer *container = nullptr; + if (filter->isGenericEvent()) { + container = takeEventFilter(filter, m_genericEventFilters); + } else { + container = takeEventFilter(filter, m_eventFilters); + } + delete container; } @@ -219,13 +235,29 @@ bool Workspace::workspaceEvent(xcb_generic_event_t *e) if (eventType == XCB_GE_GENERIC) { xcb_ge_generic_event_t *ge = reinterpret_cast(e); - foreach (X11EventFilter *filter, m_genericEventFilters) { + // 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 { - foreach (X11EventFilter *filter, m_eventFilters) { + // 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; } diff --git a/workspace.cpp b/workspace.cpp index 6aa71fc486..fbc35a8b9b 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -66,6 +66,16 @@ namespace KWin extern int screen_number; extern bool is_multihead; +X11EventFilterContainer::X11EventFilterContainer(X11EventFilter *filter) + : m_filter(filter) +{ +} + +X11EventFilter *X11EventFilterContainer::filter() const +{ + return m_filter; +} + ColorMapper::ColorMapper(QObject *parent) : QObject(parent) , m_default(kwinApp()->x11DefaultScreen()->default_colormap) diff --git a/workspace.h b/workspace.h index 489d7bae4a..61fb215a85 100644 --- a/workspace.h +++ b/workspace.h @@ -55,6 +55,19 @@ 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 @@ -654,8 +667,8 @@ private: QScopedPointer m_windowKiller; - QList m_eventFilters; - QList m_genericEventFilters; + QList> m_eventFilters; + QList> m_genericEventFilters; QScopedPointer m_movingClientFilter; QScopedPointer m_syncAlarmFilter;