blob: 491c950129f4582f4b19d12b3321c41be3546080 [file] [log] [blame]
/*
*
* D-Bus++ - C++ bindings for D-Bus
*
* Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <dbus-c++/glib-integration.h>
#include <dbus/dbus.h> // for DBUS_WATCH_*
using namespace DBus;
Glib::BusTimeout::BusTimeout(Timeout::Internal *ti, GMainContext *ctx, int priority)
: Timeout(ti), _ctx(ctx), _priority(priority), _source(NULL)
{
if (Timeout::enabled())
_enable();
}
Glib::BusTimeout::~BusTimeout()
{
_disable();
}
void Glib::BusTimeout::toggle()
{
debug_log("glib: timeout %p toggled (%s)", this, Timeout::enabled() ? "on":"off");
if (Timeout::enabled()) _enable();
else _disable();
}
gboolean Glib::BusTimeout::timeout_handler(gpointer data)
{
Glib::BusTimeout *t = reinterpret_cast<Glib::BusTimeout *>(data);
t->handle();
return TRUE;
}
void Glib::BusTimeout::_enable()
{
if (_source)
_disable(); // be sane
_source = g_timeout_source_new(Timeout::interval());
g_source_set_priority(_source, _priority);
g_source_set_callback(_source, timeout_handler, this, NULL);
g_source_attach(_source, _ctx);
}
void Glib::BusTimeout::_disable()
{
if (_source)
{
g_source_destroy(_source);
_source = NULL;
}
}
struct BusSource
{
GSource source;
GPollFD poll;
};
static gboolean watch_prepare(GSource *source, gint *timeout)
{
//debug_log("glib: watch_prepare");
*timeout = -1;
return FALSE;
}
static gboolean watch_check(GSource *source)
{
//debug_log("glib: watch_check");
BusSource *io = (BusSource *)source;
return io->poll.revents ? TRUE : FALSE;
}
static gboolean watch_dispatch(GSource *source, GSourceFunc callback, gpointer data)
{
debug_log("glib: watch_dispatch");
gboolean cb = callback(data);
return cb;
}
static GSourceFuncs watch_funcs = {
watch_prepare,
watch_check,
watch_dispatch,
NULL
};
Glib::BusWatch::BusWatch(Watch::Internal *wi, GMainContext *ctx, int priority)
: Watch(wi), _ctx(ctx), _priority(priority), _source(NULL)
{
if (Watch::enabled())
_enable();
}
Glib::BusWatch::~BusWatch()
{
_disable();
}
void Glib::BusWatch::toggle()
{
debug_log("glib: watch %p toggled (%s)", this, Watch::enabled() ? "on":"off");
if (Watch::enabled()) _enable();
else _disable();
}
gboolean Glib::BusWatch::watch_handler(gpointer data)
{
Glib::BusWatch *w = reinterpret_cast<Glib::BusWatch *>(data);
BusSource *io = (BusSource *)(w->_source);
int flags = 0;
if (io->poll.revents &G_IO_IN)
flags |= DBUS_WATCH_READABLE;
if (io->poll.revents &G_IO_OUT)
flags |= DBUS_WATCH_WRITABLE;
if (io->poll.revents &G_IO_ERR)
flags |= DBUS_WATCH_ERROR;
if (io->poll.revents &G_IO_HUP)
flags |= DBUS_WATCH_HANGUP;
w->handle(flags);
return TRUE;
}
void Glib::BusWatch::_enable()
{
if (_source)
_disable(); // be sane
_source = g_source_new(&watch_funcs, sizeof(BusSource));
g_source_set_priority(_source, _priority);
g_source_set_callback(_source, watch_handler, this, NULL);
int flags = Watch::flags();
int condition = 0;
if (flags &DBUS_WATCH_READABLE)
condition |= G_IO_IN;
if (flags &DBUS_WATCH_WRITABLE)
condition |= G_IO_OUT;
if (flags &DBUS_WATCH_ERROR)
condition |= G_IO_ERR;
if (flags &DBUS_WATCH_HANGUP)
condition |= G_IO_HUP;
GPollFD *poll = &(((BusSource *)_source)->poll);
poll->fd = Watch::descriptor();
poll->events = condition;
poll->revents = 0;
g_source_add_poll(_source, poll);
g_source_attach(_source, _ctx);
}
void Glib::BusWatch::_disable()
{
if (!_source)
return;
GPollFD *poll = &(((BusSource *)_source)->poll);
g_source_remove_poll(_source, poll);
g_source_destroy(_source);
_source = NULL;
}
/*
* We need this on top of the IO handlers, because sometimes
* there are messages to dispatch queued up but no IO pending.
* (fixes also a previous problem of code not working in case of multiple dispatchers)
*/
struct DispatcherSource
{
GSource source;
Dispatcher *dispatcher;
};
static gboolean dispatcher_prepare(GSource *source, gint *timeout)
{
Dispatcher *dispatcher = ((DispatcherSource*)source)->dispatcher;
*timeout = -1;
return dispatcher->has_something_to_dispatch()? TRUE:FALSE;
}
static gboolean dispatcher_check(GSource *source)
{
return FALSE;
}
static gboolean
dispatcher_dispatch(GSource *source,
GSourceFunc callback,
gpointer user_data)
{
Dispatcher *dispatcher = ((DispatcherSource*)source)->dispatcher;
dispatcher->dispatch_pending();
return TRUE;
}
static const GSourceFuncs dispatcher_funcs = {
dispatcher_prepare,
dispatcher_check,
dispatcher_dispatch,
NULL
};
Glib::BusDispatcher::BusDispatcher()
: _ctx(NULL), _priority(G_PRIORITY_DEFAULT), _source(NULL)
{
}
Glib::BusDispatcher::~BusDispatcher()
{
if (_source)
{
GSource *temp = _source;
_source = NULL;
g_source_destroy (temp);
g_source_unref (temp);
}
if (_ctx)
g_main_context_unref(_ctx);
}
void Glib::BusDispatcher::attach(GMainContext *ctx)
{
g_assert(_ctx == NULL); // just to be sane
_ctx = ctx ? ctx : g_main_context_default();
g_main_context_ref(_ctx);
// create the source for dispatching messages
_source = g_source_new((GSourceFuncs *) &dispatcher_funcs,
sizeof(DispatcherSource));
((DispatcherSource*)_source)->dispatcher = this;
g_source_attach (_source, _ctx);
}
Timeout *Glib::BusDispatcher::add_timeout(Timeout::Internal *wi)
{
Timeout *t = new Glib::BusTimeout(wi, _ctx, _priority);
debug_log("glib: added timeout %p (%s)", t, t->enabled() ? "on":"off");
return t;
}
void Glib::BusDispatcher::rem_timeout(Timeout *t)
{
debug_log("glib: removed timeout %p", t);
delete t;
}
Watch *Glib::BusDispatcher::add_watch(Watch::Internal *wi)
{
Watch *w = new Glib::BusWatch(wi, _ctx, _priority);
debug_log("glib: added watch %p (%s) fd=%d flags=%d",
w, w->enabled() ? "on":"off", w->descriptor(), w->flags()
);
return w;
}
void Glib::BusDispatcher::rem_watch(Watch *w)
{
debug_log("glib: removed watch %p", w);
delete w;
}
void Glib::BusDispatcher::set_priority(int priority)
{
_priority = priority;
}