fix: keep event handlers alive during dispatch
This commit is contained in:
parent
39bf4fbe84
commit
6934dbe62b
6 changed files with 101 additions and 10 deletions
|
|
@ -167,12 +167,12 @@ bool EventQueue::getEvent(Event &event, double timeout)
|
|||
bool EventQueue::dispatchEvent(const Event &event)
|
||||
{
|
||||
void *target = event.getTarget();
|
||||
if (const auto *type_handler = getHandler(event.getType(), target); type_handler) {
|
||||
(*type_handler)(event);
|
||||
if (auto typeHandler = getHandler(event.getType(), target); typeHandler.has_value()) {
|
||||
(*typeHandler)(event);
|
||||
return true;
|
||||
}
|
||||
if (const auto *any_handler = getHandler(EventTypes::Unknown, target); any_handler) {
|
||||
(*any_handler)(event);
|
||||
if (auto anyHandler = getHandler(EventTypes::Unknown, target); anyHandler.has_value()) {
|
||||
(*anyHandler)(event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -295,17 +295,17 @@ void EventQueue::removeHandlers(void *target)
|
|||
}
|
||||
}
|
||||
|
||||
const EventQueue::EventHandler *EventQueue::getHandler(EventTypes type, void *target) const
|
||||
std::optional<EventQueue::EventHandler> EventQueue::getHandler(EventTypes type, void *target) const
|
||||
{
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (HandlerTable::const_iterator index = m_handlers.find(target); index != m_handlers.end()) {
|
||||
const TypeHandlerTable &typeHandlers = index->second;
|
||||
TypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
|
||||
if (index2 != typeHandlers.end()) {
|
||||
return &index2->second;
|
||||
return index2->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
uint32_t EventQueue::saveEvent(Event &&event)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
|
|
@ -50,7 +51,7 @@ public:
|
|||
void waitForReady() const override;
|
||||
|
||||
private:
|
||||
const EventHandler *getHandler(EventTypes type, void *target) const;
|
||||
std::optional<EventHandler> getHandler(EventTypes type, void *target) const;
|
||||
uint32_t saveEvent(Event &&event);
|
||||
Event removeEvent(uint32_t eventID);
|
||||
bool hasTimerExpired(Event &event);
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ public:
|
|||
Looks up the dispatcher for the event's target and invokes it.
|
||||
Returns true iff a dispatcher exists for the target.
|
||||
|
||||
The caller must ensure that the target of the event is not removed by removeHandler() or
|
||||
removeHandlers().
|
||||
The handler may unregister itself while running. The event target object must remain alive until
|
||||
the handler starts.
|
||||
*/
|
||||
virtual bool dispatchEvent(const Event &event) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,3 +37,10 @@ create_test(
|
|||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/base"
|
||||
)
|
||||
|
||||
create_test(
|
||||
NAME EventQueueTests
|
||||
DEPENDS base
|
||||
LIBS arch mt
|
||||
SOURCE EventQueueTests.cpp
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/base"
|
||||
)
|
||||
|
|
|
|||
58
src/unittests/base/EventQueueTests.cpp
Normal file
58
src/unittests/base/EventQueueTests.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "EventQueueTests.h"
|
||||
|
||||
#include "base/EventQueue.h"
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <memory>
|
||||
|
||||
void EventQueueTests::initTestCase()
|
||||
{
|
||||
m_arch.init();
|
||||
}
|
||||
|
||||
void EventQueueTests::dispatchEvent_noHandler_returnsFalse()
|
||||
{
|
||||
EventQueue events;
|
||||
|
||||
QVERIFY(!events.dispatchEvent(Event(EventTypes::ClientDisconnected, this)));
|
||||
}
|
||||
|
||||
void EventQueueTests::dispatchEvent_noTypeHandler_dispatchesUnknownHandler()
|
||||
{
|
||||
EventQueue events;
|
||||
bool fallbackCalled = false;
|
||||
events.addHandler(EventTypes::Unknown, this, [&fallbackCalled](const Event &) { fallbackCalled = true; });
|
||||
|
||||
QVERIFY(events.dispatchEvent(Event(EventTypes::ClientDisconnected, this)));
|
||||
QVERIFY(fallbackCalled);
|
||||
}
|
||||
|
||||
void EventQueueTests::dispatchEvent_handlerRemovesItself_keepsHandlerAliveUntilReturn()
|
||||
{
|
||||
EventQueue events;
|
||||
auto handlerLifetime = std::make_shared<int>(1);
|
||||
std::weak_ptr<int> handlerLifetimeObserver = handlerLifetime;
|
||||
bool handlerAliveAfterRemoval = false;
|
||||
|
||||
events.addHandler(
|
||||
EventTypes::ClientDisconnected, this,
|
||||
[this, &events, &handlerLifetimeObserver, &handlerAliveAfterRemoval, handlerLifetime](const Event &) {
|
||||
events.removeHandler(EventTypes::ClientDisconnected, this);
|
||||
handlerAliveAfterRemoval = handlerLifetime != nullptr && !handlerLifetimeObserver.expired();
|
||||
}
|
||||
);
|
||||
handlerLifetime.reset();
|
||||
|
||||
QVERIFY(events.dispatchEvent(Event(EventTypes::ClientDisconnected, this)));
|
||||
QVERIFY(handlerAliveAfterRemoval);
|
||||
QVERIFY(handlerLifetimeObserver.expired());
|
||||
}
|
||||
|
||||
QTEST_MAIN(EventQueueTests)
|
||||
25
src/unittests/base/EventQueueTests.h
Normal file
25
src/unittests/base/EventQueueTests.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/Arch.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class EventQueueTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void dispatchEvent_noHandler_returnsFalse();
|
||||
void dispatchEvent_noTypeHandler_dispatchesUnknownHandler();
|
||||
void dispatchEvent_handlerRemovesItself_keepsHandlerAliveUntilReturn();
|
||||
|
||||
private:
|
||||
Arch m_arch;
|
||||
};
|
||||
Loading…
Reference in a new issue