Use timeout source to process ui requests on windows
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 11 Jul 2013 16:56:35 +0000 (12:56 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 11 Jul 2013 16:56:35 +0000 (12:56 -0400)
Using a timeout source to process ui events/requests is suboptimal
but it works for the moment. Have to use g_source functions as glibmm
functions are not thread safe AFAIK.

Behaviour should be exactly the same on unix.

libs/gtkmm2ext/gtk_ui.cc
libs/pbd/base_ui.cc
libs/pbd/pbd/base_ui.h

index ee5e0c07f6ad019d4128fbff08ba849c3078bf07..831fa7e38f1ecef54633c23d6778482c6de4aecc 100644 (file)
@@ -94,7 +94,7 @@ UI::UI (string namestr, int *argc, char ***argv)
 
        /* attach our request source to the default main context */
 
-       attach_request_source (MainContext::get_default());
+       attach_request_source ();
 
        errors = new TextViewer (800,600);
        errors->text().set_editable (false);
index 35ea6078ee71415ca6ba50f7fcf8a18f60c1c2ab..5725d691829d4874e68be9bcfe404c3b40debb91 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "i18n.h"
 
+#include "pbd/debug.h"
+
 using namespace std;
 using namespace PBD;
 using namespace Glib;
@@ -42,13 +44,18 @@ BaseUI::RequestType BaseUI::CallSlot = BaseUI::new_request_type();
 BaseUI::RequestType BaseUI::Quit = BaseUI::new_request_type();
 
 BaseUI::BaseUI (const string& str)
-       : run_loop_thread (0)
+       : m_context(MainContext::get_default())
+       , run_loop_thread (0)
        , _name (str)
+#ifndef WIN32
        , request_channel (true)
+#endif
 {
        base_ui_instance = this;
 
+#ifndef WIN32
        request_channel.ios()->connect (sigc::mem_fun (*this, &BaseUI::request_handler));
+#endif
 
        /* derived class must set _ok */
 }
@@ -95,11 +102,9 @@ BaseUI::run ()
        /* to be called by UI's that need/want their own distinct, self-created event loop thread.
        */
 
-       _main_loop = MainLoop::create (MainContext::create());
-       request_channel.ios()->attach (_main_loop->get_context());
-
-       /* glibmm hack - drop the refptr to the IOSource now before it can hurt */
-       request_channel.drop_ios ();
+       m_context = MainContext::create();
+       _main_loop = MainLoop::create (m_context);
+       attach_request_source ();
 
        Glib::Threads::Mutex::Lock lm (_run_lock);
        run_loop_thread = Glib::Threads::Thread::create (mem_fun (*this, &BaseUI::main_thread));
@@ -115,6 +120,24 @@ BaseUI::quit ()
        }
 }
 
+#ifdef WIN32
+gboolean
+BaseUI::_request_handler (gpointer data)
+{
+       BaseUI* ui = static_cast<BaseUI*>(data);
+       return ui->request_handler ();
+}
+
+bool
+BaseUI::request_handler ()
+{
+       DEBUG_TRACE (DEBUG::EventLoop, "BaseUI::request_handler\n");
+       handle_ui_requests ();
+       // keep calling indefinitely at the timeout interval
+       return true;
+}
+
+#else
 bool
 BaseUI::request_handler (Glib::IOCondition ioc)
 {
@@ -133,20 +156,39 @@ BaseUI::request_handler (Glib::IOCondition ioc)
 
                /* handle requests */
 
+               DEBUG_TRACE (DEBUG::EventLoop, "BaseUI::request_handler\n");
                handle_ui_requests ();
        }
 
        return true;
 }
+#endif
 
 void
 BaseUI::signal_new_request ()
 {
+       DEBUG_TRACE (DEBUG::EventLoop, "BaseUI::signal_new_request\n");
+#ifdef WIN32
+       // handled in timeout, how to signal...?
+#else
        request_channel.wakeup ();
+#endif
 }
 
+/**
+ * This method relies on the caller having already set m_context
+ */
 void
-BaseUI::attach_request_source (Glib::RefPtr<Glib::MainContext> context)
+BaseUI::attach_request_source ()
 {
-       request_channel.ios()->attach (context);
+       DEBUG_TRACE (DEBUG::EventLoop, "BaseUI::attach_request_source\n");
+#ifdef WIN32
+       GSource* request_source = g_timeout_source_new(200);
+       g_source_set_callback (request_source, &BaseUI::_request_handler, this, NULL);
+       g_source_attach (request_source, m_context->gobj());
+#else
+       request_channel.ios()->attach (m_context);
+       /* glibmm hack - drop the refptr to the IOSource now before it can hurt */
+       request_channel.drop_ios ();
+#endif
 }
index 22784c9bfc22ca9083acbb74a57185e1a41180e3..686af485e6fd50e0deaf566a375d69c35b8e4e57 100644 (file)
@@ -74,9 +74,10 @@ class BaseUI : public sigc::trackable, public PBD::EventLoop
        bool _ok; 
 
        Glib::RefPtr<Glib::MainLoop> _main_loop;
-        Glib::Threads::Thread*       run_loop_thread;
+       Glib::RefPtr<Glib::MainContext> m_context;
+       Glib::Threads::Thread*       run_loop_thread;
        Glib::Threads::Mutex        _run_lock;
-        Glib::Threads::Cond         _running;
+       Glib::Threads::Cond         _running;
 
        /* this signals _running from within the event loop,
           from an idle callback 
@@ -91,12 +92,17 @@ class BaseUI : public sigc::trackable, public PBD::EventLoop
 
        virtual void thread_init () {};
 
+#ifdef WIN32
+       static gboolean _request_handler (gpointer);
+       bool request_handler ();
+#else
        /** Called when there input ready on the request_channel
         */
        bool request_handler (Glib::IOCondition);
+#endif
 
        void signal_new_request ();
-       void attach_request_source (Glib::RefPtr<Glib::MainContext> context);
+       void attach_request_source ();
 
        /** Derived UI objects must implement this method,
         * which will be called whenever there are requests
@@ -108,7 +114,9 @@ class BaseUI : public sigc::trackable, public PBD::EventLoop
        std::string _name; 
        BaseUI* base_ui_instance;
 
+#ifndef WIN32
        CrossThreadChannel request_channel;
+#endif
        
        static uint64_t rt_bit;