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 }