deskflow/src/lib/base/EventQueue.cpp

603 lines
14 KiB
C++
Raw Normal View History

2012-06-10 16:50:54 +00:00
/*
* Deskflow -- mouse and keyboard sharing utility
2016-09-07 14:24:00 +00:00
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2004 Chris Schoeneman
*
2012-06-10 16:50:54 +00:00
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
2012-06-10 16:50:54 +00:00
* This package 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 "base/EventQueue.h"
#include "arch/Arch.h"
#include "base/EventTypes.h"
#include "base/IEventJob.h"
#include "base/Log.h"
#include "base/SimpleEventQueueBuffer.h"
#include "base/Stopwatch.h"
#include "base/XBase.h"
#include "mt/Lock.h"
#include "mt/Mutex.h"
2014-11-11 13:51:47 +00:00
EVENT_TYPE_ACCESSOR(Client)
EVENT_TYPE_ACCESSOR(IStream)
2014-11-11 13:51:47 +00:00
EVENT_TYPE_ACCESSOR(IpcClient)
EVENT_TYPE_ACCESSOR(IpcClientProxy)
EVENT_TYPE_ACCESSOR(IpcServer)
EVENT_TYPE_ACCESSOR(IpcServerProxy)
EVENT_TYPE_ACCESSOR(IDataSocket)
EVENT_TYPE_ACCESSOR(IListenSocket)
EVENT_TYPE_ACCESSOR(ISocket)
2014-11-11 13:51:47 +00:00
EVENT_TYPE_ACCESSOR(OSXScreen)
EVENT_TYPE_ACCESSOR(ClientListener)
EVENT_TYPE_ACCESSOR(ClientProxy)
EVENT_TYPE_ACCESSOR(ClientProxyUnknown)
EVENT_TYPE_ACCESSOR(Server)
EVENT_TYPE_ACCESSOR(ServerApp)
EVENT_TYPE_ACCESSOR(IKeyState)
EVENT_TYPE_ACCESSOR(IPrimaryScreen)
EVENT_TYPE_ACCESSOR(IScreen)
EVENT_TYPE_ACCESSOR(Clipboard)
2015-06-05 20:33:24 +00:00
EVENT_TYPE_ACCESSOR(File)
Wayland support (port Red Hat `libei` and `libportal` impl) (#7449) * Add libei and libportal * Port libei and libportal code by Peter Hutterer and Olivier Fourdan * Add Peter Hutterer and Olivier Fourdan to important devs list * Improve error handling for libei and libportal builds * Checkout libportal tags/0.7.1 * Hack out the gi-docgen clone * Remove new submodules in favor of using ExternalProject_Add * Remove submodule dirs * Use ExternalProject_Add instead of submodules * Fixed namespace * Hack to work around type libportal causing type conflicts * Add log helper functions * Use original log functions * Switch to FetchContent, use libportal a1530a9 (unreleased) and use camelCase member names for consistency * Restore a few events (much more work required) * Add TODOs for supporting multiple lib versions * Revert "Switch to FetchContent, use libportal a1530a9 (unreleased) and use camelCase member names for consistency" This reverts commit 610cebb5b6a08282eee68f4424fcdbe9eaab4bf9. * Simplify cmake config by removing builds for libei and libportal (will do this in `install_deps.py` instead) * Remove submodules * Remove .gitmodules * Use meson to build subprojects * Update copyright with Peter Hutterer's guidance * Use meson for installing deps * Fixed typo in tag name * Remove submodules * Remove old submodules * Fixed libei name * Defaults for pugixml and gtest depending on whether source exists in subprojects * Ignore some subproject dirs * Make deps OS-specific * Move python deps to pyproject * Only compile and install on Linux with Meson * Revert "Move python deps to pyproject" This reverts commit 92c8a287b8376a4d166058c85f1d6081f6fdb423. * Add ninja to brewfile * Add python3-attr * Restore original coverage config * Add ninja for meson * Include meson in same try-except * Fixed ninja dep name * Move libs to correct oS * Fixed include for wintoast * Disable docs for libportal * More options for libei and libportal * Fixed option for libei * Use ninja directly to install * Revert "Use ninja directly to install" This reverts commit c926d78ba483406a55acd10fb157c39e13f90b71. * Meson install verbose * Prints stdout/stderr * Remove `from None` * Remove submodules that somehow crept back in?! * Prepend sudo if exists * Add libei deps for all distros * Fixed Fedora package name * Add more deps for other distros * Add more libs (including pugixml) * Fix lib name * Drop -u from pacman * Add vala to rhel * Make libportal optional * Make portal link optional * Remove example code * Always use system pugixml * Disable interactive apt through install_deps.py * Revert "Disable interactive apt through install_deps.py" This reverts commit 5bbc8fd689182447c79b81db16c961b98361a292. * Set DEBIAN_FRONTEND in workflows * Set DEBIAN_FRONTEND in CodeQL workflow * Add gtest dep * Add bundled libei dep * Add libei dep to Arch * Use `googletest` on openSUSE * Add gmock dep * Remove gtest dep from openSUSE * Add libei on Fedora * Bundle libei for older Linux distros * Disable libei dep for RPM * Also bundle symlink to .so * Use ${CMAKE_INSTALL_LIBDIR} * Rename libei to fix openSUSE * List installed files * Add libei-devel to openSUSE * Add googletest-devel to openSUSE * Remove manual deps (probably resolved automatically) * Remove googletest from openSUSE (doesn't provide google mock) * Only add Portal* if libportal found * WIP - Partial work on using old events system :'( * Add deps install commands for subprojects * Solved more compile issues related to events system, threads, etc * Fixed bad config for adding x, ei, portal sources * Remove redundant deps * Remove (another) redundant dep * Fixed pacman command * Add Ubuntu and Linux Mint libei deps * Fixed Ubuntu and Linux Mint libei deps aliases * Only iterate subprojects if not None * Add rhel, rocky, and alma for libei * Make rhel-like deps same as fedora again * Build libportal on rhel-like * Re-enable meson rhel-like for libportal * Remove dbus-python * Make libportal optional (for rhel-like) * Handle ei event queue results * Re-introduce libportal * Print libei and libportal versions * Add ei/portal args and client screen * Switch --use args to --no * Don't build libei/libportal on older distros as it's pointless * Make libei and libportal optional * Add Debian 13 runner * Make some packages optional * Remove subprojects * Improve comment * Add comment for libportal * Improve comment * Add Debian 13 runner * Make optional... optional * Change continuation stripper to remove newline and continuation char * Make command strip more uniform * Fixed help var syntax * Fixed libei linking * Ensure `kHelpNoWayland` is always defined * Improve help message * Fixed Debian 13 runner name * Include sstream and use const var * Update ChangeLog * Remove Wayland block * Return new timer * Make tray icon logging verbose * Fixed arg parser for wayland args * Fixed init of EI screen * Fixed lint issues * Update README to indicate Wayland support in GNOME 46 * Add missing word * Fixed comment positions * Automate CI env * Tone down debug log messages * Add missing comma * Remove redundant log line
2024-08-30 14:53:25 +00:00
EVENT_TYPE_ACCESSOR(Ei)
2012-06-10 16:50:54 +00:00
// interrupt handler. this just adds a quit event to the queue.
static void interrupt(Arch::ESignal, void *data)
{
EventQueue *events = static_cast<EventQueue *>(data);
events->addEvent(Event(Event::kQuit));
2012-06-10 16:50:54 +00:00
}
//
2014-11-11 13:51:47 +00:00
// EventQueue
2012-06-10 16:50:54 +00:00
//
EventQueue::EventQueue()
: m_systemTarget(0),
m_nextType(Event::kLast),
m_typesForClient(NULL),
m_typesForIStream(NULL),
m_typesForIpcClient(NULL),
m_typesForIpcClientProxy(NULL),
m_typesForIpcServer(NULL),
m_typesForIpcServerProxy(NULL),
m_typesForIDataSocket(NULL),
m_typesForIListenSocket(NULL),
m_typesForISocket(NULL),
m_typesForOSXScreen(NULL),
m_typesForClientListener(NULL),
m_typesForClientProxy(NULL),
m_typesForClientProxyUnknown(NULL),
m_typesForServer(NULL),
m_typesForServerApp(NULL),
m_typesForIKeyState(NULL),
m_typesForIPrimaryScreen(NULL),
m_typesForIScreen(NULL),
m_typesForClipboard(NULL),
m_typesForFile(NULL),
Wayland support (port Red Hat `libei` and `libportal` impl) (#7449) * Add libei and libportal * Port libei and libportal code by Peter Hutterer and Olivier Fourdan * Add Peter Hutterer and Olivier Fourdan to important devs list * Improve error handling for libei and libportal builds * Checkout libportal tags/0.7.1 * Hack out the gi-docgen clone * Remove new submodules in favor of using ExternalProject_Add * Remove submodule dirs * Use ExternalProject_Add instead of submodules * Fixed namespace * Hack to work around type libportal causing type conflicts * Add log helper functions * Use original log functions * Switch to FetchContent, use libportal a1530a9 (unreleased) and use camelCase member names for consistency * Restore a few events (much more work required) * Add TODOs for supporting multiple lib versions * Revert "Switch to FetchContent, use libportal a1530a9 (unreleased) and use camelCase member names for consistency" This reverts commit 610cebb5b6a08282eee68f4424fcdbe9eaab4bf9. * Simplify cmake config by removing builds for libei and libportal (will do this in `install_deps.py` instead) * Remove submodules * Remove .gitmodules * Use meson to build subprojects * Update copyright with Peter Hutterer's guidance * Use meson for installing deps * Fixed typo in tag name * Remove submodules * Remove old submodules * Fixed libei name * Defaults for pugixml and gtest depending on whether source exists in subprojects * Ignore some subproject dirs * Make deps OS-specific * Move python deps to pyproject * Only compile and install on Linux with Meson * Revert "Move python deps to pyproject" This reverts commit 92c8a287b8376a4d166058c85f1d6081f6fdb423. * Add ninja to brewfile * Add python3-attr * Restore original coverage config * Add ninja for meson * Include meson in same try-except * Fixed ninja dep name * Move libs to correct oS * Fixed include for wintoast * Disable docs for libportal * More options for libei and libportal * Fixed option for libei * Use ninja directly to install * Revert "Use ninja directly to install" This reverts commit c926d78ba483406a55acd10fb157c39e13f90b71. * Meson install verbose * Prints stdout/stderr * Remove `from None` * Remove submodules that somehow crept back in?! * Prepend sudo if exists * Add libei deps for all distros * Fixed Fedora package name * Add more deps for other distros * Add more libs (including pugixml) * Fix lib name * Drop -u from pacman * Add vala to rhel * Make libportal optional * Make portal link optional * Remove example code * Always use system pugixml * Disable interactive apt through install_deps.py * Revert "Disable interactive apt through install_deps.py" This reverts commit 5bbc8fd689182447c79b81db16c961b98361a292. * Set DEBIAN_FRONTEND in workflows * Set DEBIAN_FRONTEND in CodeQL workflow * Add gtest dep * Add bundled libei dep * Add libei dep to Arch * Use `googletest` on openSUSE * Add gmock dep * Remove gtest dep from openSUSE * Add libei on Fedora * Bundle libei for older Linux distros * Disable libei dep for RPM * Also bundle symlink to .so * Use ${CMAKE_INSTALL_LIBDIR} * Rename libei to fix openSUSE * List installed files * Add libei-devel to openSUSE * Add googletest-devel to openSUSE * Remove manual deps (probably resolved automatically) * Remove googletest from openSUSE (doesn't provide google mock) * Only add Portal* if libportal found * WIP - Partial work on using old events system :'( * Add deps install commands for subprojects * Solved more compile issues related to events system, threads, etc * Fixed bad config for adding x, ei, portal sources * Remove redundant deps * Remove (another) redundant dep * Fixed pacman command * Add Ubuntu and Linux Mint libei deps * Fixed Ubuntu and Linux Mint libei deps aliases * Only iterate subprojects if not None * Add rhel, rocky, and alma for libei * Make rhel-like deps same as fedora again * Build libportal on rhel-like * Re-enable meson rhel-like for libportal * Remove dbus-python * Make libportal optional (for rhel-like) * Handle ei event queue results * Re-introduce libportal * Print libei and libportal versions * Add ei/portal args and client screen * Switch --use args to --no * Don't build libei/libportal on older distros as it's pointless * Make libei and libportal optional * Add Debian 13 runner * Make some packages optional * Remove subprojects * Improve comment * Add comment for libportal * Improve comment * Add Debian 13 runner * Make optional... optional * Change continuation stripper to remove newline and continuation char * Make command strip more uniform * Fixed help var syntax * Fixed libei linking * Ensure `kHelpNoWayland` is always defined * Improve help message * Fixed Debian 13 runner name * Include sstream and use const var * Update ChangeLog * Remove Wayland block * Return new timer * Make tray icon logging verbose * Fixed arg parser for wayland args * Fixed init of EI screen * Fixed lint issues * Update README to indicate Wayland support in GNOME 46 * Add missing word * Fixed comment positions * Automate CI env * Tone down debug log messages * Add missing comma * Remove redundant log line
2024-08-30 14:53:25 +00:00
m_typesForEi(NULL),
m_readyMutex(new Mutex),
m_readyCondVar(new CondVar<bool>(m_readyMutex, false))
{
m_mutex = ARCH->newMutex();
ARCH->setSignalHandler(Arch::kINTERRUPT, &interrupt, this);
ARCH->setSignalHandler(Arch::kTERMINATE, &interrupt, this);
m_buffer = new SimpleEventQueueBuffer;
}
EventQueue::~EventQueue()
{
delete m_buffer;
delete m_readyCondVar;
delete m_readyMutex;
ARCH->setSignalHandler(Arch::kINTERRUPT, NULL, NULL);
ARCH->setSignalHandler(Arch::kTERMINATE, NULL, NULL);
ARCH->closeMutex(m_mutex);
}
void EventQueue::loop()
{
m_buffer->init();
{
Lock lock(m_readyMutex);
*m_readyCondVar = true;
m_readyCondVar->signal();
}
LOG((CLOG_DEBUG "event queue is ready"));
while (!m_pending.empty()) {
LOG((CLOG_DEBUG "add pending events to buffer"));
Event &event = m_pending.front();
addEventToBuffer(event);
m_pending.pop();
}
Event event;
getEvent(event);
while (event.getType() != Event::kQuit) {
dispatchEvent(event);
Event::deleteData(event);
getEvent(event);
}
}
Event::Type EventQueue::registerTypeOnce(Event::Type &type, const char *name)
{
ArchMutexLock lock(m_mutex);
if (type == Event::kUnknown) {
m_typeMap.insert(std::make_pair(m_nextType, name));
m_nameMap.insert(std::make_pair(name, m_nextType));
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
type = m_nextType++;
}
return type;
2012-06-10 16:50:54 +00:00
}
const char *EventQueue::getTypeName(Event::Type type)
{
switch (type) {
case Event::kUnknown:
return "nil";
2012-06-10 16:50:54 +00:00
case Event::kQuit:
return "quit";
case Event::kSystem:
return "system";
case Event::kTimer:
return "timer";
2012-06-10 16:50:54 +00:00
default:
TypeMap::const_iterator i = m_typeMap.find(type);
if (i == m_typeMap.end()) {
return "<unknown>";
} else {
return i->second;
}
}
2012-06-10 16:50:54 +00:00
}
void EventQueue::adoptBuffer(IEventQueueBuffer *buffer)
{
ArchMutexLock lock(m_mutex);
LOG((CLOG_DEBUG "adopting new buffer"));
2012-06-10 16:50:54 +00:00
if (m_events.size() != 0) {
// this can come as a nasty surprise to programmers expecting
// their events to be raised, only to have them deleted.
LOG((CLOG_DEBUG "discarding %d event(s)", m_events.size()));
}
2012-06-10 16:50:54 +00:00
// discard old buffer and old events
delete m_buffer;
for (EventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) {
Event::deleteData(i->second);
}
m_events.clear();
m_oldEventIDs.clear();
// use new buffer
m_buffer = buffer;
if (m_buffer == NULL) {
m_buffer = new SimpleEventQueueBuffer;
}
2012-06-10 16:50:54 +00:00
}
bool EventQueue::getEvent(Event &event, double timeout)
{
Stopwatch timer(true);
retry:
// if no events are waiting then handle timers and then wait
while (m_buffer->isEmpty()) {
// handle timers first
if (hasTimerExpired(event)) {
return true;
}
// get time remaining in timeout
double timeLeft = timeout - timer.getTime();
if (timeout >= 0.0 && timeLeft <= 0.0) {
return false;
}
// get time until next timer expires. if there is a timer
// and it'll expire before the client's timeout then use
// that duration for our timeout instead.
double timerTimeout = getNextTimerTimeout();
if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
timeLeft = timerTimeout;
}
// wait for an event
m_buffer->waitForEvent(timeLeft);
}
// get the event
UInt32 dataID;
IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
switch (type) {
case IEventQueueBuffer::kNone:
if (timeout < 0.0 || timeout <= timer.getTime()) {
// don't want to fail if client isn't expecting that
// so if getEvent() fails with an infinite timeout
// then just try getting another event.
goto retry;
}
return false;
2012-06-10 16:50:54 +00:00
case IEventQueueBuffer::kSystem:
return true;
2012-06-10 16:50:54 +00:00
case IEventQueueBuffer::kUser: {
ArchMutexLock lock(m_mutex);
event = removeEvent(dataID);
return true;
}
2012-06-10 16:50:54 +00:00
default:
assert(0 && "invalid event type");
return false;
}
2012-06-10 16:50:54 +00:00
}
bool EventQueue::dispatchEvent(const Event &event)
{
void *target = event.getTarget();
IEventJob *job = getHandler(event.getType(), target);
if (job == NULL) {
job = getHandler(Event::kUnknown, target);
}
if (job != NULL) {
job->run(event);
return true;
}
return false;
}
void EventQueue::addEvent(const Event &event)
{
// discard bogus event types
switch (event.getType()) {
case Event::kUnknown:
case Event::kSystem:
case Event::kTimer:
return;
default:
break;
}
if ((event.getFlags() & Event::kDeliverImmediately) != 0) {
dispatchEvent(event);
Event::deleteData(event);
} else if (!(*m_readyCondVar)) {
m_pending.push(event);
} else {
addEventToBuffer(event);
}
}
void EventQueue::addEventToBuffer(const Event &event)
{
ArchMutexLock lock(m_mutex);
// store the event's data locally
UInt32 eventID = saveEvent(event);
// add it
if (!m_buffer->addEvent(eventID)) {
// failed to send event
removeEvent(eventID);
Event::deleteData(event);
}
}
EventQueueTimer *EventQueue::newTimer(double duration, void *target)
{
assert(duration > 0.0);
EventQueueTimer *timer = m_buffer->newTimer(duration, false);
if (target == NULL) {
target = timer;
}
ArchMutexLock lock(m_mutex);
m_timers.insert(timer);
// initial duration is requested duration plus whatever's on
// the clock currently because the latter will be subtracted
// the next time we check for timers.
m_timerQueue.push(Timer(timer, duration, duration + m_time.getTime(), target, false));
return timer;
}
EventQueueTimer *EventQueue::newOneShotTimer(double duration, void *target)
{
assert(duration > 0.0);
EventQueueTimer *timer = m_buffer->newTimer(duration, true);
if (target == NULL) {
target = timer;
}
ArchMutexLock lock(m_mutex);
m_timers.insert(timer);
// initial duration is requested duration plus whatever's on
// the clock currently because the latter will be subtracted
// the next time we check for timers.
m_timerQueue.push(Timer(timer, duration, duration + m_time.getTime(), target, true));
return timer;
}
void EventQueue::deleteTimer(EventQueueTimer *timer)
{
ArchMutexLock lock(m_mutex);
for (TimerQueue::iterator index = m_timerQueue.begin(); index != m_timerQueue.end(); ++index) {
if (index->getTimer() == timer) {
m_timerQueue.erase(index);
break;
}
}
Timers::iterator index = m_timers.find(timer);
if (index != m_timers.end()) {
m_timers.erase(index);
}
m_buffer->deleteTimer(timer);
}
void EventQueue::adoptHandler(Event::Type type, void *target, IEventJob *handler)
{
ArchMutexLock lock(m_mutex);
IEventJob *&job = m_handlers[target][type];
delete job;
job = handler;
}
void EventQueue::removeHandler(Event::Type type, void *target)
{
IEventJob *handler = NULL;
{
ArchMutexLock lock(m_mutex);
HandlerTable::iterator index = m_handlers.find(target);
if (index != m_handlers.end()) {
TypeHandlerTable &typeHandlers = index->second;
TypeHandlerTable::iterator index2 = typeHandlers.find(type);
if (index2 != typeHandlers.end()) {
handler = index2->second;
typeHandlers.erase(index2);
}
}
}
delete handler;
2012-06-10 16:50:54 +00:00
}
void EventQueue::removeHandlers(void *target)
{
std::vector<IEventJob *> handlers;
{
ArchMutexLock lock(m_mutex);
HandlerTable::iterator index = m_handlers.find(target);
if (index != m_handlers.end()) {
// copy to handlers array and clear table for target
TypeHandlerTable &typeHandlers = index->second;
for (TypeHandlerTable::iterator index2 = typeHandlers.begin(); index2 != typeHandlers.end(); ++index2) {
handlers.push_back(index2->second);
}
typeHandlers.clear();
}
}
// delete handlers
for (std::vector<IEventJob *>::iterator index = handlers.begin(); index != handlers.end(); ++index) {
delete *index;
}
}
bool EventQueue::isEmpty() const
{
return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0);
}
IEventJob *EventQueue::getHandler(Event::Type type, void *target) const
{
ArchMutexLock lock(m_mutex);
HandlerTable::const_iterator index = m_handlers.find(target);
if (index != m_handlers.end()) {
const TypeHandlerTable &typeHandlers = index->second;
TypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
if (index2 != typeHandlers.end()) {
return index2->second;
}
}
return NULL;
}
UInt32 EventQueue::saveEvent(const Event &event)
{
// choose id
UInt32 id;
if (!m_oldEventIDs.empty()) {
// reuse an id
id = m_oldEventIDs.back();
m_oldEventIDs.pop_back();
} else {
// make a new id
id = static_cast<UInt32>(m_events.size());
}
// save data
m_events[id] = event;
return id;
}
Event EventQueue::removeEvent(UInt32 eventID)
{
// look up id
EventTable::iterator index = m_events.find(eventID);
if (index == m_events.end()) {
return Event();
}
// get data
Event event = index->second;
m_events.erase(index);
// save old id for reuse
m_oldEventIDs.push_back(eventID);
return event;
}
bool EventQueue::hasTimerExpired(Event &event)
{
// return true if there's a timer in the timer priority queue that
// has expired. if returning true then fill in event appropriately
// and reset and reinsert the timer.
if (m_timerQueue.empty()) {
return false;
}
2012-06-10 16:50:54 +00:00
// get time elapsed since last check
const double time = m_time.getTime();
m_time.reset();
2012-06-10 16:50:54 +00:00
// countdown elapsed time
for (TimerQueue::iterator index = m_timerQueue.begin(); index != m_timerQueue.end(); ++index) {
(*index) -= time;
}
2012-06-10 16:50:54 +00:00
// done if no timers are expired
if (m_timerQueue.top() > 0.0) {
return false;
}
2012-06-10 16:50:54 +00:00
// remove timer from queue
Timer timer = m_timerQueue.top();
m_timerQueue.pop();
2012-06-10 16:50:54 +00:00
// prepare event and reset the timer's clock
timer.fillEvent(m_timerEvent);
event = Event(Event::kTimer, timer.getTarget(), &m_timerEvent);
timer.reset();
2012-06-10 16:50:54 +00:00
// reinsert timer into queue if it's not a one-shot
if (!timer.isOneShot()) {
m_timerQueue.push(timer);
}
2012-06-10 16:50:54 +00:00
return true;
2012-06-10 16:50:54 +00:00
}
double EventQueue::getNextTimerTimeout() const
{
// return -1 if no timers, 0 if the top timer has expired, otherwise
// the time until the top timer in the timer priority queue will
// expire.
if (m_timerQueue.empty()) {
return -1.0;
}
if (m_timerQueue.top() <= 0.0) {
return 0.0;
}
return m_timerQueue.top();
2012-06-10 16:50:54 +00:00
}
Event::Type EventQueue::getRegisteredType(const std::string &name) const
{
NameMap::const_iterator found = m_nameMap.find(name);
if (found != m_nameMap.end())
return found->second;
2012-06-10 16:50:54 +00:00
return Event::kUnknown;
2012-06-10 16:50:54 +00:00
}
void *EventQueue::getSystemTarget()
{
// any unique arbitrary pointer will do
return &m_systemTarget;
}
2012-06-10 16:50:54 +00:00
void EventQueue::waitForReady() const
{
double timeout = ARCH->time() + 10;
Lock lock(m_readyMutex);
while (!m_readyCondVar->wait()) {
if (ARCH->time() > timeout) {
throw std::runtime_error("event queue is not ready within 5 sec");
}
}
}
2012-06-10 16:50:54 +00:00
//
2014-11-11 13:51:47 +00:00
// EventQueue::Timer
2012-06-10 16:50:54 +00:00
//
EventQueue::Timer::Timer(EventQueueTimer *timer, double timeout, double initialTime, void *target, bool oneShot)
: m_timer(timer),
m_timeout(timeout),
m_target(target),
m_oneShot(oneShot),
m_time(initialTime)
{
assert(m_timeout > 0.0);
2012-06-10 16:50:54 +00:00
}
EventQueue::Timer::~Timer()
{
// do nothing
2012-06-10 16:50:54 +00:00
}
void EventQueue::Timer::reset()
{
m_time = m_timeout;
}
2012-06-10 16:50:54 +00:00
EventQueue::Timer &EventQueue::Timer::operator-=(double dt)
{
m_time -= dt;
return *this;
2012-06-10 16:50:54 +00:00
}
EventQueue::Timer::operator double() const
{
return m_time;
}
2012-06-10 16:50:54 +00:00
bool EventQueue::Timer::isOneShot() const
{
return m_oneShot;
}
2012-06-10 16:50:54 +00:00
EventQueueTimer *EventQueue::Timer::getTimer() const
{
return m_timer;
}
2012-06-10 16:50:54 +00:00
void *EventQueue::Timer::getTarget() const
{
return m_target;
}
2012-06-10 16:50:54 +00:00
void EventQueue::Timer::fillEvent(TimerEvent &event) const
{
event.m_timer = m_timer;
event.m_count = 0;
if (m_time <= 0.0) {
event.m_count = static_cast<UInt32>((m_timeout - m_time) / m_timeout);
}
2012-06-10 16:50:54 +00:00
}
bool EventQueue::Timer::operator<(const Timer &t) const
{
return m_time < t.m_time;
2012-06-10 16:50:54 +00:00
}