mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-10 00:34:59 +01:00
Initial revision
git-svn-id: svn://localhost/trunk/ardour2@4 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
commit
d09f6b3016
1253 changed files with 292928 additions and 0 deletions
986
libs/glibmm2/glibmm/main.cc
Normal file
986
libs/glibmm2/glibmm/main.cc
Normal file
|
|
@ -0,0 +1,986 @@
|
|||
// -*- c++ -*-
|
||||
/* $Id$ */
|
||||
|
||||
/* Copyright (C) 2002 The gtkmm Development Team
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <glibmm/main.h>
|
||||
#include <glibmm/exceptionhandler.h>
|
||||
#include <glibmm/thread.h>
|
||||
#include <glibmm/wrap.h>
|
||||
#include <glibmm/iochannel.h>
|
||||
|
||||
#include <glib/gmessages.h>
|
||||
#include <algorithm>
|
||||
|
||||
GLIBMM_USING_STD(min)
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class SourceConnectionNode
|
||||
{
|
||||
public:
|
||||
explicit inline SourceConnectionNode(const sigc::slot_base& slot);
|
||||
|
||||
static void* notify(void* data);
|
||||
static void destroy_notify_callback(void* data);
|
||||
|
||||
inline void install(GSource* source);
|
||||
inline sigc::slot_base* get_slot();
|
||||
|
||||
private:
|
||||
sigc::slot_base slot_;
|
||||
GSource* source_;
|
||||
};
|
||||
|
||||
inline
|
||||
SourceConnectionNode::SourceConnectionNode(const sigc::slot_base& slot)
|
||||
:
|
||||
slot_ (slot),
|
||||
source_ (0)
|
||||
{
|
||||
slot_.set_parent(this, &SourceConnectionNode::notify);
|
||||
}
|
||||
|
||||
void* SourceConnectionNode::notify(void* data)
|
||||
{
|
||||
SourceConnectionNode *const self = static_cast<SourceConnectionNode*>(data);
|
||||
|
||||
// if there is no object, this call was triggered from destroy_notify_handler(),
|
||||
// because we set self->source_ to 0 there:
|
||||
if (self->source_)
|
||||
{
|
||||
GSource* s = self->source_;
|
||||
self->source_ = 0;
|
||||
g_source_destroy(s);
|
||||
|
||||
// Destroying the object triggers execution of destroy_notify_handler(),
|
||||
// eiter immediately or later, so we leave that to do the deletion.
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
void SourceConnectionNode::destroy_notify_callback(void* data)
|
||||
{
|
||||
SourceConnectionNode *const self = static_cast<SourceConnectionNode*>(data);
|
||||
|
||||
if (self)
|
||||
{
|
||||
// The GLib side is disconnected now, thus the GSource* is no longer valid.
|
||||
self->source_ = 0;
|
||||
|
||||
delete self;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
void SourceConnectionNode::install(GSource* source)
|
||||
{
|
||||
source_ = source;
|
||||
}
|
||||
|
||||
inline
|
||||
sigc::slot_base* SourceConnectionNode::get_slot()
|
||||
{
|
||||
return &slot_;
|
||||
}
|
||||
|
||||
|
||||
/* We use the callback data member of GSource to store both a pointer to our
|
||||
* wrapper and a pointer to the connection node that is currently being used.
|
||||
* The one and only SourceCallbackData object of a Glib::Source is constructed
|
||||
* in the ctor of Glib::Source and destroyed after the GSource object when the
|
||||
* reference counter of the GSource object reaches zero!
|
||||
*/
|
||||
struct SourceCallbackData
|
||||
{
|
||||
explicit inline SourceCallbackData(Glib::Source* wrapper_);
|
||||
|
||||
void set_node(SourceConnectionNode* node_);
|
||||
|
||||
static void destroy_notify_callback(void* data);
|
||||
|
||||
Glib::Source* wrapper;
|
||||
SourceConnectionNode* node;
|
||||
};
|
||||
|
||||
inline
|
||||
SourceCallbackData::SourceCallbackData(Glib::Source* wrapper_)
|
||||
:
|
||||
wrapper (wrapper_),
|
||||
node (0)
|
||||
{}
|
||||
|
||||
void SourceCallbackData::set_node(SourceConnectionNode* node_)
|
||||
{
|
||||
if(node)
|
||||
SourceConnectionNode::destroy_notify_callback(node);
|
||||
|
||||
node = node_;
|
||||
}
|
||||
|
||||
// static
|
||||
void SourceCallbackData::destroy_notify_callback(void* data)
|
||||
{
|
||||
SourceCallbackData *const self = static_cast<SourceCallbackData*>(data);
|
||||
|
||||
if(self->node)
|
||||
SourceConnectionNode::destroy_notify_callback(self->node);
|
||||
|
||||
if(self->wrapper)
|
||||
Glib::Source::destroy_notify_callback(self->wrapper);
|
||||
|
||||
delete self;
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve the callback data from a wrapped GSource object.
|
||||
*/
|
||||
static SourceCallbackData* glibmm_source_get_callback_data(GSource* source)
|
||||
{
|
||||
g_return_val_if_fail(source->callback_funcs->get != 0, 0);
|
||||
|
||||
GSourceFunc func;
|
||||
void* user_data = 0;
|
||||
|
||||
// Retrieve the callback function and data.
|
||||
(*source->callback_funcs->get)(source->callback_data, source, &func, &user_data);
|
||||
|
||||
return static_cast<SourceCallbackData*>(user_data);
|
||||
}
|
||||
|
||||
/* Glib::Source doesn't use the callback function installed with
|
||||
* g_source_set_callback(). Instead, it invokes the sigc++ slot
|
||||
* directly from dispatch_vfunc(), which is both simpler and more
|
||||
* efficient.
|
||||
* For correctness, provide a pointer to this dummy callback rather
|
||||
* than some random pointer. That also allows for sanity checks
|
||||
* here as well as in Source::dispatch_vfunc().
|
||||
*/
|
||||
static gboolean glibmm_dummy_source_callback(void*)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Only used by SignalTimeout::connect() and SignalIdle::connect().
|
||||
* These don't use Glib::Source, to avoid the unnecessary overhead
|
||||
* of a completely unused wrapper object.
|
||||
*/
|
||||
static gboolean glibmm_source_callback(void* data)
|
||||
{
|
||||
SourceConnectionNode *const conn_data = static_cast<SourceConnectionNode*>(data);
|
||||
|
||||
try
|
||||
{
|
||||
// Recreate the specific slot from the generic slot node.
|
||||
return (*static_cast<sigc::slot<bool>*>(conn_data->get_slot()))();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean glibmm_iosource_callback(GIOChannel*, GIOCondition condition, void* data)
|
||||
{
|
||||
SourceCallbackData *const callback_data = static_cast<SourceCallbackData*>(data);
|
||||
g_return_val_if_fail(callback_data->node != 0, 0);
|
||||
|
||||
try
|
||||
{
|
||||
// Recreate the specific slot from the generic slot node.
|
||||
return (*static_cast<sigc::slot<bool,Glib::IOCondition>*>(callback_data->node->get_slot()))
|
||||
((Glib::IOCondition) condition);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
namespace Glib
|
||||
{
|
||||
|
||||
/**** Glib::PollFD *********************************************************/
|
||||
|
||||
PollFD::PollFD()
|
||||
{
|
||||
gobject_.fd = 0;
|
||||
gobject_.events = 0;
|
||||
gobject_.revents = 0;
|
||||
}
|
||||
|
||||
PollFD::PollFD(int fd)
|
||||
{
|
||||
gobject_.fd = fd;
|
||||
gobject_.events = 0;
|
||||
gobject_.revents = 0;
|
||||
}
|
||||
|
||||
PollFD::PollFD(int fd, IOCondition events)
|
||||
{
|
||||
gobject_.fd = fd;
|
||||
gobject_.events = events;
|
||||
gobject_.revents = 0;
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::SignalTimeout **************************************************/
|
||||
|
||||
inline
|
||||
SignalTimeout::SignalTimeout(GMainContext* context)
|
||||
:
|
||||
context_ (context)
|
||||
{}
|
||||
|
||||
sigc::connection SignalTimeout::connect(const sigc::slot<bool>& slot,
|
||||
unsigned int interval, int priority)
|
||||
{
|
||||
SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
|
||||
const sigc::connection connection (*conn_node->get_slot());
|
||||
|
||||
GSource *const source = g_timeout_source_new(interval);
|
||||
|
||||
if(priority != G_PRIORITY_DEFAULT)
|
||||
g_source_set_priority(source, priority);
|
||||
|
||||
g_source_set_callback(
|
||||
source, &glibmm_source_callback, conn_node,
|
||||
&SourceConnectionNode::destroy_notify_callback);
|
||||
|
||||
g_source_attach(source, context_);
|
||||
g_source_unref(source); // GMainContext holds a reference
|
||||
|
||||
conn_node->install(source);
|
||||
return connection;
|
||||
}
|
||||
|
||||
SignalTimeout signal_timeout()
|
||||
{
|
||||
return SignalTimeout(0); // 0 means default context
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::SignalIdle *****************************************************/
|
||||
|
||||
inline
|
||||
SignalIdle::SignalIdle(GMainContext* context)
|
||||
:
|
||||
context_ (context)
|
||||
{}
|
||||
|
||||
sigc::connection SignalIdle::connect(const sigc::slot<bool>& slot, int priority)
|
||||
{
|
||||
SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
|
||||
const sigc::connection connection (*conn_node->get_slot());
|
||||
|
||||
GSource *const source = g_idle_source_new();
|
||||
|
||||
if(priority != G_PRIORITY_DEFAULT)
|
||||
g_source_set_priority(source, priority);
|
||||
|
||||
g_source_set_callback(
|
||||
source, &glibmm_source_callback, conn_node,
|
||||
&SourceConnectionNode::destroy_notify_callback);
|
||||
|
||||
g_source_attach(source, context_);
|
||||
g_source_unref(source); // GMainContext holds a reference
|
||||
|
||||
conn_node->install(source);
|
||||
return connection;
|
||||
}
|
||||
|
||||
SignalIdle signal_idle()
|
||||
{
|
||||
return SignalIdle(0); // 0 means default context
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::SignalIO *******************************************************/
|
||||
|
||||
inline
|
||||
SignalIO::SignalIO(GMainContext* context)
|
||||
:
|
||||
context_ (context)
|
||||
{}
|
||||
|
||||
sigc::connection SignalIO::connect(const sigc::slot<bool,IOCondition>& slot,
|
||||
int fd, IOCondition condition, int priority)
|
||||
{
|
||||
const Glib::RefPtr<IOSource> source = IOSource::create(fd, condition);
|
||||
|
||||
if(priority != G_PRIORITY_DEFAULT)
|
||||
source->set_priority(priority);
|
||||
|
||||
const sigc::connection connection = source->connect(slot);
|
||||
|
||||
g_source_attach(source->gobj(), context_);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
sigc::connection SignalIO::connect(const sigc::slot<bool,IOCondition>& slot,
|
||||
const Glib::RefPtr<IOChannel>& channel,
|
||||
IOCondition condition, int priority)
|
||||
{
|
||||
const Glib::RefPtr<IOSource> source = IOSource::create(channel, condition);
|
||||
|
||||
if(priority != G_PRIORITY_DEFAULT)
|
||||
source->set_priority(priority);
|
||||
|
||||
const sigc::connection connection = source->connect(slot);
|
||||
|
||||
g_source_attach(source->gobj(), context_);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
SignalIO signal_io()
|
||||
{
|
||||
return SignalIO(0); // 0 means default context
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::MainContext ****************************************************/
|
||||
|
||||
// static
|
||||
Glib::RefPtr<MainContext> MainContext::create()
|
||||
{
|
||||
return Glib::RefPtr<MainContext>(reinterpret_cast<MainContext*>(g_main_context_new()));
|
||||
}
|
||||
|
||||
// static
|
||||
Glib::RefPtr<MainContext> MainContext::get_default()
|
||||
{
|
||||
return Glib::wrap(g_main_context_default(), true);
|
||||
}
|
||||
|
||||
bool MainContext::iteration(bool may_block)
|
||||
{
|
||||
return g_main_context_iteration(gobj(), may_block);
|
||||
}
|
||||
|
||||
bool MainContext::pending()
|
||||
{
|
||||
return g_main_context_pending(gobj());
|
||||
}
|
||||
|
||||
void MainContext::wakeup()
|
||||
{
|
||||
g_main_context_wakeup(gobj());
|
||||
}
|
||||
|
||||
bool MainContext::acquire()
|
||||
{
|
||||
return g_main_context_acquire(gobj());
|
||||
}
|
||||
|
||||
bool MainContext::wait(Glib::Cond& cond, Glib::Mutex& mutex)
|
||||
{
|
||||
return g_main_context_wait(gobj(), cond.gobj(), mutex.gobj());
|
||||
}
|
||||
|
||||
void MainContext::release()
|
||||
{
|
||||
g_main_context_release(gobj());
|
||||
}
|
||||
|
||||
bool MainContext::prepare(int& priority)
|
||||
{
|
||||
return g_main_context_prepare(gobj(), &priority);
|
||||
}
|
||||
|
||||
bool MainContext::prepare()
|
||||
{
|
||||
return g_main_context_prepare(gobj(), 0);
|
||||
}
|
||||
|
||||
void MainContext::query(int max_priority, int& timeout, std::vector<PollFD>& fds)
|
||||
{
|
||||
if(fds.empty())
|
||||
fds.resize(8); // rather bogus number, but better than 0
|
||||
|
||||
for(;;)
|
||||
{
|
||||
const int size_before = fds.size();
|
||||
const int size_needed = g_main_context_query(
|
||||
gobj(), max_priority, &timeout, reinterpret_cast<GPollFD*>(&fds.front()), size_before);
|
||||
|
||||
fds.resize(size_needed);
|
||||
|
||||
if(size_needed <= size_before)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MainContext::check(int max_priority, std::vector<PollFD>& fds)
|
||||
{
|
||||
if(!fds.empty())
|
||||
return g_main_context_check(gobj(), max_priority, reinterpret_cast<GPollFD*>(&fds.front()), fds.size());
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainContext::dispatch()
|
||||
{
|
||||
g_main_context_dispatch(gobj());
|
||||
}
|
||||
|
||||
void MainContext::set_poll_func(GPollFunc poll_func)
|
||||
{
|
||||
g_main_context_set_poll_func(gobj(), poll_func);
|
||||
}
|
||||
|
||||
GPollFunc MainContext::get_poll_func()
|
||||
{
|
||||
return g_main_context_get_poll_func(gobj());
|
||||
}
|
||||
|
||||
void MainContext::add_poll(PollFD& fd, int priority)
|
||||
{
|
||||
g_main_context_add_poll(gobj(), fd.gobj(), priority);
|
||||
}
|
||||
|
||||
void MainContext::remove_poll(PollFD& fd)
|
||||
{
|
||||
g_main_context_remove_poll(gobj(), fd.gobj());
|
||||
}
|
||||
|
||||
SignalTimeout MainContext::signal_timeout()
|
||||
{
|
||||
return SignalTimeout(gobj());
|
||||
}
|
||||
|
||||
SignalIdle MainContext::signal_idle()
|
||||
{
|
||||
return SignalIdle(gobj());
|
||||
}
|
||||
|
||||
SignalIO MainContext::signal_io()
|
||||
{
|
||||
return SignalIO(gobj());
|
||||
}
|
||||
|
||||
void MainContext::reference() const
|
||||
{
|
||||
g_main_context_ref(reinterpret_cast<GMainContext*>(const_cast<MainContext*>(this)));
|
||||
}
|
||||
|
||||
void MainContext::unreference() const
|
||||
{
|
||||
g_main_context_unref(reinterpret_cast<GMainContext*>(const_cast<MainContext*>(this)));
|
||||
}
|
||||
|
||||
GMainContext* MainContext::gobj()
|
||||
{
|
||||
return reinterpret_cast<GMainContext*>(this);
|
||||
}
|
||||
|
||||
const GMainContext* MainContext::gobj() const
|
||||
{
|
||||
return reinterpret_cast<const GMainContext*>(this);
|
||||
}
|
||||
|
||||
GMainContext* MainContext::gobj_copy() const
|
||||
{
|
||||
reference();
|
||||
return const_cast<GMainContext*>(gobj());
|
||||
}
|
||||
|
||||
Glib::RefPtr<MainContext> wrap(GMainContext* gobject, bool take_copy)
|
||||
{
|
||||
if(take_copy && gobject)
|
||||
g_main_context_ref(gobject);
|
||||
|
||||
return Glib::RefPtr<MainContext>(reinterpret_cast<MainContext*>(gobject));
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::MainLoop *******************************************************/
|
||||
|
||||
Glib::RefPtr<MainLoop> MainLoop::create(bool is_running)
|
||||
{
|
||||
return Glib::RefPtr<MainLoop>(
|
||||
reinterpret_cast<MainLoop*>(g_main_loop_new(0, is_running)));
|
||||
}
|
||||
|
||||
Glib::RefPtr<MainLoop> MainLoop::create(const Glib::RefPtr<MainContext>& context, bool is_running)
|
||||
{
|
||||
return Glib::RefPtr<MainLoop>(
|
||||
reinterpret_cast<MainLoop*>(g_main_loop_new(Glib::unwrap(context), is_running)));
|
||||
}
|
||||
|
||||
void MainLoop::run()
|
||||
{
|
||||
g_main_loop_run(gobj());
|
||||
}
|
||||
|
||||
void MainLoop::quit()
|
||||
{
|
||||
g_main_loop_quit(gobj());
|
||||
}
|
||||
|
||||
bool MainLoop::is_running()
|
||||
{
|
||||
return g_main_loop_is_running(gobj());
|
||||
}
|
||||
|
||||
Glib::RefPtr<MainContext> MainLoop::get_context()
|
||||
{
|
||||
return Glib::wrap(g_main_loop_get_context(gobj()), true);
|
||||
}
|
||||
|
||||
//static:
|
||||
int MainLoop::depth()
|
||||
{
|
||||
return g_main_depth();
|
||||
}
|
||||
|
||||
void MainLoop::reference() const
|
||||
{
|
||||
g_main_loop_ref(reinterpret_cast<GMainLoop*>(const_cast<MainLoop*>(this)));
|
||||
}
|
||||
|
||||
void MainLoop::unreference() const
|
||||
{
|
||||
g_main_loop_unref(reinterpret_cast<GMainLoop*>(const_cast<MainLoop*>(this)));
|
||||
}
|
||||
|
||||
GMainLoop* MainLoop::gobj()
|
||||
{
|
||||
return reinterpret_cast<GMainLoop*>(this);
|
||||
}
|
||||
|
||||
const GMainLoop* MainLoop::gobj() const
|
||||
{
|
||||
return reinterpret_cast<const GMainLoop*>(this);
|
||||
}
|
||||
|
||||
GMainLoop* MainLoop::gobj_copy() const
|
||||
{
|
||||
reference();
|
||||
return const_cast<GMainLoop*>(gobj());
|
||||
}
|
||||
|
||||
Glib::RefPtr<MainLoop> wrap(GMainLoop* gobject, bool take_copy)
|
||||
{
|
||||
if(take_copy && gobject)
|
||||
g_main_loop_ref(gobject);
|
||||
|
||||
return Glib::RefPtr<MainLoop>(reinterpret_cast<MainLoop*>(gobject));
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::Source *********************************************************/
|
||||
|
||||
// static
|
||||
const GSourceFuncs Source::vfunc_table_ =
|
||||
{
|
||||
&Source::prepare_vfunc,
|
||||
&Source::check_vfunc,
|
||||
&Source::dispatch_vfunc,
|
||||
0, // finalize_vfunc // We can't use finalize_vfunc because there is no way
|
||||
// to store a pointer to our wrapper anywhere in GSource so
|
||||
// that it persists until finalize_vfunc would be called from here.
|
||||
0, // closure_callback
|
||||
0, // closure_marshal
|
||||
};
|
||||
|
||||
unsigned int Source::attach(const Glib::RefPtr<MainContext>& context)
|
||||
{
|
||||
return g_source_attach(gobject_, Glib::unwrap(context));
|
||||
}
|
||||
|
||||
unsigned int Source::attach()
|
||||
{
|
||||
return g_source_attach(gobject_, 0);
|
||||
}
|
||||
|
||||
void Source::destroy()
|
||||
{
|
||||
g_source_destroy(gobject_);
|
||||
}
|
||||
|
||||
void Source::set_priority(int priority)
|
||||
{
|
||||
g_source_set_priority(gobject_, priority);
|
||||
}
|
||||
|
||||
int Source::get_priority() const
|
||||
{
|
||||
return g_source_get_priority(gobject_);
|
||||
}
|
||||
|
||||
void Source::set_can_recurse(bool can_recurse)
|
||||
{
|
||||
g_source_set_can_recurse(gobject_, can_recurse);
|
||||
}
|
||||
|
||||
bool Source::get_can_recurse() const
|
||||
{
|
||||
return g_source_get_can_recurse(gobject_);
|
||||
}
|
||||
|
||||
unsigned int Source::get_id() const
|
||||
{
|
||||
return g_source_get_id(gobject_);
|
||||
}
|
||||
|
||||
Glib::RefPtr<MainContext> Source::get_context()
|
||||
{
|
||||
return Glib::wrap(g_source_get_context(gobject_), true);
|
||||
}
|
||||
|
||||
GSource* Source::gobj_copy() const
|
||||
{
|
||||
return g_source_ref(gobject_);
|
||||
}
|
||||
|
||||
void Source::reference() const
|
||||
{
|
||||
g_source_ref(gobject_);
|
||||
}
|
||||
|
||||
void Source::unreference() const
|
||||
{
|
||||
g_source_unref(gobject_);
|
||||
}
|
||||
|
||||
Source::Source()
|
||||
:
|
||||
gobject_ (g_source_new(const_cast<GSourceFuncs*>(&vfunc_table_), sizeof(GSource)))
|
||||
{
|
||||
g_source_set_callback(
|
||||
gobject_, &glibmm_dummy_source_callback,
|
||||
new SourceCallbackData(this), // our persistant callback data object
|
||||
&SourceCallbackData::destroy_notify_callback);
|
||||
}
|
||||
|
||||
Source::Source(GSource* cast_item, GSourceFunc callback_func)
|
||||
:
|
||||
gobject_ (cast_item)
|
||||
{
|
||||
g_source_set_callback(
|
||||
gobject_, callback_func,
|
||||
new SourceCallbackData(this), // our persistant callback data object
|
||||
&SourceCallbackData::destroy_notify_callback);
|
||||
}
|
||||
|
||||
Source::~Source()
|
||||
{
|
||||
// The dtor should be invoked by destroy_notify_callback() only, which clears
|
||||
// gobject_ before deleting. However, we might also get to this point if
|
||||
// a derived ctor threw an exception, and then we need to unref manually.
|
||||
|
||||
if(gobject_)
|
||||
{
|
||||
SourceCallbackData *const data = glibmm_source_get_callback_data(gobject_);
|
||||
data->wrapper = 0;
|
||||
|
||||
GSource *const tmp_gobject = gobject_;
|
||||
gobject_ = 0;
|
||||
|
||||
g_source_unref(tmp_gobject);
|
||||
}
|
||||
}
|
||||
|
||||
sigc::connection Source::connect_generic(const sigc::slot_base& slot)
|
||||
{
|
||||
SourceConnectionNode *const conn_node = new SourceConnectionNode(slot);
|
||||
const sigc::connection connection (*conn_node->get_slot());
|
||||
|
||||
// Don't override the callback data. Reuse the existing one
|
||||
// calling SourceCallbackData::set_node() to register conn_node.
|
||||
SourceCallbackData *const data = glibmm_source_get_callback_data(gobject_);
|
||||
data->set_node(conn_node);
|
||||
|
||||
conn_node->install(gobject_);
|
||||
return connection;
|
||||
}
|
||||
|
||||
void Source::add_poll(Glib::PollFD& poll_fd)
|
||||
{
|
||||
g_source_add_poll(gobject_, poll_fd.gobj());
|
||||
}
|
||||
|
||||
void Source::remove_poll(Glib::PollFD& poll_fd)
|
||||
{
|
||||
g_source_remove_poll(gobject_, poll_fd.gobj());
|
||||
}
|
||||
|
||||
void Source::get_current_time(Glib::TimeVal& current_time)
|
||||
{
|
||||
g_source_get_current_time(gobject_, ¤t_time);
|
||||
}
|
||||
|
||||
inline // static
|
||||
Source* Source::get_wrapper(GSource* source)
|
||||
{
|
||||
SourceCallbackData *const data = glibmm_source_get_callback_data(source);
|
||||
return data->wrapper;
|
||||
}
|
||||
|
||||
// static
|
||||
gboolean Source::prepare_vfunc(GSource* source, int* timeout)
|
||||
{
|
||||
try
|
||||
{
|
||||
Source *const self = get_wrapper(source);
|
||||
return self->prepare(*timeout);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
gboolean Source::check_vfunc(GSource* source)
|
||||
{
|
||||
try
|
||||
{
|
||||
Source *const self = get_wrapper(source);
|
||||
return self->check();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
gboolean Source::dispatch_vfunc(GSource*, GSourceFunc callback, void* user_data)
|
||||
{
|
||||
SourceCallbackData *const callback_data = static_cast<SourceCallbackData*>(user_data);
|
||||
|
||||
g_return_val_if_fail(callback == &glibmm_dummy_source_callback, 0);
|
||||
g_return_val_if_fail(callback_data != 0 && callback_data->node != 0, 0);
|
||||
|
||||
try
|
||||
{
|
||||
Source *const self = callback_data->wrapper;
|
||||
return self->dispatch(callback_data->node->get_slot());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
Glib::exception_handlers_invoke();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
void Source::destroy_notify_callback(void* data)
|
||||
{
|
||||
if(data)
|
||||
{
|
||||
Source *const self = static_cast<Source*>(data);
|
||||
|
||||
// gobject_ is already invalid at this point.
|
||||
self->gobject_ = 0;
|
||||
|
||||
// No exception checking: if the dtor throws, you're out of luck anyway.
|
||||
delete self;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::TimeoutSource **************************************************/
|
||||
|
||||
// static
|
||||
Glib::RefPtr<TimeoutSource> TimeoutSource::create(unsigned int interval)
|
||||
{
|
||||
return Glib::RefPtr<TimeoutSource>(new TimeoutSource(interval));
|
||||
}
|
||||
|
||||
sigc::connection TimeoutSource::connect(const sigc::slot<bool>& slot)
|
||||
{
|
||||
return connect_generic(slot);
|
||||
}
|
||||
|
||||
TimeoutSource::TimeoutSource(unsigned int interval)
|
||||
:
|
||||
interval_ (interval)
|
||||
{
|
||||
expiration_.assign_current_time();
|
||||
expiration_.add_milliseconds(std::min<unsigned long>(G_MAXLONG, interval_));
|
||||
}
|
||||
|
||||
TimeoutSource::~TimeoutSource()
|
||||
{}
|
||||
|
||||
bool TimeoutSource::prepare(int& timeout)
|
||||
{
|
||||
Glib::TimeVal current_time;
|
||||
get_current_time(current_time);
|
||||
|
||||
Glib::TimeVal remaining = expiration_;
|
||||
remaining.subtract(current_time);
|
||||
|
||||
if(remaining.negative())
|
||||
{
|
||||
// Already expired.
|
||||
timeout = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned long milliseconds =
|
||||
static_cast<unsigned long>(remaining.tv_sec) * 1000U +
|
||||
static_cast<unsigned long>(remaining.tv_usec) / 1000U;
|
||||
|
||||
// Set remaining milliseconds.
|
||||
timeout = std::min<unsigned long>(G_MAXINT, milliseconds);
|
||||
|
||||
// Check if the system time has been set backwards. (remaining > interval)
|
||||
remaining.add_milliseconds(- std::min<unsigned long>(G_MAXLONG, interval_) - 1);
|
||||
if(!remaining.negative())
|
||||
{
|
||||
// Oh well. Reset the expiration time to now + interval;
|
||||
// this at least avoids hanging for long periods of time.
|
||||
expiration_ = current_time;
|
||||
expiration_.add_milliseconds(interval_);
|
||||
timeout = std::min<unsigned int>(G_MAXINT, interval_);
|
||||
}
|
||||
}
|
||||
|
||||
return (timeout == 0);
|
||||
}
|
||||
|
||||
bool TimeoutSource::check()
|
||||
{
|
||||
Glib::TimeVal current_time;
|
||||
get_current_time(current_time);
|
||||
|
||||
return (expiration_ <= current_time);
|
||||
}
|
||||
|
||||
bool TimeoutSource::dispatch(sigc::slot_base* slot)
|
||||
{
|
||||
const bool again = (*static_cast<sigc::slot<bool>*>(slot))();
|
||||
|
||||
if(again)
|
||||
{
|
||||
get_current_time(expiration_);
|
||||
expiration_.add_milliseconds(std::min<unsigned long>(G_MAXLONG, interval_));
|
||||
}
|
||||
|
||||
return again;
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::IdleSource *****************************************************/
|
||||
|
||||
// static
|
||||
Glib::RefPtr<IdleSource> IdleSource::create()
|
||||
{
|
||||
return Glib::RefPtr<IdleSource>(new IdleSource());
|
||||
}
|
||||
|
||||
sigc::connection IdleSource::connect(const sigc::slot<bool>& slot)
|
||||
{
|
||||
return connect_generic(slot);
|
||||
}
|
||||
|
||||
IdleSource::IdleSource()
|
||||
{
|
||||
set_priority(PRIORITY_DEFAULT_IDLE);
|
||||
}
|
||||
|
||||
IdleSource::~IdleSource()
|
||||
{}
|
||||
|
||||
bool IdleSource::prepare(int& timeout)
|
||||
{
|
||||
timeout = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IdleSource::check()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IdleSource::dispatch(sigc::slot_base* slot)
|
||||
{
|
||||
return (*static_cast<sigc::slot<bool>*>(slot))();
|
||||
}
|
||||
|
||||
|
||||
/**** Glib::IOSource *******************************************************/
|
||||
|
||||
// static
|
||||
Glib::RefPtr<IOSource> IOSource::create(int fd, IOCondition condition)
|
||||
{
|
||||
return Glib::RefPtr<IOSource>(new IOSource(fd, condition));
|
||||
}
|
||||
|
||||
Glib::RefPtr<IOSource> IOSource::create(const Glib::RefPtr<IOChannel>& channel, IOCondition condition)
|
||||
{
|
||||
return Glib::RefPtr<IOSource>(new IOSource(channel, condition));
|
||||
}
|
||||
|
||||
sigc::connection IOSource::connect(const sigc::slot<bool,IOCondition>& slot)
|
||||
{
|
||||
return connect_generic(slot);
|
||||
}
|
||||
|
||||
IOSource::IOSource(int fd, IOCondition condition)
|
||||
:
|
||||
poll_fd_ (fd, condition)
|
||||
{
|
||||
add_poll(poll_fd_);
|
||||
}
|
||||
|
||||
IOSource::IOSource(const Glib::RefPtr<IOChannel>& channel, IOCondition condition)
|
||||
:
|
||||
Source(g_io_create_watch(channel->gobj(), (GIOCondition) condition),
|
||||
(GSourceFunc) &glibmm_iosource_callback)
|
||||
{}
|
||||
|
||||
IOSource::~IOSource()
|
||||
{}
|
||||
|
||||
bool IOSource::prepare(int& timeout)
|
||||
{
|
||||
timeout = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOSource::check()
|
||||
{
|
||||
return ((poll_fd_.get_revents() & poll_fd_.get_events()) != 0);
|
||||
}
|
||||
|
||||
bool IOSource::dispatch(sigc::slot_base* slot)
|
||||
{
|
||||
return (*static_cast<sigc::slot<bool,IOCondition>*>(slot))
|
||||
(poll_fd_.get_revents());
|
||||
}
|
||||
|
||||
} // namespace Glib
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue