Merge remote-tracking branch 'origin/master' into 2.0
[dcpomatic.git] / src / lib / ui_signaller.h
index 9de1b736ddf6246b4e7ac7b37598d50746bbe2f6..ee4d230d407e566114ae57b491700196c19d21c5 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 */
@@ -33,26 +36,48 @@ public:
        {
                _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 ();
                }
        }
 
-       void ui_idle () {
-               _service.poll ();
+       /* Do something next time the UI is idle */
+       template <typename T>
+       void when_idle (T f) {
+               _service.post (f);
        }
 
-       virtual void wake_ui () = 0;
+       /** Call this in the UI when it is idle */
+       size_t ui_idle () {
+               /* This executes any functors that have been post()ed to _service */
+               return _service.poll ();
+       }
+
+       /** 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;
 };