Merge branch 'master' of /home/carl/git/dvdomatic
[dcpomatic.git] / src / lib / ui_signaller.h
index 0797d911e7123198f02f4c0fd3c061ae4dc3d9b4..221bcbe9581ad2cdfaacdcaaeabf4487ab6e6723 100644 (file)
 
 #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)
-       {}
-       
+       {
+               _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 ();
        }
 
+       /** This should wake the UI and make it call ui_idle() */
        virtual void wake_ui () = 0;
 
 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;