mirror of
https://github.com/debauchee/barrier.git
synced 2025-06-17 02:01:41 +02:00
removed trunk; please commit to (and build patches against) release branches instead.
This commit is contained in:
parent
422fd7adf3
commit
e65886857d
757 changed files with 7 additions and 341444 deletions
|
@ -1,529 +0,0 @@
|
|||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
|
||||
*
|
||||
* 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 COPYING that should have accompanied this file.
|
||||
*
|
||||
* 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 "CEventQueue.h"
|
||||
#include "CLog.h"
|
||||
#include "CSimpleEventQueueBuffer.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "IEventJob.h"
|
||||
#include "CArch.h"
|
||||
|
||||
// interrupt handler. this just adds a quit event to the queue.
|
||||
static
|
||||
void
|
||||
interrupt(CArch::ESignal, void*)
|
||||
{
|
||||
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CEventQueue
|
||||
//
|
||||
|
||||
CEventQueue::CEventQueue() :
|
||||
m_nextType(CEvent::kLast)
|
||||
{
|
||||
setInstance(this);
|
||||
m_mutex = ARCH->newMutex();
|
||||
ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
|
||||
ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
|
||||
m_buffer = new CSimpleEventQueueBuffer;
|
||||
}
|
||||
|
||||
CEventQueue::~CEventQueue()
|
||||
{
|
||||
delete m_buffer;
|
||||
ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
|
||||
ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
|
||||
ARCH->closeMutex(m_mutex);
|
||||
setInstance(NULL);
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
CEventQueue::registerType(const char* name)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
m_typeMap.insert(std::make_pair(m_nextType, name));
|
||||
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
|
||||
return m_nextType++;
|
||||
}
|
||||
|
||||
CEvent::Type
|
||||
CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
if (type == CEvent::kUnknown) {
|
||||
m_typeMap.insert(std::make_pair(m_nextType, name));
|
||||
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
|
||||
type = m_nextType++;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
const char*
|
||||
CEventQueue::getTypeName(CEvent::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case CEvent::kUnknown:
|
||||
return "nil";
|
||||
|
||||
case CEvent::kQuit:
|
||||
return "quit";
|
||||
|
||||
case CEvent::kSystem:
|
||||
return "system";
|
||||
|
||||
case CEvent::kTimer:
|
||||
return "timer";
|
||||
|
||||
default:
|
||||
CTypeMap::const_iterator i = m_typeMap.find(type);
|
||||
if (i == m_typeMap.end()) {
|
||||
return "<unknown>";
|
||||
}
|
||||
else {
|
||||
return i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
|
||||
// discard old buffer and old events
|
||||
delete m_buffer;
|
||||
for (CEventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) {
|
||||
CEvent::deleteData(i->second);
|
||||
}
|
||||
m_events.clear();
|
||||
m_oldEventIDs.clear();
|
||||
|
||||
// use new buffer
|
||||
m_buffer = buffer;
|
||||
if (m_buffer == NULL) {
|
||||
m_buffer = new CSimpleEventQueueBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::getEvent(CEvent& event, double timeout)
|
||||
{
|
||||
CStopwatch 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;
|
||||
|
||||
case IEventQueueBuffer::kSystem:
|
||||
return true;
|
||||
|
||||
case IEventQueueBuffer::kUser:
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
event = removeEvent(dataID);
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
assert(0 && "invalid event type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::dispatchEvent(const CEvent& event)
|
||||
{
|
||||
void* target = event.getTarget();
|
||||
IEventJob* job = getHandler(event.getType(), target);
|
||||
if (job == NULL) {
|
||||
job = getHandler(CEvent::kUnknown, target);
|
||||
}
|
||||
if (job != NULL) {
|
||||
job->run(event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::addEvent(const CEvent& event)
|
||||
{
|
||||
// discard bogus event types
|
||||
switch (event.getType()) {
|
||||
case CEvent::kUnknown:
|
||||
case CEvent::kSystem:
|
||||
case CEvent::kTimer:
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((event.getFlags() & CEvent::kDeliverImmediately) != 0) {
|
||||
dispatchEvent(event);
|
||||
CEvent::deleteData(event);
|
||||
}
|
||||
else {
|
||||
CArchMutexLock 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);
|
||||
CEvent::deleteData(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CEventQueue::newTimer(double duration, void* target)
|
||||
{
|
||||
assert(duration > 0.0);
|
||||
|
||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
|
||||
if (target == NULL) {
|
||||
target = timer;
|
||||
}
|
||||
CArchMutexLock 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(CTimer(timer, duration,
|
||||
duration + m_time.getTime(), target, false));
|
||||
return timer;
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CEventQueue::newOneShotTimer(double duration, void* target)
|
||||
{
|
||||
assert(duration > 0.0);
|
||||
|
||||
CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
|
||||
if (target == NULL) {
|
||||
target = timer;
|
||||
}
|
||||
CArchMutexLock 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(CTimer(timer, duration,
|
||||
duration + m_time.getTime(), target, true));
|
||||
return timer;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::deleteTimer(CEventQueueTimer* timer)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
for (CTimerQueue::iterator index = m_timerQueue.begin();
|
||||
index != m_timerQueue.end(); ++index) {
|
||||
if (index->getTimer() == timer) {
|
||||
m_timerQueue.erase(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CTimers::iterator index = m_timers.find(timer);
|
||||
if (index != m_timers.end()) {
|
||||
m_timers.erase(index);
|
||||
}
|
||||
m_buffer->deleteTimer(timer);
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::adoptHandler(CEvent::Type type, void* target, IEventJob* handler)
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
IEventJob*& job = m_handlers[target][type];
|
||||
delete job;
|
||||
job = handler;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::removeHandler(CEvent::Type type, void* target)
|
||||
{
|
||||
IEventJob* handler = NULL;
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
CHandlerTable::iterator index = m_handlers.find(target);
|
||||
if (index != m_handlers.end()) {
|
||||
CTypeHandlerTable& typeHandlers = index->second;
|
||||
CTypeHandlerTable::iterator index2 = typeHandlers.find(type);
|
||||
if (index2 != typeHandlers.end()) {
|
||||
handler = index2->second;
|
||||
typeHandlers.erase(index2);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete handler;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::removeHandlers(void* target)
|
||||
{
|
||||
std::vector<IEventJob*> handlers;
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
CHandlerTable::iterator index = m_handlers.find(target);
|
||||
if (index != m_handlers.end()) {
|
||||
// copy to handlers array and clear table for target
|
||||
CTypeHandlerTable& typeHandlers = index->second;
|
||||
for (CTypeHandlerTable::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
|
||||
CEventQueue::isEmpty() const
|
||||
{
|
||||
return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0);
|
||||
}
|
||||
|
||||
IEventJob*
|
||||
CEventQueue::getHandler(CEvent::Type type, void* target) const
|
||||
{
|
||||
CArchMutexLock lock(m_mutex);
|
||||
CHandlerTable::const_iterator index = m_handlers.find(target);
|
||||
if (index != m_handlers.end()) {
|
||||
const CTypeHandlerTable& typeHandlers = index->second;
|
||||
CTypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
|
||||
if (index2 != typeHandlers.end()) {
|
||||
return index2->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UInt32
|
||||
CEventQueue::saveEvent(const CEvent& 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;
|
||||
}
|
||||
|
||||
CEvent
|
||||
CEventQueue::removeEvent(UInt32 eventID)
|
||||
{
|
||||
// look up id
|
||||
CEventTable::iterator index = m_events.find(eventID);
|
||||
if (index == m_events.end()) {
|
||||
return CEvent();
|
||||
}
|
||||
|
||||
// get data
|
||||
CEvent event = index->second;
|
||||
m_events.erase(index);
|
||||
|
||||
// save old id for reuse
|
||||
m_oldEventIDs.push_back(eventID);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::hasTimerExpired(CEvent& 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;
|
||||
}
|
||||
|
||||
// get time elapsed since last check
|
||||
const double time = m_time.getTime();
|
||||
m_time.reset();
|
||||
|
||||
// countdown elapsed time
|
||||
for (CTimerQueue::iterator index = m_timerQueue.begin();
|
||||
index != m_timerQueue.end(); ++index) {
|
||||
(*index) -= time;
|
||||
}
|
||||
|
||||
// done if no timers are expired
|
||||
if (m_timerQueue.top() > 0.0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove timer from queue
|
||||
CTimer timer = m_timerQueue.top();
|
||||
m_timerQueue.pop();
|
||||
|
||||
// prepare event and reset the timer's clock
|
||||
timer.fillEvent(m_timerEvent);
|
||||
event = CEvent(CEvent::kTimer, timer.getTarget(), &m_timerEvent);
|
||||
timer.reset();
|
||||
|
||||
// reinsert timer into queue if it's not a one-shot
|
||||
if (!timer.isOneShot()) {
|
||||
m_timerQueue.push(timer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double
|
||||
CEventQueue::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();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CEventQueue::CTimer
|
||||
//
|
||||
|
||||
CEventQueue::CTimer::CTimer(CEventQueueTimer* 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);
|
||||
}
|
||||
|
||||
CEventQueue::CTimer::~CTimer()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::CTimer::reset()
|
||||
{
|
||||
m_time = m_timeout;
|
||||
}
|
||||
|
||||
CEventQueue::CTimer&
|
||||
CEventQueue::CTimer::operator-=(double dt)
|
||||
{
|
||||
m_time -= dt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CEventQueue::CTimer::operator double() const
|
||||
{
|
||||
return m_time;
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::CTimer::isOneShot() const
|
||||
{
|
||||
return m_oneShot;
|
||||
}
|
||||
|
||||
CEventQueueTimer*
|
||||
CEventQueue::CTimer::getTimer() const
|
||||
{
|
||||
return m_timer;
|
||||
}
|
||||
|
||||
void*
|
||||
CEventQueue::CTimer::getTarget() const
|
||||
{
|
||||
return m_target;
|
||||
}
|
||||
|
||||
void
|
||||
CEventQueue::CTimer::fillEvent(CTimerEvent& 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);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEventQueue::CTimer::operator<(const CTimer& t) const
|
||||
{
|
||||
return m_time < t.m_time;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue