summaryrefslogtreecommitdiff
path: root/libs/pbd/timer.cc
diff options
context:
space:
mode:
authorTim Mayberry <mojofunk@gmail.com>2014-12-25 20:44:06 +0700
committerTim Mayberry <mojofunk@gmail.com>2015-01-01 18:59:01 +0700
commitb959b3fb87f4e3b740d3ad64024d1c8c3eb0aebc (patch)
tree17f9cdc4eea4a61a99bdd0499e64216cc7ee8850 /libs/pbd/timer.cc
parent770c190ccff8e6096e0bff9c78b42633020f72be (diff)
Add PBD::Timer/StandardTimer/BlinkTimer classes for convenient timeouts
Diffstat (limited to 'libs/pbd/timer.cc')
-rw-r--r--libs/pbd/timer.cc156
1 files changed, 156 insertions, 0 deletions
diff --git a/libs/pbd/timer.cc b/libs/pbd/timer.cc
new file mode 100644
index 0000000000..662c7ddc38
--- /dev/null
+++ b/libs/pbd/timer.cc
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) 2014 Tim Mayberry
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "pbd/timer.h"
+
+namespace PBD {
+
+Timer::Timer (unsigned int interval,
+ const Glib::RefPtr<Glib::MainContext>& main_context)
+ : m_timeout_source(NULL)
+ , m_timeout_interval(interval)
+ , m_main_context(main_context)
+{
+
+}
+
+gboolean
+Timer::_timeout_handler (void *data)
+{
+ Timer *const timer = static_cast<Timer*>(data);
+ return timer->timeout_handler();
+}
+
+unsigned int
+Timer::get_interval () const
+{
+ return m_timeout_interval;
+}
+
+void
+Timer::set_interval (unsigned int new_interval)
+{
+ if (new_interval == m_timeout_interval) return;
+
+ stop ();
+ m_timeout_interval = new_interval;
+ start ();
+}
+
+/**
+ * We don't use Glibmm::TimeoutSource::create() here as contrary
+ * to the documentation, SignalTimeout::connect and manually
+ * adding a TimeoutSource to a GMainContext are not equivalent.
+ *
+ * SignalTimeout::connect is the equivalent of g_timeout_add in
+ * terms off callback timing but TimeoutSource tries to adjust
+ * the timeout based on the time elapsed since the last timeout.
+ *
+ * On Windows with a high frequency timeout(40ms) this causes a
+ * small but noticable increase in CPU Usage.
+ */
+void
+Timer::start()
+{
+ if (m_timeout_source) return;
+
+ m_timeout_source = g_timeout_source_new (m_timeout_interval);
+
+#if 0 // support priorites?
+ if(priority != G_PRIORITY_DEFAULT)
+ g_source_set_priority(source, priority);
+#endif
+
+ g_source_set_callback (m_timeout_source, &Timer::_timeout_handler, this, NULL);
+
+ g_source_attach (m_timeout_source, m_main_context->gobj());
+ // GMainContext also holds a reference
+}
+
+void
+Timer::stop()
+{
+ if (m_timeout_source) {
+ g_source_destroy (m_timeout_source);
+ g_source_unref (m_timeout_source);
+ m_timeout_source = NULL;
+ }
+}
+
+bool
+Timer::timeout_handler()
+{
+ return on_elapsed();
+}
+
+StandardTimer::StandardTimer(unsigned int interval,
+ const Glib::RefPtr<Glib::MainContext>& main_context)
+ : Timer(interval, main_context)
+{ }
+
+sigc::connection
+StandardTimer::connect(const sigc::slot<void>& slot)
+{
+ if(m_signal.size() == 0) { start(); }
+
+ return m_signal.connect(slot);
+}
+
+bool
+StandardTimer::on_elapsed()
+{
+ if(m_signal.size() == 0)
+ {
+ stop();
+ return false;
+ }
+
+ m_signal();
+ return true;
+}
+
+BlinkTimer::BlinkTimer(unsigned int interval,
+ const Glib::RefPtr<Glib::MainContext>& main_context)
+ : Timer(interval, main_context)
+{ }
+
+sigc::connection
+BlinkTimer::connect(const sigc::slot<void, bool>& slot)
+{
+ if(m_blink_signal.size() == 0) { start(); }
+
+ return m_blink_signal.connect(slot);
+}
+
+bool
+BlinkTimer::on_elapsed()
+{
+ static bool blink_on = false;
+
+ if(m_blink_signal.size() == 0)
+ {
+ stop();
+ return false;
+ }
+
+ m_blink_signal(blink_on = !blink_on);
+ return true;
+}
+
+} // namespace PBD