mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-30 03:15:38 -05:00
fix event listeners not being removed from the right queue
This commit is contained in:
parent
6d77f841c9
commit
6ba91482a6
3 changed files with 34 additions and 29 deletions
|
@ -28,16 +28,13 @@ namespace geode {
|
|||
EventListenerPool() = default;
|
||||
EventListenerPool(EventListenerPool const&) = delete;
|
||||
EventListenerPool(EventListenerPool&&) = delete;
|
||||
|
||||
static EventListenerPool* getDefault();
|
||||
};
|
||||
|
||||
class GEODE_DLL DefaultEventListenerPool : public EventListenerPool {
|
||||
protected:
|
||||
std::atomic_size_t m_locked = 0;
|
||||
std::vector<EventListenerProtocol*> m_listeners;
|
||||
std::unordered_set<EventListenerProtocol*> m_toAdd;
|
||||
std::unordered_set<EventListenerProtocol*> m_toRemove;
|
||||
std::vector<EventListenerProtocol*> m_toAdd;
|
||||
|
||||
public:
|
||||
bool add(EventListenerProtocol* listener) override;
|
||||
|
@ -47,7 +44,11 @@ namespace geode {
|
|||
static DefaultEventListenerPool* get();
|
||||
};
|
||||
|
||||
struct GEODE_DLL EventListenerProtocol {
|
||||
class GEODE_DLL EventListenerProtocol {
|
||||
private:
|
||||
EventListenerPool* m_pool = nullptr;
|
||||
|
||||
public:
|
||||
bool enable();
|
||||
void disable();
|
||||
|
||||
|
@ -78,7 +79,7 @@ namespace geode {
|
|||
}
|
||||
|
||||
EventListenerPool* getPool() const {
|
||||
return EventListenerPool::getDefault();
|
||||
return DefaultEventListenerPool::get();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.hpp"
|
||||
#include "../utils/Result.hpp"
|
||||
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
#include <Geode/utils/ranges.hpp>
|
||||
|
|
|
@ -6,7 +6,7 @@ using namespace geode::prelude;
|
|||
|
||||
bool DefaultEventListenerPool::add(EventListenerProtocol* listener) {
|
||||
if (m_locked) {
|
||||
m_toAdd.insert(listener);
|
||||
m_toAdd.push_back(listener);
|
||||
}
|
||||
else {
|
||||
m_listeners.push_back(listener);
|
||||
|
@ -15,35 +15,31 @@ bool DefaultEventListenerPool::add(EventListenerProtocol* listener) {
|
|||
}
|
||||
|
||||
void DefaultEventListenerPool::remove(EventListenerProtocol* listener) {
|
||||
if (m_locked) {
|
||||
m_toRemove.insert(listener);
|
||||
}
|
||||
else {
|
||||
ranges::remove(m_listeners, listener);
|
||||
for (size_t i = 0; i < m_listeners.size(); i++) {
|
||||
if (m_listeners[i] == listener) {
|
||||
m_listeners[i] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultEventListenerPool::handle(Event* event) {
|
||||
m_locked += 1;
|
||||
for (auto h : m_listeners) {
|
||||
// if an event listener gets destroyed in the middle of this loop, we
|
||||
// need to handle that
|
||||
if (m_toRemove.contains(h)) continue;
|
||||
if (h->handle(event) == ListenerResult::Stop) {
|
||||
// if an event listener gets destroyed in the middle of this loop, it
|
||||
// gets set to null
|
||||
if (h && h->handle(event) == ListenerResult::Stop) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_locked -= 1;
|
||||
// only clear listeners once nothing is iterating (if there are recursive handle calls)
|
||||
// only mutate listeners once nothing is iterating
|
||||
// (if there are recursive handle calls)
|
||||
if (m_locked == 0) {
|
||||
ranges::remove(m_listeners, nullptr);
|
||||
for (auto listener : m_toAdd) {
|
||||
m_listeners.push_back(listener);
|
||||
}
|
||||
for (auto listener : m_toRemove) {
|
||||
ranges::remove(m_listeners, listener);
|
||||
}
|
||||
m_toAdd.clear();
|
||||
m_toRemove.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,20 +48,27 @@ DefaultEventListenerPool* DefaultEventListenerPool::get() {
|
|||
return inst;
|
||||
}
|
||||
|
||||
EventListenerPool* EventListenerPool::getDefault() {
|
||||
EventListenerPool* EventListenerProtocol::getPool() const {
|
||||
return DefaultEventListenerPool::get();
|
||||
}
|
||||
|
||||
EventListenerPool* EventListenerProtocol::getPool() const {
|
||||
return EventListenerPool::getDefault();
|
||||
}
|
||||
|
||||
bool EventListenerProtocol::enable() {
|
||||
return this->getPool()->add(this);
|
||||
// virtual calls from destructors always call the base class so we gotta
|
||||
// store the subclass' pool in a member to be able to access it in disable
|
||||
// this is actually better because now regardless of what getPool() does
|
||||
// we can always be assured that whatever pool it returns this listener
|
||||
// will be removed from that pool and can't be in multiple pools at once
|
||||
if (m_pool || !(m_pool = this->getPool())) {
|
||||
return false;
|
||||
}
|
||||
return m_pool->add(this);
|
||||
}
|
||||
|
||||
void EventListenerProtocol::disable() {
|
||||
this->getPool()->remove(this);
|
||||
if (m_pool) {
|
||||
m_pool->remove(this);
|
||||
m_pool = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
EventListenerProtocol::~EventListenerProtocol() {
|
||||
|
@ -75,7 +78,7 @@ EventListenerProtocol::~EventListenerProtocol() {
|
|||
Event::~Event() {}
|
||||
|
||||
EventListenerPool* Event::getPool() const {
|
||||
return EventListenerPool::getDefault();
|
||||
return DefaultEventListenerPool::get();
|
||||
}
|
||||
|
||||
void Event::postFrom(Mod* m) {
|
||||
|
|
Loading…
Reference in a new issue