X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fbase_ui.cc;h=3a4257ebdd9a9ecaf9bfc1109277543588e73427;hb=95ccbc452f513a9d6f70de45bc413067e568364c;hp=94d039ba8633aef20c4d9f462527831a7e996de6;hpb=449aab3c465bbbf66d221fac3d7ea559f1720357;p=ardour.git diff --git a/libs/pbd/base_ui.cc b/libs/pbd/base_ui.cc index 94d039ba86..3a4257ebdd 100644 --- a/libs/pbd/base_ui.cc +++ b/libs/pbd/base_ui.cc @@ -19,49 +19,53 @@ #include #include +#ifdef COMPILER_MSVC +#include // Microsoft's nearest equivalent to +#else #include +#endif #include -#include +#include +#include -#include -#include -#include -#include +#include "pbd/base_ui.h" +#include "pbd/debug.h" +#include "pbd/pthread_utils.h" +#include "pbd/error.h" +#include "pbd/compose.h" +#include "pbd/failed_constructor.h" #include "i18n.h" +#include "pbd/debug.h" + using namespace std; using namespace PBD; +using namespace Glib; -uint32_t BaseUI::rt_bit = 1; +uint64_t BaseUI::rt_bit = 1; BaseUI::RequestType BaseUI::CallSlot = BaseUI::new_request_type(); - -BaseUI::BaseUI (string str, bool with_signal_pipe) - : _name (str) +BaseUI::RequestType BaseUI::Quit = BaseUI::new_request_type(); + +BaseUI::BaseUI (const string& str) + : m_context(MainContext::get_default()) + , run_loop_thread (0) + , _name (str) +#ifndef PLATFORM_WINDOWS + , request_channel (true) +#endif { - /* odd pseudo-singleton semantics */ - base_ui_instance = this; - signal_pipe[0] = -1; - signal_pipe[1] = -1; +#ifndef PLATFORM_WINDOWS + request_channel.ios()->connect (sigc::mem_fun (*this, &BaseUI::request_handler)); +#endif - if (with_signal_pipe) { - if (setup_signal_pipe ()) { - throw failed_constructor (); - } - } + /* derived class must set _ok */ } BaseUI::~BaseUI() { - if (signal_pipe[0] >= 0) { - close (signal_pipe[0]); - } - - if (signal_pipe[1] >= 0) { - close (signal_pipe[1]); - } } BaseUI::RequestType @@ -77,32 +81,118 @@ BaseUI::new_request_type () return rt; } -int -BaseUI::setup_signal_pipe () +void +BaseUI::main_thread () +{ + DEBUG_TRACE (DEBUG::EventLoop, string_compose ("%1: event loop running in thread %2\n", name(), pthread_name())); + set_event_loop_for_thread (this); + thread_init (); + _main_loop->get_context()->signal_idle().connect (sigc::mem_fun (*this, &BaseUI::signal_running)); + _main_loop->run (); +} + +bool +BaseUI::signal_running () +{ + Glib::Threads::Mutex::Lock lm (_run_lock); + _running.signal (); + + return false; // don't call it again +} + +void +BaseUI::run () { - /* setup the pipe that other threads send us notifications/requests - through. + /* to be called by UI's that need/want their own distinct, self-created event loop thread. */ - if (pipe (signal_pipe)) { - error << string_compose (_("%1-UI: cannot create error signal pipe (%2)"), _name, std::strerror (errno)) - << endmsg; + 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)); + _running.wait (_run_lock); +} - return -1; +void +BaseUI::quit () +{ + if (_main_loop && _main_loop->is_running()) { + _main_loop->quit (); + run_loop_thread->join (); } +} + +#ifdef PLATFORM_WINDOWS +gboolean +BaseUI::_request_handler (gpointer data) +{ + BaseUI* ui = static_cast(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) +{ + /* check the request pipe */ - if (fcntl (signal_pipe[0], F_SETFL, O_NONBLOCK)) { - error << string_compose (_("%1-UI: cannot set O_NONBLOCK on signal read pipe (%2)"), _name, std::strerror (errno)) - << endmsg; - return -1; + if (ioc & ~IO_IN) { + _main_loop->quit (); } - if (fcntl (signal_pipe[1], F_SETFL, O_NONBLOCK)) { - error << string_compose (_("%1-UI: cannot set O_NONBLOCK on signal write pipe (%2)"), _name, std::strerror (errno)) - << endmsg; - return -1; + if (ioc & IO_IN) { + request_channel.drain (); + + /* there may been an error. we'd rather handle requests first, + and then get IO_HUP or IO_ERR on the next loop. + */ + + /* handle requests */ + + DEBUG_TRACE (DEBUG::EventLoop, "BaseUI::request_handler\n"); + handle_ui_requests (); } - return 0; + return true; +} +#endif + +void +BaseUI::signal_new_request () +{ + DEBUG_TRACE (DEBUG::EventLoop, "BaseUI::signal_new_request\n"); +#ifdef PLATFORM_WINDOWS + // 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 () +{ + DEBUG_TRACE (DEBUG::EventLoop, "BaseUI::attach_request_source\n"); +#ifdef PLATFORM_WINDOWS + 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 +}