source: vendor/synergy/current/lib/base/CEventQueue.cpp

Last change on this file was 2749, checked in by bird, 19 years ago

synergy v1.3.1 sources (zip).

File size: 11.2 KB
Line 
1;/*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2004 Chris Schoeneman
4 *
5 * This package is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * found in the file COPYING that should have accompanied this file.
8 *
9 * This package is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include "CEventQueue.h"
16#include "CLog.h"
17#include "CSimpleEventQueueBuffer.h"
18#include "CStopwatch.h"
19#include "IEventJob.h"
20#include "CArch.h"
21
22// interrupt handler. this just adds a quit event to the queue.
23static
24void
25interrupt(CArch::ESignal, void*)
26{
27 EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
28}
29
30
31//
32// CEventQueue
33//
34
35CEventQueue::CEventQueue() :
36 m_nextType(CEvent::kLast)
37{
38 setInstance(this);
39 m_mutex = ARCH->newMutex();
40 ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
41 ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
42 m_buffer = new CSimpleEventQueueBuffer;
43}
44
45CEventQueue::~CEventQueue()
46{
47 delete m_buffer;
48 ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
49 ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
50 ARCH->closeMutex(m_mutex);
51 setInstance(NULL);
52}
53
54CEvent::Type
55CEventQueue::registerType(const char* name)
56{
57 CArchMutexLock lock(m_mutex);
58 m_typeMap.insert(std::make_pair(m_nextType, name));
59 LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
60 return m_nextType++;
61}
62
63CEvent::Type
64CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
65{
66 CArchMutexLock lock(m_mutex);
67 if (type == CEvent::kUnknown) {
68 m_typeMap.insert(std::make_pair(m_nextType, name));
69 LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
70 type = m_nextType++;
71 }
72 return type;
73}
74
75const char*
76CEventQueue::getTypeName(CEvent::Type type)
77{
78 switch (type) {
79 case CEvent::kUnknown:
80 return "nil";
81
82 case CEvent::kQuit:
83 return "quit";
84
85 case CEvent::kSystem:
86 return "system";
87
88 case CEvent::kTimer:
89 return "timer";
90
91 default:
92 CTypeMap::const_iterator i = m_typeMap.find(type);
93 if (i == m_typeMap.end()) {
94 return "<unknown>";
95 }
96 else {
97 return i->second;
98 }
99 }
100}
101
102void
103CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
104{
105 CArchMutexLock lock(m_mutex);
106
107 // discard old buffer and old events
108 delete m_buffer;
109 for (CEventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) {
110 CEvent::deleteData(i->second);
111 }
112 m_events.clear();
113 m_oldEventIDs.clear();
114
115 // use new buffer
116 m_buffer = buffer;
117 if (m_buffer == NULL) {
118 m_buffer = new CSimpleEventQueueBuffer;
119 }
120}
121
122bool
123CEventQueue::getEvent(CEvent& event, double timeout)
124{
125 CStopwatch timer(true);
126retry:
127 // if no events are waiting then handle timers and then wait
128 while (m_buffer->isEmpty()) {
129 // handle timers first
130 if (hasTimerExpired(event)) {
131 return true;
132 }
133
134 // get time remaining in timeout
135 double timeLeft = timeout - timer.getTime();
136 if (timeout >= 0.0 && timeLeft <= 0.0) {
137 return false;
138 }
139
140 // get time until next timer expires. if there is a timer
141 // and it'll expire before the client's timeout then use
142 // that duration for our timeout instead.
143 double timerTimeout = getNextTimerTimeout();
144 if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
145 timeLeft = timerTimeout;
146 }
147
148 // wait for an event
149 m_buffer->waitForEvent(timeLeft);
150 }
151
152 // get the event
153 UInt32 dataID;
154 IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
155 switch (type) {
156 case IEventQueueBuffer::kNone:
157 if (timeout < 0.0 || timeout <= timer.getTime()) {
158 // don't want to fail if client isn't expecting that
159 // so if getEvent() fails with an infinite timeout
160 // then just try getting another event.
161 goto retry;
162 }
163 return false;
164
165 case IEventQueueBuffer::kSystem:
166 return true;
167
168 case IEventQueueBuffer::kUser:
169 {
170 CArchMutexLock lock(m_mutex);
171 event = removeEvent(dataID);
172 return true;
173 }
174
175 default:
176 assert(0 && "invalid event type");
177 return false;
178 }
179}
180
181bool
182CEventQueue::dispatchEvent(const CEvent& event)
183{
184 void* target = event.getTarget();
185 IEventJob* job = getHandler(event.getType(), target);
186 if (job == NULL) {
187 job = getHandler(CEvent::kUnknown, target);
188 }
189 if (job != NULL) {
190 job->run(event);
191 return true;
192 }
193 return false;
194}
195
196void
197CEventQueue::addEvent(const CEvent& event)
198{
199 // discard bogus event types
200 switch (event.getType()) {
201 case CEvent::kUnknown:
202 case CEvent::kSystem:
203 case CEvent::kTimer:
204 return;
205
206 default:
207 break;
208 }
209
210 if ((event.getFlags() & CEvent::kDeliverImmediately) != 0) {
211 dispatchEvent(event);
212 CEvent::deleteData(event);
213 }
214 else {
215 CArchMutexLock lock(m_mutex);
216
217 // store the event's data locally
218 UInt32 eventID = saveEvent(event);
219
220 // add it
221 if (!m_buffer->addEvent(eventID)) {
222 // failed to send event
223 removeEvent(eventID);
224 CEvent::deleteData(event);
225 }
226 }
227}
228
229CEventQueueTimer*
230CEventQueue::newTimer(double duration, void* target)
231{
232 assert(duration > 0.0);
233
234 CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
235 if (target == NULL) {
236 target = timer;
237 }
238 CArchMutexLock lock(m_mutex);
239 m_timers.insert(timer);
240 // initial duration is requested duration plus whatever's on
241 // the clock currently because the latter will be subtracted
242 // the next time we check for timers.
243 m_timerQueue.push(CTimer(timer, duration,
244 duration + m_time.getTime(), target, false));
245 return timer;
246}
247
248CEventQueueTimer*
249CEventQueue::newOneShotTimer(double duration, void* target)
250{
251 assert(duration > 0.0);
252
253 CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
254 if (target == NULL) {
255 target = timer;
256 }
257 CArchMutexLock lock(m_mutex);
258 m_timers.insert(timer);
259 // initial duration is requested duration plus whatever's on
260 // the clock currently because the latter will be subtracted
261 // the next time we check for timers.
262 m_timerQueue.push(CTimer(timer, duration,
263 duration + m_time.getTime(), target, true));
264 return timer;
265}
266
267void
268CEventQueue::deleteTimer(CEventQueueTimer* timer)
269{
270 CArchMutexLock lock(m_mutex);
271 for (CTimerQueue::iterator index = m_timerQueue.begin();
272 index != m_timerQueue.end(); ++index) {
273 if (index->getTimer() == timer) {
274 m_timerQueue.erase(index);
275 break;
276 }
277 }
278 CTimers::iterator index = m_timers.find(timer);
279 if (index != m_timers.end()) {
280 m_timers.erase(index);
281 }
282 m_buffer->deleteTimer(timer);
283}
284
285void
286CEventQueue::adoptHandler(CEvent::Type type, void* target, IEventJob* handler)
287{
288 CArchMutexLock lock(m_mutex);
289 IEventJob*& job = m_handlers[target][type];
290 delete job;
291 job = handler;
292}
293
294void
295CEventQueue::removeHandler(CEvent::Type type, void* target)
296{
297 IEventJob* handler = NULL;
298 {
299 CArchMutexLock lock(m_mutex);
300 CHandlerTable::iterator index = m_handlers.find(target);
301 if (index != m_handlers.end()) {
302 CTypeHandlerTable& typeHandlers = index->second;
303 CTypeHandlerTable::iterator index2 = typeHandlers.find(type);
304 if (index2 != typeHandlers.end()) {
305 handler = index2->second;
306 typeHandlers.erase(index2);
307 }
308 }
309 }
310 delete handler;
311}
312
313void
314CEventQueue::removeHandlers(void* target)
315{
316 std::vector<IEventJob*> handlers;
317 {
318 CArchMutexLock lock(m_mutex);
319 CHandlerTable::iterator index = m_handlers.find(target);
320 if (index != m_handlers.end()) {
321 // copy to handlers array and clear table for target
322 CTypeHandlerTable& typeHandlers = index->second;
323 for (CTypeHandlerTable::iterator index2 = typeHandlers.begin();
324 index2 != typeHandlers.end(); ++index2) {
325 handlers.push_back(index2->second);
326 }
327 typeHandlers.clear();
328 }
329 }
330
331 // delete handlers
332 for (std::vector<IEventJob*>::iterator index = handlers.begin();
333 index != handlers.end(); ++index) {
334 delete *index;
335 }
336}
337
338bool
339CEventQueue::isEmpty() const
340{
341 return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0);
342}
343
344IEventJob*
345CEventQueue::getHandler(CEvent::Type type, void* target) const
346{
347 CArchMutexLock lock(m_mutex);
348 CHandlerTable::const_iterator index = m_handlers.find(target);
349 if (index != m_handlers.end()) {
350 const CTypeHandlerTable& typeHandlers = index->second;
351 CTypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
352 if (index2 != typeHandlers.end()) {
353 return index2->second;
354 }
355 }
356 return NULL;
357}
358
359UInt32
360CEventQueue::saveEvent(const CEvent& event)
361{
362 // choose id
363 UInt32 id;
364 if (!m_oldEventIDs.empty()) {
365 // reuse an id
366 id = m_oldEventIDs.back();
367 m_oldEventIDs.pop_back();
368 }
369 else {
370 // make a new id
371 id = static_cast<UInt32>(m_events.size());
372 }
373
374 // save data
375 m_events[id] = event;
376 return id;
377}
378
379CEvent
380CEventQueue::removeEvent(UInt32 eventID)
381{
382 // look up id
383 CEventTable::iterator index = m_events.find(eventID);
384 if (index == m_events.end()) {
385 return CEvent();
386 }
387
388 // get data
389 CEvent event = index->second;
390 m_events.erase(index);
391
392 // save old id for reuse
393 m_oldEventIDs.push_back(eventID);
394
395 return event;
396}
397
398bool
399CEventQueue::hasTimerExpired(CEvent& event)
400{
401 // return true if there's a timer in the timer priority queue that
402 // has expired. if returning true then fill in event appropriately
403 // and reset and reinsert the timer.
404 if (m_timerQueue.empty()) {
405 return false;
406 }
407
408 // get time elapsed since last check
409 const double time = m_time.getTime();
410 m_time.reset();
411
412 // countdown elapsed time
413 for (CTimerQueue::iterator index = m_timerQueue.begin();
414 index != m_timerQueue.end(); ++index) {
415 (*index) -= time;
416 }
417
418 // done if no timers are expired
419 if (m_timerQueue.top() > 0.0) {
420 return false;
421 }
422
423 // remove timer from queue
424 CTimer timer = m_timerQueue.top();
425 m_timerQueue.pop();
426
427 // prepare event and reset the timer's clock
428 timer.fillEvent(m_timerEvent);
429 event = CEvent(CEvent::kTimer, timer.getTarget(), &m_timerEvent);
430 timer.reset();
431
432 // reinsert timer into queue if it's not a one-shot
433 if (!timer.isOneShot()) {
434 m_timerQueue.push(timer);
435 }
436
437 return true;
438}
439
440double
441CEventQueue::getNextTimerTimeout() const
442{
443 // return -1 if no timers, 0 if the top timer has expired, otherwise
444 // the time until the top timer in the timer priority queue will
445 // expire.
446 if (m_timerQueue.empty()) {
447 return -1.0;
448 }
449 if (m_timerQueue.top() <= 0.0) {
450 return 0.0;
451 }
452 return m_timerQueue.top();
453}
454
455
456//
457// CEventQueue::CTimer
458//
459
460CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
461 double initialTime, void* target, bool oneShot) :
462 m_timer(timer),
463 m_timeout(timeout),
464 m_target(target),
465 m_oneShot(oneShot),
466 m_time(initialTime)
467{
468 assert(m_timeout > 0.0);
469}
470
471CEventQueue::CTimer::~CTimer()
472{
473 // do nothing
474}
475
476void
477CEventQueue::CTimer::reset()
478{
479 m_time = m_timeout;
480}
481
482CEventQueue::CTimer&
483CEventQueue::CTimer::operator-=(double dt)
484{
485 m_time -= dt;
486 return *this;
487}
488
489CEventQueue::CTimer::operator double() const
490{
491 return m_time;
492}
493
494bool
495CEventQueue::CTimer::isOneShot() const
496{
497 return m_oneShot;
498}
499
500CEventQueueTimer*
501CEventQueue::CTimer::getTimer() const
502{
503 return m_timer;
504}
505
506void*
507CEventQueue::CTimer::getTarget() const
508{
509 return m_target;
510}
511
512void
513CEventQueue::CTimer::fillEvent(CTimerEvent& event) const
514{
515 event.m_timer = m_timer;
516 event.m_count = 0;
517 if (m_time <= 0.0) {
518 event.m_count = static_cast<UInt32>((m_timeout - m_time) / m_timeout);
519 }
520}
521
522bool
523CEventQueue::CTimer::operator<(const CTimer& t) const
524{
525 return m_time < t.m_time;
526}
Note: See TracBrowser for help on using the repository browser.