]> Dogcows Code - chaz/openbox/blob - otk/timer.cc
ceee8f2a2c57abc9488a8342c4ed3e0969e98bd8
[chaz/openbox] / otk / timer.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif // HAVE_CONFIG_H
6
7 #include "timer.hh"
8 #include "display.hh"
9
10 extern "C" {
11 #ifdef HAVE_SYS_SELECT_H
12 # include <sys/select.h>
13 #else
14 # ifdef HAVE_UNISTD_H
15 # include <sys/types.h>
16 # include <unistd.h>
17 # endif // HAVE_UNISTD_H
18 #endif // HAVE_SYS_SELECT_H
19 }
20
21 namespace otk {
22
23 timeval Timer::_nearest_timeout, Timer::_now;
24 Timer::TimerQ Timer::_q;
25
26 void Timer::timevalAdd(timeval &a, long msec)
27 {
28 a.tv_sec += msec / 1000;
29 a.tv_usec += (msec % 1000) * 1000;
30 a.tv_sec += a.tv_usec / 1000000;
31 a.tv_usec %= 1000000;
32 }
33
34 bool Timer::nearestTimeout(struct timeval &tm)
35 {
36 if (_q.empty())
37 return false;
38 tm.tv_sec = _nearest_timeout.tv_sec - _now.tv_sec;
39 tm.tv_usec = _nearest_timeout.tv_usec - _now.tv_usec;
40
41 while (tm.tv_usec < 0) {
42 tm.tv_usec += 1000000;
43 tm.tv_sec--;
44 }
45 tm.tv_sec += tm.tv_usec / 1000000;
46 tm.tv_usec %= 1000000;
47 if (tm.tv_sec < 0)
48 tm.tv_sec = 0;
49
50 return true;
51 }
52
53 void Timer::dispatchTimers(bool wait)
54 {
55 fd_set selset;
56 int fd;
57 timeval next;
58 Timer *curr;
59
60 gettimeofday(&_now, NULL);
61 _nearest_timeout = _now;
62 _nearest_timeout.tv_sec += 10000;
63
64 while (!_q.empty()) {
65 curr = _q.top();
66 /* since we overload the destructor to keep from removing from the middle
67 of the priority queue, set _del_me, we have to do our real delete in
68 here.
69 */
70 if (curr->_del_me) {
71 _q.pop();
72 realDelete(curr);
73 continue;
74 }
75
76 // the queue is sorted, so if this timer shouldn't fire, none are ready
77 _nearest_timeout = curr->_timeout;
78 if (!timercmp(&_now, &_nearest_timeout, >))
79 break;
80
81 /* we set the last fired time to delay msec after the previous firing, then
82 re-insert. timers maintain their order and may trigger more than once
83 if they've waited more than one delay's worth of time.
84 */
85 _q.pop();
86 timevalAdd(curr->_last, curr->_delay);
87 curr->_action(curr->_data);
88 timevalAdd(curr->_timeout, curr->_delay);
89 _q.push(curr);
90 }
91
92 if (wait) {
93 // wait for the nearest trigger, or for X to do something interesting
94 fd = ConnectionNumber(**display);
95 FD_ZERO(&selset);
96 FD_SET(fd, &selset);
97 if (nearestTimeout(next))
98 select(fd + 1, &selset, NULL, NULL, &next);
99 else
100 select(fd + 1, &selset, NULL, NULL, NULL);
101 }
102 }
103
104 Timer::Timer(long delay, Timer::TimeoutHandler action, void *data)
105 : _delay(delay),
106 _action(action),
107 _data(data),
108 _del_me(false),
109 _last(_now),
110 _timeout(_now)
111 {
112 timevalAdd(_timeout, delay);
113 _q.push(this);
114 }
115
116 void Timer::operator delete(void *self)
117 {
118 Timer *t;
119 t = (Timer *)self;
120 t->_del_me = true;
121 }
122
123 void Timer::realDelete(Timer *me)
124 {
125 ::delete me;
126 }
127
128 void Timer::initialize(void)
129 {
130 gettimeofday(&_now, NULL);
131 _nearest_timeout.tv_sec = 100000;
132 _nearest_timeout.tv_usec = 0;
133 }
134
135 void Timer::destroy(void)
136 {
137 while(!_q.empty()) {
138 realDelete(_q.top());
139 _q.pop();
140 }
141 }
142
143 }
This page took 0.037707 seconds and 4 git commands to generate.