More noncopyable.
[dcpomatic.git] / src / lib / ui_signaller.h
index 0797d911e7123198f02f4c0fd3c061ae4dc3d9b4..7e0f575135fc893681cc08e3b481847d112c3824 100644 (file)
 
 */
 
-#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>
 
-class UISignaller
+/** A class to allow signals to be emitted from non-UI threads and handled
+ *  by a UI thread.
+ */
+class UISignaller : public boost::noncopyable
 {
 public:
+       /** Create a UISignaller.  Must be called from the UI thread */
        UISignaller ()
                : _work (_service)
-       {}
-       
+       {
+               _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) {
-               _service.post (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;