glib-integration.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *  D-Bus++ - C++ bindings for D-Bus
00004  *
00005  *  Copyright (C) 2005-2007  Paolo Durante <shackan@gmail.com>
00006  *
00007  *
00008  *  This library is free software; you can redistribute it and/or
00009  *  modify it under the terms of the GNU Lesser General Public
00010  *  License as published by the Free Software Foundation; either
00011  *  version 2.1 of the License, or (at your option) any later version.
00012  *
00013  *  This library is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *  Lesser General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU Lesser General Public
00019  *  License along with this library; if not, write to the Free Software
00020  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 #include <dbus-c++/glib-integration.h>
00028 
00029 #include <dbus/dbus.h> // for DBUS_WATCH_*
00030 
00031 using namespace DBus;
00032 
00033 Glib::BusTimeout::BusTimeout(Timeout::Internal *ti, GMainContext *ctx, int priority)
00034   : Timeout(ti), _ctx(ctx), _priority(priority), _source(NULL)
00035 {
00036   if (Timeout::enabled())
00037     _enable();
00038 }
00039 
00040 Glib::BusTimeout::~BusTimeout()
00041 {
00042   _disable();
00043 }
00044 
00045 void Glib::BusTimeout::toggle()
00046 {
00047   debug_log("glib: timeout %p toggled (%s)", this, Timeout::enabled() ? "on" : "off");
00048 
00049   if (Timeout::enabled()) _enable();
00050   else      _disable();
00051 }
00052 
00053 gboolean Glib::BusTimeout::timeout_handler(gpointer data)
00054 {
00055   Glib::BusTimeout *t = reinterpret_cast<Glib::BusTimeout *>(data);
00056 
00057   t->handle();
00058 
00059   return TRUE;
00060 }
00061 
00062 void Glib::BusTimeout::_enable()
00063 {
00064   if (_source)
00065     _disable(); // be sane
00066 
00067   _source = g_timeout_source_new(Timeout::interval());
00068   g_source_set_priority(_source, _priority);
00069   g_source_set_callback(_source, timeout_handler, this, NULL);
00070   g_source_attach(_source, _ctx);
00071 }
00072 
00073 void Glib::BusTimeout::_disable()
00074 {
00075   if (_source)
00076   {
00077     g_source_destroy(_source);
00078     _source = NULL;
00079   }
00080 }
00081 
00082 struct BusSource
00083 {
00084   GSource source;
00085   GPollFD poll;
00086 };
00087 
00088 static gboolean watch_prepare(GSource *source, gint *timeout)
00089 {
00090   debug_log("glib: watch_prepare");
00091 
00092   *timeout = -1;
00093   return FALSE;
00094 }
00095 
00096 static gboolean watch_check(GSource *source)
00097 {
00098   debug_log("glib: watch_check");
00099 
00100   BusSource *io = (BusSource *)source;
00101   return io->poll.revents ? TRUE : FALSE;
00102 }
00103 
00104 static gboolean watch_dispatch(GSource *source, GSourceFunc callback, gpointer data)
00105 {
00106   debug_log("glib: watch_dispatch");
00107 
00108   gboolean cb = callback(data);
00109   return cb;
00110 }
00111 
00112 static GSourceFuncs watch_funcs =
00113 {
00114   watch_prepare,
00115   watch_check,
00116   watch_dispatch,
00117   NULL
00118 };
00119 
00120 Glib::BusWatch::BusWatch(Watch::Internal *wi, GMainContext *ctx, int priority)
00121   : Watch(wi), _ctx(ctx), _priority(priority), _source(NULL)
00122 {
00123   if (Watch::enabled())
00124     _enable();
00125 }
00126 
00127 Glib::BusWatch::~BusWatch()
00128 {
00129   _disable();
00130 }
00131 
00132 void Glib::BusWatch::toggle()
00133 {
00134   debug_log("glib: watch %p toggled (%s)", this, Watch::enabled() ? "on" : "off");
00135 
00136   if (Watch::enabled()) _enable();
00137   else      _disable();
00138 }
00139 
00140 gboolean Glib::BusWatch::watch_handler(gpointer data)
00141 {
00142   Glib::BusWatch *w = reinterpret_cast<Glib::BusWatch *>(data);
00143 
00144   BusSource *io = (BusSource *)(w->_source);
00145 
00146   int flags = 0;
00147   if (io->poll.revents & G_IO_IN)
00148     flags |= DBUS_WATCH_READABLE;
00149   if (io->poll.revents & G_IO_OUT)
00150     flags |= DBUS_WATCH_WRITABLE;
00151   if (io->poll.revents & G_IO_ERR)
00152     flags |= DBUS_WATCH_ERROR;
00153   if (io->poll.revents & G_IO_HUP)
00154     flags |= DBUS_WATCH_HANGUP;
00155 
00156   w->handle(flags);
00157 
00158   return TRUE;
00159 }
00160 
00161 void Glib::BusWatch::_enable()
00162 {
00163   if (_source)
00164     _disable(); // be sane
00165   _source = g_source_new(&watch_funcs, sizeof(BusSource));
00166   g_source_set_priority(_source, _priority);
00167   g_source_set_callback(_source, watch_handler, this, NULL);
00168 
00169   int flags = Watch::flags();
00170   int condition = 0;
00171 
00172   if (flags & DBUS_WATCH_READABLE)
00173     condition |= G_IO_IN;
00174   if (flags & DBUS_WATCH_WRITABLE)
00175     condition |= G_IO_OUT;
00176   if (flags & DBUS_WATCH_ERROR)
00177     condition |= G_IO_ERR;
00178   if (flags & DBUS_WATCH_HANGUP)
00179     condition |= G_IO_HUP;
00180 
00181   GPollFD *poll = &(((BusSource *)_source)->poll);
00182   poll->fd = Watch::descriptor();
00183   poll->events = condition;
00184   poll->revents = 0;
00185 
00186   g_source_add_poll(_source, poll);
00187   g_source_attach(_source, _ctx);
00188 }
00189 
00190 void Glib::BusWatch::_disable()
00191 {
00192   if (!_source)
00193     return;
00194   GPollFD *poll = &(((BusSource *)_source)->poll);
00195   g_source_remove_poll(_source, poll);
00196   g_source_destroy(_source);
00197   _source = NULL;
00198 }
00199 
00200 /*
00201  * We need this on top of the IO handlers, because sometimes
00202  * there are messages to dispatch queued up but no IO pending.
00203  * (fixes also a previous problem of code not working in case of multiple dispatchers)
00204 */
00205 struct DispatcherSource
00206 {
00207   GSource source;
00208   Dispatcher *dispatcher;
00209 };
00210 
00211 
00212 static gboolean dispatcher_prepare(GSource *source, gint *timeout)
00213 {
00214   Dispatcher *dispatcher = ((DispatcherSource *)source)->dispatcher;
00215 
00216   *timeout = -1;
00217 
00218   return dispatcher->has_something_to_dispatch() ? TRUE : FALSE;
00219 }
00220 
00221 static gboolean dispatcher_check(GSource *source)
00222 {
00223   return FALSE;
00224 }
00225 
00226 static gboolean
00227 dispatcher_dispatch(GSource *source,
00228                     GSourceFunc callback,
00229                     gpointer user_data)
00230 {
00231   Dispatcher *dispatcher = ((DispatcherSource *)source)->dispatcher;
00232 
00233   dispatcher->dispatch_pending();
00234   return TRUE;
00235 }
00236 
00237 static const GSourceFuncs dispatcher_funcs =
00238 {
00239   dispatcher_prepare,
00240   dispatcher_check,
00241   dispatcher_dispatch,
00242   NULL
00243 };
00244 
00245 Glib::BusDispatcher::BusDispatcher()
00246   : _ctx(NULL), _priority(G_PRIORITY_DEFAULT), _source(NULL)
00247 {
00248 }
00249 
00250 Glib::BusDispatcher::~BusDispatcher()
00251 {
00252   if (_source)
00253   {
00254     GSource *temp = _source;
00255     _source = NULL;
00256 
00257     g_source_destroy(temp);
00258     g_source_unref(temp);
00259   }
00260 
00261   if (_ctx)
00262     g_main_context_unref(_ctx);
00263 }
00264 
00265 void Glib::BusDispatcher::attach(GMainContext *ctx)
00266 {
00267   g_assert(_ctx == NULL); // just to be sane
00268 
00269   _ctx = ctx ? ctx : g_main_context_default();
00270   g_main_context_ref(_ctx);
00271 
00272   // create the source for dispatching messages
00273   _source = g_source_new((GSourceFuncs *) &dispatcher_funcs,
00274                          sizeof(DispatcherSource));
00275 
00276   ((DispatcherSource *)_source)->dispatcher = this;
00277   g_source_attach(_source, _ctx);
00278 }
00279 
00280 Timeout *Glib::BusDispatcher::add_timeout(Timeout::Internal *wi)
00281 {
00282   Timeout *t = new Glib::BusTimeout(wi, _ctx, _priority);
00283 
00284   debug_log("glib: added timeout %p (%s)", t, t->enabled() ? "on" : "off");
00285 
00286   return t;
00287 }
00288 
00289 void Glib::BusDispatcher::rem_timeout(Timeout *t)
00290 {
00291   debug_log("glib: removed timeout %p", t);
00292 
00293   delete t;
00294 }
00295 
00296 Watch *Glib::BusDispatcher::add_watch(Watch::Internal *wi)
00297 {
00298   Watch *w = new Glib::BusWatch(wi, _ctx, _priority);
00299 
00300   debug_log("glib: added watch %p (%s) fd=%d flags=%d",
00301             w, w->enabled() ? "on" : "off", w->descriptor(), w->flags()
00302            );
00303   return w;
00304 }
00305 
00306 void Glib::BusDispatcher::rem_watch(Watch *w)
00307 {
00308   debug_log("glib: removed watch %p", w);
00309 
00310   delete w;
00311 }
00312 
00313 void Glib::BusDispatcher::set_priority(int priority)
00314 {
00315   _priority = priority;
00316 }