add realloc pool to MSVC project
[ardour.git] / libs / pbd / timer.cc
1 /*
2     Copyright (C) 2014 Tim Mayberry
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program 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     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "pbd/timer.h"
21
22 namespace PBD {
23
24 Timer::Timer (unsigned int interval,
25               const Glib::RefPtr<Glib::MainContext>& main_context)
26         : m_timeout_source(NULL)
27         , m_timeout_interval(interval)
28         , m_main_context(main_context)
29         , m_suspended(false)
30 {
31
32 }
33
34 gboolean
35 Timer::_timeout_handler (void *data)
36 {
37         Timer *const timer = static_cast<Timer*>(data);
38         return timer->timeout_handler();
39 }
40
41 unsigned int
42 Timer::get_interval () const
43 {
44         return m_timeout_interval;
45 }
46
47 void
48 Timer::set_interval (unsigned int new_interval)
49 {
50         if (new_interval == m_timeout_interval) return;
51
52         stop ();
53         m_timeout_interval = new_interval;
54         start ();
55 }
56
57 /**
58  * We don't use Glibmm::TimeoutSource::create() here as contrary
59  * to the documentation, SignalTimeout::connect and manually
60  * adding a TimeoutSource to a GMainContext are not equivalent.
61  *
62  * SignalTimeout::connect is the equivalent of g_timeout_add in
63  * terms off callback timing but TimeoutSource tries to adjust
64  * the timeout based on the time elapsed since the last timeout.
65  *
66  * On Windows with a high frequency timeout(40ms) this causes a
67  * small but noticable increase in CPU Usage.
68  */
69 void
70 Timer::start()
71 {
72         if (m_timeout_source) return;
73
74         m_timeout_source = g_timeout_source_new (m_timeout_interval);
75
76 #if 0 // support priorites?
77         if(priority != G_PRIORITY_DEFAULT)
78                 g_source_set_priority(source, priority);
79 #endif
80
81         g_source_set_callback (m_timeout_source, &Timer::_timeout_handler, this, NULL);
82
83         g_source_attach (m_timeout_source, m_main_context->gobj());
84         // GMainContext also holds a reference
85 }
86
87 void
88 Timer::stop()
89 {
90         if (m_timeout_source) {
91                 g_source_destroy (m_timeout_source);
92                 g_source_unref (m_timeout_source);
93                 m_timeout_source = NULL;
94         }
95 }
96
97 bool
98 Timer::timeout_handler()
99 {
100         return on_elapsed();
101 }
102
103 StandardTimer::StandardTimer(unsigned int interval,
104                 const Glib::RefPtr<Glib::MainContext>& main_context)
105         : Timer(interval, main_context)
106 { }
107
108 sigc::connection
109 StandardTimer::connect(const sigc::slot<void>& slot)
110 {
111         if(m_signal.size() == 0) { start(); }
112
113         return m_signal.connect(slot);
114 }
115
116 bool
117 StandardTimer::on_elapsed()
118 {
119         if(m_signal.size() == 0)
120         {
121                 stop();
122                 return false;
123         }
124
125         if (!suspended ()) {
126                 m_signal();
127         }
128         return true;
129 }
130
131 BlinkTimer::BlinkTimer(unsigned int interval,
132                 const Glib::RefPtr<Glib::MainContext>& main_context)
133         : Timer(interval, main_context)
134 { }
135
136 sigc::connection
137 BlinkTimer::connect(const sigc::slot<void, bool>& slot)
138 {
139         if(m_blink_signal.size() == 0) { start(); }
140
141         return m_blink_signal.connect(slot);
142 }
143
144 bool
145 BlinkTimer::on_elapsed()
146 {
147         static bool blink_on = false;
148
149         if(m_blink_signal.size() == 0)
150         {
151                 stop();
152                 return false;
153         }
154
155         if (!suspended ()) {
156                 m_blink_signal(blink_on = !blink_on);
157         }
158         return true;
159 }
160
161 } // namespace PBD