| /* |
| * |
| * 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; |
| } |