diff --git a/lib/base/CEventQueue.cpp b/lib/base/CEventQueue.cpp index 9c6d6ca4..8528b0ac 100644 --- a/lib/base/CEventQueue.cpp +++ b/lib/base/CEventQueue.cpp @@ -13,6 +13,7 @@ */ #include "CEventQueue.h" +#include "CSimpleEventQueueBuffer.h" #include "IEventJob.h" #include "CArch.h" @@ -34,20 +35,42 @@ CEventQueue::CEventQueue() setInstance(this); m_mutex = ARCH->newMutex(); ARCH->setInterruptHandler(&interrupt, NULL); + m_buffer = new CSimpleEventQueueBuffer; } CEventQueue::~CEventQueue() { + delete m_buffer; ARCH->setInterruptHandler(NULL, NULL); ARCH->closeMutex(m_mutex); setInstance(NULL); } +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) { // if no events are waiting then handle timers and then wait - if (doIsEmpty()) { + if (m_buffer->isEmpty()) { // handle timers first if (hasTimerExpired(event)) { return true; @@ -62,15 +85,30 @@ CEventQueue::getEvent(CEvent& event, double timeout) } // wait for an event - waitForEvent(timeout); + m_buffer->waitForEvent(timeout); } // if no events are pending then do the timers - if (doIsEmpty()) { + if (m_buffer->isEmpty()) { return hasTimerExpired(event); } - return doGetEvent(event); + UInt32 dataID; + IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID); + switch (type) { + case IEventQueueBuffer::kNone: + return false; + + case IEventQueueBuffer::kSystem: + return true; + + case IEventQueueBuffer::kUser: + { + CArchMutexLock lock(m_mutex); + event = removeEvent(dataID); + return true; + } + } } bool @@ -99,11 +137,13 @@ CEventQueue::addEvent(const CEvent& event) break; } + CArchMutexLock lock(m_mutex); + // store the event's data locally UInt32 eventID = saveEvent(event); // add it - if (!doAddEvent(eventID)) { + if (!m_buffer->addEvent(eventID)) { // failed to send event removeEvent(eventID); CEvent::deleteData(event); @@ -115,7 +155,7 @@ CEventQueue::newTimer(double duration, void* target) { assert(duration > 0.0); - CEventQueueTimer* timer = doNewTimer(duration, false); + CEventQueueTimer* timer = m_buffer->newTimer(duration, false); CArchMutexLock lock(m_mutex); m_timers.insert(timer); m_timerQueue.push(CTimer(timer, duration, target, false)); @@ -127,7 +167,7 @@ CEventQueue::newOneShotTimer(double duration, void* target) { assert(duration > 0.0); - CEventQueueTimer* timer = doNewTimer(duration, true); + CEventQueueTimer* timer = m_buffer->newTimer(duration, true); CArchMutexLock lock(m_mutex); m_timers.insert(timer); m_timerQueue.push(CTimer(timer, duration, target, true)); @@ -137,27 +177,24 @@ CEventQueue::newOneShotTimer(double duration, void* target) 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); + 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; } } - doDeleteTimer(timer); + CTimers::iterator index = m_timers.find(timer); + if (index != m_timers.end()) { + m_timers.erase(index); + } + m_buffer->deleteTimer(timer); } void CEventQueue::adoptHandler(void* target, IEventJob* handler) { - CArchMutexLock lock(m_mutex); doAdoptHandler(CEvent::kUnknown, target, handler); } @@ -165,14 +202,12 @@ void CEventQueue::adoptHandler(CEvent::Type type, void* target, IEventJob* handler) { assert(type != CEvent::kUnknown); - CArchMutexLock lock(m_mutex); doAdoptHandler(type, target, handler); } IEventJob* CEventQueue::orphanHandler(void* target) { - CArchMutexLock lock(m_mutex); return doOrphanHandler(CEvent::kUnknown, target); } @@ -180,7 +215,6 @@ IEventJob* CEventQueue::orphanHandler(CEvent::Type type, void* target) { assert(type != CEvent::kUnknown); - CArchMutexLock lock(m_mutex); return doOrphanHandler(type, target); } @@ -199,6 +233,7 @@ CEventQueue::removeHandler(CEvent::Type type, void* target) void CEventQueue::doAdoptHandler(CEvent::Type type, void* target, IEventJob* handler) { + CArchMutexLock lock(m_mutex); IEventJob*& job = m_handlers[CTypeTarget(type, target)]; delete job; job = handler; @@ -207,6 +242,7 @@ CEventQueue::doAdoptHandler(CEvent::Type type, void* target, IEventJob* handler) IEventJob* CEventQueue::doOrphanHandler(CEvent::Type type, void* target) { + CArchMutexLock lock(m_mutex); CHandlerTable::iterator index = m_handlers.find(CTypeTarget(type, target)); if (index != m_handlers.end()) { IEventJob* handler = index->second; @@ -221,7 +257,7 @@ CEventQueue::doOrphanHandler(CEvent::Type type, void* target) bool CEventQueue::isEmpty() const { - return (doIsEmpty() && getNextTimerTimeout() != 0.0); + return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0); } IEventJob* @@ -243,8 +279,6 @@ CEventQueue::getHandler(CEvent::Type type, void* target) const UInt32 CEventQueue::saveEvent(const CEvent& event) { - CArchMutexLock lock(m_mutex); - // choose id UInt32 id; if (!m_oldEventIDs.empty()) { @@ -265,8 +299,6 @@ CEventQueue::saveEvent(const CEvent& event) CEvent CEventQueue::removeEvent(UInt32 eventID) { - CArchMutexLock lock(m_mutex); - // look up id CEventTable::iterator index = m_events.find(eventID); if (index == m_events.end()) { @@ -286,8 +318,6 @@ CEventQueue::removeEvent(UInt32 eventID) bool CEventQueue::hasTimerExpired(CEvent& event) { - CArchMutexLock lock(m_mutex); - // 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. @@ -330,8 +360,6 @@ CEventQueue::hasTimerExpired(CEvent& event) double CEventQueue::getNextTimerTimeout() const { - CArchMutexLock lock(m_mutex); - // 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. diff --git a/lib/base/CEventQueue.h b/lib/base/CEventQueue.h index 5443c394..514612bb 100644 --- a/lib/base/CEventQueue.h +++ b/lib/base/CEventQueue.h @@ -34,6 +34,7 @@ public: virtual ~CEventQueue(); // IEventQueue overrides + virtual void adoptBuffer(IEventQueueBuffer*); virtual bool getEvent(CEvent& event, double timeout = -1.0); virtual bool dispatchEvent(const CEvent& event); virtual void addEvent(const CEvent& event); @@ -52,80 +53,13 @@ public: virtual bool isEmpty() const; virtual IEventJob* getHandler(CEvent::Type type, void* target) const; -protected: - //! @name manipulators - //@{ - - //! Get the data for a given id - /*! - Takes a saved event id, \p eventID, and returns a \c CEvent. The - event id becomes invalid after this call. The \p eventID must have - been passed to a successful call to \c doAddEvent() and not removed - since. - */ - CEvent removeEvent(UInt32 eventID); - - //! Block waiting for an event - /*! - Wait for an event in the system event queue for up to \p timeout - seconds. - */ - virtual void waitForEvent(double timeout) = 0; - - //! Get the next event - /*! - Remove the next system event (one should be pending) and convert it - to a \c CEvent. The event type should be either \c CEvent::kSystem - if the event was not added by \c doAddEvent() or a type returned by - \c CEvent::registerType() if it was (and not \c CEvent::kTimer). A - non-system event will normally be retrieved by \c removeEvent(), but - the implementation must be able to tell the difference between a - system event and one added by \c doAddEvent(). - */ - virtual bool doGetEvent(CEvent& event) = 0; - - //! Post an event - /*! - Add the given event to the end of the system queue. This is a user - event and \c doGetEvent() must be able to identify it as such. - This method must cause \c waitForEvent() to return at some future - time if it's blocked waiting on an event. - */ - virtual bool doAddEvent(UInt32 dataID) = 0; - - //@} - //! @name accessors - //@{ - - //! Check if system queue is empty - /*! - Return true iff the system queue is empty. - */ - virtual bool doIsEmpty() const = 0; - - //! Create a timer object - /*! - Create and return a timer object. The object is opaque and is - used only by the subclass but it must be a valid object (i.e. - not NULL). - */ - virtual CEventQueueTimer* - doNewTimer(double duration, bool oneShot) const = 0; - - //! Destroy a timer object - /*! - Destroy a timer object previously returned by \c doNewTimer(). - */ - virtual void doDeleteTimer(CEventQueueTimer*) const = 0; - - //@} - private: void doAdoptHandler(CEvent::Type type, void* target, IEventJob* handler); IEventJob* doOrphanHandler(CEvent::Type type, void* target); UInt32 saveEvent(const CEvent& event); + CEvent removeEvent(UInt32 eventID); bool hasTimerExpired(CEvent& event); double getNextTimerTimeout() const; @@ -175,6 +109,8 @@ private: CArchMutex m_mutex; + IEventQueueBuffer* m_buffer; + CEventTable m_events; CEventIDList m_oldEventIDs; diff --git a/lib/base/CSimpleEventQueue.cpp b/lib/base/CSimpleEventQueue.cpp deleted file mode 100644 index 9fc7e616..00000000 --- a/lib/base/CSimpleEventQueue.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2004 Chris Schoeneman - * - * 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. - */ - -#include "CSimpleEventQueue.h" -#include "CArch.h" - -class CEventQueueTimer { }; - -// -// CSimpleEventQueue -// - -CSimpleEventQueue::CSimpleEventQueue() -{ - m_queueMutex = ARCH->newMutex(); - m_queueReadyCond = ARCH->newCondVar(); - m_queueReady = false; -} - -CSimpleEventQueue::~CSimpleEventQueue() -{ - ARCH->closeCondVar(m_queueReadyCond); - ARCH->closeMutex(m_queueMutex); -} - -void -CSimpleEventQueue::waitForEvent(double timeout) -{ - CArchMutexLock lock(m_queueMutex); - while (!m_queueReady) { - ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, -1.0); - } -} - -bool -CSimpleEventQueue::doGetEvent(CEvent& event) -{ - CArchMutexLock lock(m_queueMutex); - if (!m_queueReady) { - return false; - } - event = removeEvent(m_queue.back()); - m_queue.pop_back(); - m_queueReady = !m_queue.empty(); - return true; -} - -bool -CSimpleEventQueue::doAddEvent(UInt32 dataID) -{ - CArchMutexLock lock(m_queueMutex); - m_queue.push_front(dataID); - if (!m_queueReady) { - m_queueReady = true; - ARCH->broadcastCondVar(m_queueReadyCond); - } - return true; -} - -bool -CSimpleEventQueue::doIsEmpty() const -{ - CArchMutexLock lock(m_queueMutex); - return !m_queueReady; -} - -CEventQueueTimer* -CSimpleEventQueue::doNewTimer(double, bool) const -{ - return new CEventQueueTimer; -} - -void -CSimpleEventQueue::doDeleteTimer(CEventQueueTimer* timer) const -{ - delete timer; -} diff --git a/lib/base/CSimpleEventQueue.h b/lib/base/CSimpleEventQueue.h deleted file mode 100644 index 35ad4ecc..00000000 --- a/lib/base/CSimpleEventQueue.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2004 Chris Schoeneman - * - * 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. - */ - -#ifndef CSIMPLEEVENTQUEUE_H -#define CSIMPLEEVENTQUEUE_H - -#include "CEventQueue.h" -#include "IArchMultithread.h" -#include "stddeque.h" - -//! Event queue for added events only -/*! -An event queue that provides no system events, just events added by -addEvent(). -*/ -class CSimpleEventQueue : public CEventQueue { -public: - CSimpleEventQueue(); - virtual ~CSimpleEventQueue(); - - //! @name manipulators - //@{ - - //@} - //! @name accessors - //@{ - - //@} - -protected: - // CEventQueue overrides - virtual void waitForEvent(double timeout); - virtual bool doGetEvent(CEvent& event); - virtual bool doAddEvent(UInt32 dataID); - virtual bool doIsEmpty() const; - virtual CEventQueueTimer* - doNewTimer(double duration, bool oneShot) const; - virtual void doDeleteTimer(CEventQueueTimer*) const; - -private: - typedef std::deque CEventDeque; - - CArchMutex m_queueMutex; - CArchCond m_queueReadyCond; - bool m_queueReady; - CEventDeque m_queue; -}; - -#endif diff --git a/lib/base/IEventQueue.h b/lib/base/IEventQueue.h index 0d144ebf..6e649456 100644 --- a/lib/base/IEventQueue.h +++ b/lib/base/IEventQueue.h @@ -21,9 +21,10 @@ #define EVENTQUEUE IEventQueue::getInstance() class IEventJob; +class IEventQueueBuffer; // Opaque type for timer info. This is defined by subclasses of -// IEventQueue. +// IEventQueueBuffer. class CEventQueueTimer; //! Event queue interface @@ -44,6 +45,13 @@ public: //! @name manipulators //@{ + //! Set the buffer + /*! + Replace the current event queue buffer. Any queued events are + discarded. The queue takes ownership of the buffer. + */ + virtual void adoptBuffer(IEventQueueBuffer*) = 0; + //! Remove event from queue /*! Returns the next event on the queue into \p event. If no event is diff --git a/lib/base/Makefile.am b/lib/base/Makefile.am index f146cb11..9eb2a526 100644 --- a/lib/base/Makefile.am +++ b/lib/base/Makefile.am @@ -15,49 +15,50 @@ NULL = DEPTH = ../.. VDEPTH = ./$(VPATH)/$(DEPTH) -EXTRA_DIST = \ - base.dsp \ +EXTRA_DIST = \ + base.dsp \ $(NULL) -MAINTAINERCLEANFILES = \ - Makefile.in \ +MAINTAINERCLEANFILES = \ + Makefile.in \ $(NULL) noinst_LIBRARIES = libbase.a -libbase_a_SOURCES = \ - CEvent.cpp \ - CEventQueue.cpp \ - CFunctionEventJob.cpp \ - CFunctionJob.cpp \ - CJobList.cpp \ - CLog.cpp \ - CSimpleEventQueue.cpp \ - CStopwatch.cpp \ - CStringUtil.cpp \ - CUnicode.cpp \ - IEventQueue.cpp \ - LogOutputters.cpp \ - XBase.cpp \ - CEvent.h \ - CEventQueue.h \ - CFunctionJob.h \ - CJobList.h \ - CLog.h \ - CPriorityQueue.h \ - CSimpleEventQueue.h \ - CStopwatch.h \ - CString.h \ - CStringUtil.h \ - CUnicode.h \ - IEventQueue.h \ - IJob.h \ - ILogOutputter.h \ - LogOutputters.h \ - TMethodEventJob.h \ - TMethodJob.h \ - XBase.h \ +libbase_a_SOURCES = \ + CEvent.cpp \ + CEventQueue.cpp \ + CFunctionEventJob.cpp \ + CFunctionJob.cpp \ + CJobList.cpp \ + CLog.cpp \ + CSimpleEventQueueBuffer.cpp \ + CStopwatch.cpp \ + CStringUtil.cpp \ + CUnicode.cpp \ + IEventQueue.cpp \ + LogOutputters.cpp \ + XBase.cpp \ + CEvent.h \ + CEventQueue.h \ + CFunctionJob.h \ + CJobList.h \ + CLog.h \ + CPriorityQueue.h \ + CSimpleEventQueueBuffer.h \ + CStopwatch.h \ + CString.h \ + CStringUtil.h \ + CUnicode.h \ + IEventQueue.h \ + IEventQueueBuffer.h \ + IJob.h \ + ILogOutputter.h \ + LogOutputters.h \ + TMethodEventJob.h \ + TMethodJob.h \ + XBase.h \ $(NULL) -INCLUDES = \ - -I$(VDEPTH)/lib/common \ - -I$(VDEPTH)/lib/arch \ +INCLUDES = \ + -I$(VDEPTH)/lib/common \ + -I$(VDEPTH)/lib/arch \ $(NULL)