*/
-#ifndef DVDOMATIC_UI_SIGNALLER_H
-#define DVDOMATIC_UI_SIGNALLER_H
+#ifndef DCPOMATIC_UI_SIGNALLER_H
+#define DCPOMATIC_UI_SIGNALLER_H
#include <boost/bind.hpp>
#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+/** A class to allow signals to be emitted from non-UI threads and handled
+ * by a UI thread.
+ */
class UISignaller
{
public:
+ /** Create a UISignaller. Must be called from the UI thread */
UISignaller ()
: _work (_service)
- {}
-
- template <class S>
- void emit (S signal) {
- _service.post (boost::bind (boost::ref (signal)));
+ {
+ _ui_thread = boost::this_thread::get_id ();
}
+ /** Emit a signal from any thread whose handlers will be called in the UI
+ * thread. Use something like:
+ *
+ * ui_signaller->emit (boost::bind (boost::ref (SomeSignal), parameter));
+ */
+ template <typename T>
+ void emit (T f) {
+ if (boost::this_thread::get_id() == _ui_thread) {
+ /* already in the UI thread */
+ f ();
+ } else {
+ /* non-UI thread; post to the service and wake up the UI */
+ _service.post (f);
+ wake_ui ();
+ }
+ }
+
+ /** Call this in the UI when it is idle */
void ui_idle () {
_service.poll ();
}
- virtual void wake_ui () = 0;
+ /** This should wake the UI and make it call ui_idle() */
+ virtual void wake_ui () {
+ /* This is only a sensible implementation when there is no GUI... */
+ ui_idle ();
+ }
private:
+ /** A io_service which is used as the conduit for messages */
boost::asio::io_service _service;
+ /** Object required to keep io_service from stopping when it has nothing to do */
boost::asio::io_service::work _work;
+ /** The UI thread's ID */
+ boost::thread::id _ui_thread;
};
extern UISignaller* ui_signaller;