2 * Copyright (C) 2011 Intel Corporation
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) version 3.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 #ifndef INCL_GLIB_SUPPORT
21 # define INCL_GLIB_SUPPORT
27 #include <syncevo/util.h>
30 # include <glib-object.h>
33 typedef void *GMainLoop;
36 #include <boost/shared_ptr.hpp>
37 #include <boost/intrusive_ptr.hpp>
38 #include <boost/utility.hpp>
39 #include <boost/foreach.hpp>
40 #include <boost/function.hpp>
41 #include <boost/bind.hpp>
42 #include <boost/type_traits/remove_pointer.hpp>
43 #include <boost/type_traits/function_traits.hpp>
44 #include <boost/utility/value_init.hpp>
45 #include <boost/lambda/lambda.hpp>
50 #include <syncevo/declarations.h>
59 enum GLibSelectResult {
60 GLIB_SELECT_TIMEOUT, /**< returned because not ready after given amount of time */
61 GLIB_SELECT_READY, /**< fd is ready */
62 GLIB_SELECT_QUIT /**< something else caused the loop to quit, return to caller immediately */
66 * Waits for one particular file descriptor to become ready for reading
67 * and/or writing. Keeps the given loop running while waiting.
69 * @param loop loop to keep running; must not be NULL
70 * @param fd file descriptor to watch, -1 for none
71 * @param direction read, write, both, or none (then fd is ignored)
72 * @param timeout timeout in seconds + nanoseconds from now, NULL for no timeout, empty value for immediate return
73 * @return see GLibSelectResult
75 GLibSelectResult GLibSelect(GMainLoop *loop, int fd, int direction, Timespec *timeout);
79 // Signal callback. Specializations will handle varying number of parameters.
80 template<class S> struct GObjectSignalHandler {
81 // static void handler();
82 // No specialization defined for the requested function prototype.
85 template<> struct GObjectSignalHandler<void ()> {
86 static void handler(gpointer data) throw () {
88 (*reinterpret_cast< boost::function<void ()> *>(data))();
90 Exception::handle(HANDLE_EXCEPTION_FATAL);
94 template<class A1> struct GObjectSignalHandler<void (A1)> {
95 static void handler(A1 a1, gpointer data) throw () {
97 (*reinterpret_cast< boost::function<void (A1)> *>(data))(a1);
99 Exception::handle(HANDLE_EXCEPTION_FATAL);
103 template<class A1, class A2> struct GObjectSignalHandler<void (A1, A2)> {
104 static void handler(A1 a1, A2 a2, gpointer data) throw () {
106 (*reinterpret_cast< boost::function<void (A1, A2)> *>(data))(a1, a2);
108 Exception::handle(HANDLE_EXCEPTION_FATAL);
112 template<class A1, class A2, class A3> struct GObjectSignalHandler<void (A1, A2, A3)> {
113 static void handler(A1 a1, A2 a2, A3 a3, gpointer data) throw () {
115 (*reinterpret_cast< boost::function<void (A1, A2, A3)> *>(data))(a1, a2, a3);
117 Exception::handle(HANDLE_EXCEPTION_FATAL);
121 template<class A1, class A2, class A3, class A4> struct GObjectSignalHandler<void (A1, A2, A3, A4)> {
122 static void handler(A1 a1, A2 a2, A3 a3, A4 a4, gpointer data) throw () {
124 (*reinterpret_cast< boost::function<void (A1, A2, A3, A4)> *>(data))(a1, a2, a3, a4);
126 Exception::handle(HANDLE_EXCEPTION_FATAL);
130 template<class A1, class A2, class A3, class A4, class A5> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5)> {
131 static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, gpointer data) throw () {
133 (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5)> *>(data))(a1, a2, a3, a4, a5);
135 Exception::handle(HANDLE_EXCEPTION_FATAL);
139 template<class A1, class A2, class A3, class A4, class A5, class A6> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6)> {
140 static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, gpointer data) throw () {
142 (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6)> *>(data))(a1, a2, a3, a4, a5, a6);
144 Exception::handle(HANDLE_EXCEPTION_FATAL);
148 template<class A1, class A2, class A3, class A4, class A5, class A6, class A7> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7)> {
149 static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, gpointer data) throw () {
151 (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7)> *>(data))(a1, a2, a3, a4, a5, a6, a7);
153 Exception::handle(HANDLE_EXCEPTION_FATAL);
157 template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7, A8)> {
158 static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, gpointer data) throw () {
160 (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8)> *>(data))(a1, a2, a3, a4, a5, a6, a7, a8);
162 Exception::handle(HANDLE_EXCEPTION_FATAL);
166 template<class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9> struct GObjectSignalHandler<void (A1, A2, A3, A4, A5, A6, A7, A8, A9)> {
167 static void handler(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, gpointer data) throw () {
169 (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8, A9)> *>(data))(a1, a2, a3, a4, a5, a6, a7, a8, a9);
171 Exception::handle(HANDLE_EXCEPTION_FATAL);
178 TRANSFER_REF = false, /**<
179 * Create new smart pointer which steals an existing reference without
180 * increasing the reference count of the object.
183 * Create new smart pointer which increases the reference count when
184 * storing the pointer to the object.
189 template<class C> class TrackGObject : public boost::intrusive_ptr<C> {
190 typedef boost::intrusive_ptr<C> Base_t;
192 // Frees the instance of boost::function which was allocated
194 template<class S> static void signalDestroy(gpointer data, GClosure *closure) throw () {
196 delete reinterpret_cast< boost::function<void ()> *>(data);
198 Exception::handle(HANDLE_EXCEPTION_FATAL);
203 TrackGObject(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
205 TrackGObject(const TrackGObject &other) : Base_t(other) {}
206 operator C * () const { return Base_t::get(); }
207 operator bool () const { return Base_t::get() != NULL; }
208 C * ref() const { return static_cast<C *>(g_object_ref(Base_t::get())); }
210 static TrackGObject steal(C *ptr) { return TrackGObject(ptr, TRANSFER_REF); }
212 template<class S> guint connectSignal(const char *signal,
213 const boost::function<S> &callback) {
214 return g_signal_connect_data(Base_t::get(), signal,
215 G_CALLBACK(&GObjectSignalHandler<S>::handler),
216 new boost::function<S>(callback),
220 void disconnectSignal(guint handlerID) {
221 g_signal_handler_disconnect(static_cast<gpointer>(Base_t::get()),
226 template<class C> class StealGObject : public TrackGObject<C> {
228 StealGObject(C *ptr) : TrackGObject<C>(ptr, TRANSFER_REF) {}
230 StealGObject(const StealGObject &other) : TrackGObject<C>(other) {}
233 template<class C> class TrackGLib : public boost::intrusive_ptr<C> {
234 typedef boost::intrusive_ptr<C> Base_t;
237 TrackGLib(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
239 TrackGLib(const TrackGLib &other) : Base_t(other) {}
240 operator C * () const { return Base_t::get(); }
241 operator bool () const { return Base_t::get() != NULL; }
242 C * ref() const { return static_cast<C *>(g_object_ref(Base_t::get())); }
244 static TrackGLib steal(C *ptr) { return TrackGLib(ptr, TRANSFER_REF); }
247 template<class C> class StealGLib : public TrackGLib<C> {
249 StealGLib(C *ptr) : TrackGLib<C>(ptr, TRANSFER_REF) {}
251 StealGLib(const StealGLib &other) : TrackGLib<C>(other) {}
255 * Defines a shared pointer for a GObject-based type, with intrusive
256 * reference counting. Use *outside* of SyncEvolution namespace
257 * (i.e. outside of SE_BEGIN/END_CXX. This is necessary because some
258 * functions must be put into the boost namespace. The type itself is
259 * *inside* the SyncEvolution namespace.
261 * connectSignal() connects a GObject signal to a boost::function with
262 * the function signature S. Returns the handler ID, which can be
263 * passed to g_signal_handler_disconnect() to remove the connection.
266 * SE_GOBJECT_TYPE(GFile)
267 * SE_GOBJECT_TYPE(GObject)
270 * // reference normally increased during construction,
271 * // steal() avoids that
272 * GFileCXX filecxx = GFileCXX::steal(g_file_new_for_path("foo"));
273 * GFile *filec = filecxx.get(); // does not increase reference count
274 * // file freed here as filecxx gets destroyed
277 * GObjectCXX object(...);
278 * // Define signature explicitly because it cannot be guessed from
279 * // boost::bind() result.
280 * object.connectSignal<void (GObject *gobject, GParamSpec *pspec)>("notify",
282 * // Signature is taken from boost::function parameter.
284 * object.connectSignal("notify",
285 * boost::function<void (GObject *, GParamSpec *)>(boost::bind(...)));
286 * object.disconnectSignal(handlerID);
289 #define SE_GOBJECT_TYPE(_x) \
290 void inline intrusive_ptr_add_ref(_x *ptr) { g_object_ref(ptr); } \
291 void inline intrusive_ptr_release(_x *ptr) { g_object_unref(ptr); } \
293 typedef TrackGObject<_x> _x ## CXX; \
294 typedef StealGObject<_x> _x ## StealCXX; \
298 * Defines a CXX smart pointer similar to SE_GOBJECT_TYPE,
299 * but for types which have their own _ref and _unref
303 * SE_GLIB_TYPE(GMainLoop, g_main_loop)
305 #define SE_GLIB_TYPE(_x, _func_prefix) \
306 void inline intrusive_ptr_add_ref(_x *ptr) { _func_prefix ## _ref(ptr); } \
307 void inline intrusive_ptr_release(_x *ptr) { _func_prefix ## _unref(ptr); } \
309 typedef TrackGLib<_x> _x ## CXX; \
310 typedef StealGLib<_x> _x ## StealCXX; \
315 SE_GOBJECT_TYPE(GFile)
316 SE_GOBJECT_TYPE(GFileMonitor)
317 SE_GLIB_TYPE(GMainLoop, g_main_loop)
318 SE_GLIB_TYPE(GAsyncQueue, g_async_queue)
323 * Wrapper around g_file_monitor_file().
324 * Not copyable because monitor is tied to specific callback
325 * via memory address.
327 class GLibNotify : public boost::noncopyable
330 typedef boost::function<void (GFile *, GFile *, GFileMonitorEvent)> callback_t;
332 GLibNotify(const char *file,
333 const callback_t &callback);
335 GFileMonitorCXX m_monitor;
336 callback_t m_callback;
340 * Wraps GError. Where a GError** is expected, simply pass
341 * a GErrorCXX instance.
346 /** empty error, NULL pointer */
347 GErrorCXX() : m_gerror(NULL) {}
349 /** copies error content */
350 GErrorCXX(const GErrorCXX &other) : m_gerror(g_error_copy(other.m_gerror)) {}
351 GErrorCXX &operator =(const GErrorCXX &other) {
352 if (m_gerror != other.m_gerror) {
354 g_clear_error(&m_gerror);
356 if (other.m_gerror) {
357 m_gerror = g_error_copy(other.m_gerror);
362 GErrorCXX &operator =(const GError* err) {
363 if (err != m_gerror) {
365 g_clear_error(&m_gerror);
368 m_gerror = g_error_copy(err);
374 /** takes over ownership */
375 void take (GError *err) {
376 if (err != m_gerror) {
378 g_clear_error(&m_gerror);
384 /** For convenient access to GError members (message, domain, ...) */
385 const GError * operator-> () const { return m_gerror; }
388 * For passing to C functions. They must not free the GError,
389 * because GErrorCXX retains ownership.
391 operator const GError * () const { return m_gerror; }
393 /** error description, with fallback if not set (not expected, so not localized) */
394 operator const char * () { return m_gerror ? m_gerror->message : "<<no error>>"; }
397 ~GErrorCXX() { g_clear_error(&m_gerror); }
399 /** clear error if any is set */
400 void clear() { g_clear_error(&m_gerror); }
402 /** transfer ownership of error back to caller */
403 GError *release() { GError *gerror = m_gerror; m_gerror = NULL; return gerror; }
405 /** checks whether the current error is the one passed as parameters */
406 bool matches(GQuark domain, gint code) { return g_error_matches(m_gerror, domain, code); }
409 * Use this when passing GErrorCXX instance to C functions which need to set it.
410 * Make sure the pointer isn't set yet (new GErrorCXX instance, reset if
411 * an error was encountered before) or the GNOME functions will complain
412 * when overwriting the existing error.
414 operator GError ** () { return &m_gerror; }
416 /** true if error set */
417 operator bool () { return m_gerror != NULL; }
420 * always throws an exception, including information from GError if available:
421 * <action>: <error message>|failure
423 void throwError(const std::string &action);
424 static void throwError(const std::string &action, const GError *err);
427 template<class T> void NoopDestructor(T *) {}
428 template<class T> void GObjectDestructor(T *ptr) { g_object_unref(ptr); }
429 template<class T> void GFreeDestructor(T *ptr) { g_free(static_cast<void *>(ptr)); }
432 * Copies strings from a collection into a newly allocated, NULL
433 * terminated array. Copying the strings is optional. Suggested
437 * collection.push_back(...);
438 * boost::scoped_array<char *> array(AllocStringArray(collection));
441 template<typename T> char **AllocStringArray(const T &strings,
442 const char **(*allocArray)(size_t) = NULL,
443 void (*freeArray)(const char **) = NULL,
444 const char *(*copyString)(const char *) = NULL,
445 const void (*freeString)(char *) = NULL)
447 size_t arraySize = strings.size() + 1;
448 const char **array = NULL;
449 array = allocArray ? allocArray(arraySize) : new const char *[arraySize];
451 throw std::bad_alloc();
454 memset(array, 0, sizeof(*array) * arraySize);
456 BOOST_FOREACH(const std::string &str, strings) {
457 array[i] = copyString ? copyString(str.c_str()) : str.c_str();
459 throw std::bad_alloc();
465 for (const char **ptr = array;
468 freeString(const_cast<char *>(*ptr));
476 return const_cast<char **>(array);
481 * Wraps a G[S]List of pointers to a specific type.
482 * Can be used with boost::FOREACH and provides forward iterators
483 * (two-way iterators and reverse iterators also possible, but not implemented).
484 * Frees the list and optionally (not turned on by default) also frees
485 * the data contained in it, using the provided destructor class.
486 * Use GObjectDestructor for GObject instances.
488 * @param T the type of the instances pointed to inside the list
489 * @param L GList or GSList
490 * @param D destructor function freeing a T instance
492 template< class T, class L, void (*D)(T*) = NoopDestructor<T> > struct GListCXX : boost::noncopyable {
495 static void listFree(GSList *l) { g_slist_free(l); }
496 static void listFree(GList *l) { g_list_free(l); }
498 static GSList *listPrepend(GSList *list, T *entry) { return g_slist_prepend(list, (gpointer)entry); }
499 static GList *listPrepend(GList *list, T *entry) { return g_list_prepend(list, (gpointer)entry); }
501 static GSList *listAppend(GSList *list, T *entry) { return g_slist_append(list, (gpointer)entry); }
502 static GList *listAppend(GList *list, T *entry) { return g_list_append(list, (gpointer)entry); }
505 typedef T * value_type;
507 /** by default initialize an empty list; if parameter is not NULL,
508 owership is transferred to the new instance of GListCXX */
509 GListCXX(L *list = NULL) : m_list(list) {}
512 ~GListCXX() { clear(); }
514 /** free old content, take owership of new one */
515 void reset(L *list = NULL) {
520 bool empty() { return m_list == NULL; }
522 /** clear error if any is set */
525 BOOST_FOREACH(T *entry, *this) {
529 for (iterator it = begin();
540 * Use this when passing GListCXX instance to C functions which need to set it.
541 * Make sure the pointer isn't set yet (new GListCXX instance or cleared).
543 operator L ** () { return &m_list; }
546 * Cast to plain G[S]List, for use in functions which do not modify the list.
548 operator L * () { return m_list; }
550 class iterator : public std::iterator<std::forward_iterator_tag, T *> {
553 iterator(L *list) : m_entry(list) {}
554 iterator(const iterator &other) : m_entry(other.m_entry) {}
556 * boost::foreach needs a reference as return code here,
557 * which forces us to do type casting on the address of the void * pointer,
558 * then dereference the pointer. The reason is that typecasting the
559 * pointer value directly yields an rvalue, which can't be used to initialize
560 * the reference return value.
562 T * &operator -> () const { return *getEntryPtr(); }
563 T * &operator * () const { return *getEntryPtr(); }
564 iterator & operator ++ () { m_entry = m_entry->next; return *this; }
565 iterator operator ++ (int) { return iterator(m_entry->next); }
566 bool operator == (const iterator &other) { return m_entry == other.m_entry; }
567 bool operator != (const iterator &other) { return m_entry != other.m_entry; }
571 * Used above, necessary to hide the fact that we do type
572 * casting tricks. Otherwise the compiler will complain about
573 * *(T **)&m_entry->data with "dereferencing type-punned
574 * pointer will break strict-aliasing rules".
576 * That warning is about breaking assumptions that the compiler
577 * uses for optimizations. The hope is that those optimzations
578 * aren't done here, and/or are disabled by using a function.
580 T** getEntryPtr() const { return (T **)&m_entry->data; }
582 iterator begin() { return iterator(m_list); }
583 iterator end() { return iterator(NULL); }
585 class const_iterator : public std::iterator<std::forward_iterator_tag, T *> {
590 const_iterator(L *list) : m_entry(list) {}
591 const_iterator(const const_iterator &other) : m_entry(other.m_entry) {}
592 T * &operator -> () const { return *getEntryPtr(); }
593 T * &operator * () const { return *getEntryPtr(); }
594 const_iterator & operator ++ () { m_entry = m_entry->next; return *this; }
595 const_iterator operator ++ (int) { return iterator(m_entry->next); }
596 bool operator == (const const_iterator &other) { return m_entry == other.m_entry; }
597 bool operator != (const const_iterator &other) { return m_entry != other.m_entry; }
600 T** getEntryPtr() const { return (T **)&m_entry->data; }
603 const_iterator begin() const { return const_iterator(m_list); }
604 const_iterator end() const { return const_iterator(NULL); }
606 void push_back(T *entry) { m_list = listAppend(m_list, entry); }
607 void push_front(T *entry) { m_list = listPrepend(m_list, entry); }
610 /** use this for a list which owns the strings it points to */
611 typedef GListCXX<char, GList, GFreeDestructor<char> > GStringListFreeCXX;
612 /** use this for a list which does not own the strings it points to */
613 typedef GListCXX<char, GList> GStringListNoFreeCXX;
616 * Wraps a C gchar array and takes care of freeing the memory.
618 class PlainGStr : public boost::shared_ptr<gchar>
622 PlainGStr(gchar *str) : boost::shared_ptr<char>(str, g_free) {}
623 PlainGStr(const PlainGStr &other) : boost::shared_ptr<gchar>(other) {}
624 operator const gchar *() const { return &**this; }
625 const gchar *c_str() const { return &**this; }
629 * Wraps a glib string array, frees with g_strfreev().
631 class PlainGStrArray : public boost::shared_ptr<gchar *>
635 PlainGStrArray(gchar **array) : boost::shared_ptr<char *>(array, g_strfreev) {}
636 PlainGStrArray(const PlainGStrArray &other) : boost::shared_ptr<char *>(other) {}
637 operator gchar * const *() const { return &**this; }
638 gchar * &at(size_t index) { return get()[index]; }
640 // Hide this operator because boost::shared_ptr has problems with it,
641 // probably because of missing traits for a pointer type. Instead use
643 gchar * operator[] (size_t index);
646 // empty template, need specialization based on parameter and return types
647 template <class T, class F, F *finish, class A1, class A2, class A3, class A4, class A5> struct GAsyncReady5 {};
648 template <class T, class F, F *finish, class A1, class A2, class A3, class A4> struct GAsyncReady4 {};
649 template <class T, class F, F *finish, class A1, class A2, class A3> struct GAsyncReady3 {};
650 template <class T, class F, F *finish, class A1, class A2> struct GAsyncReady2 {};
651 template <class T, class F, F *finish, class A1> struct GAsyncReady1 {};
653 // empty template, need specializations based on arity
654 template<class F, F *finish, int arity> struct GAsyncReadyCXX {};
656 // five parameters of finish function
657 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 5> :
658 public GAsyncReady5<typename boost::function_traits<F>::result_type,
660 typename boost::function_traits<F>::arg1_type,
661 typename boost::function_traits<F>::arg2_type,
662 typename boost::function_traits<F>::arg3_type,
663 typename boost::function_traits<F>::arg4_type,
664 typename boost::function_traits<F>::arg5_type>
669 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 4> :
670 public GAsyncReady4<typename boost::function_traits<F>::result_type,
672 typename boost::function_traits<F>::arg1_type,
673 typename boost::function_traits<F>::arg2_type,
674 typename boost::function_traits<F>::arg3_type,
675 typename boost::function_traits<F>::arg4_type>
680 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 3> :
681 public GAsyncReady3<typename boost::function_traits<F>::result_type,
683 typename boost::function_traits<F>::arg1_type,
684 typename boost::function_traits<F>::arg2_type,
685 typename boost::function_traits<F>::arg3_type>
690 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 2> :
691 public GAsyncReady2<typename boost::function_traits<F>::result_type,
693 typename boost::function_traits<F>::arg1_type,
694 typename boost::function_traits<F>::arg2_type>
699 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 1> :
700 public GAsyncReady1<typename boost::function_traits<F>::result_type,
702 typename boost::function_traits<F>::arg1_type>
707 // For finish functions with return parameters the assumption is that
708 // they have a non-void return value. Otherwise there would be no need
709 // for the return parameters.
711 // result = GObject, GAsyncResult, A3, A4, A5
712 template<class T, class F, F *finish, class A1, class A3, class A4, class A5> struct GAsyncReady5<T, F, finish, A1, GAsyncResult *, A3, A4, A5>
714 typedef typename boost::remove_pointer<A3>::type A3_t;
715 typedef typename boost::remove_pointer<A4>::type A4_t;
716 typedef typename boost::remove_pointer<A5>::type A5_t;
717 typedef boost::function<void (T, A3_t, A4_t, A5_t)> CXXFunctionCB_t;
719 static void handleGLibResult(GObject *sourceObject,
720 GAsyncResult *result,
721 gpointer userData) throw () {
723 A3_t retval1 = boost::value_initialized<A3_t>();
724 A4_t retval2 = boost::value_initialized<A4_t>();
725 A5_t retval3 = boost::value_initialized<A5_t>();
726 T t = finish(reinterpret_cast<A1>(sourceObject),
727 result, &retval1, &retval2, &retval3);
728 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
729 (*cb)(t, retval1, retval2, retval3);
731 // called from C, must not let exception escape
732 Exception::handle(HANDLE_EXCEPTION_FATAL);
737 // result = GObject, GAsyncResult, A3, A4, GError
738 template<class T, class F, F *finish, class A1, class A3, class A4> struct GAsyncReady5<T, F, finish, A1, GAsyncResult *, A3, A4, GError **>
740 typedef typename boost::remove_pointer<A3>::type A3_t;
741 typedef typename boost::remove_pointer<A4>::type A4_t;
742 typedef boost::function<void (T, A3_t, A4_t, const GError *)> CXXFunctionCB_t;
744 static void handleGLibResult(GObject *sourceObject,
745 GAsyncResult *result,
746 gpointer userData) throw () {
749 A3_t retval1 = boost::value_initialized<A3_t>();
750 A4_t retval2 = boost::value_initialized<A4_t>();
751 T t = finish(reinterpret_cast<A1>(sourceObject),
752 result, &retval1, &retval2, gerror);
753 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
754 (*cb)(t, retval1, retval2, gerror);
756 // called from C, must not let exception escape
757 Exception::handle(HANDLE_EXCEPTION_FATAL);
762 // result = GObject, GAsyncResult, A3, A4
763 template<class T, class F, F *finish, class A1, class A3, class A4> struct GAsyncReady4<T, F, finish, A1, GAsyncResult *, A3, A4>
765 typedef typename boost::remove_pointer<A3>::type A3_t;
766 typedef typename boost::remove_pointer<A4>::type A4_t;
767 typedef boost::function<void (T, A3_t, A4_t)> CXXFunctionCB_t;
769 static void handleGLibResult(GObject *sourceObject,
770 GAsyncResult *result,
771 gpointer userData) throw () {
773 A3_t retval1 = boost::value_initialized<A3_t>();
774 A4_t retval2 = boost::value_initialized<A4_t>();
775 T t = finish(reinterpret_cast<A1>(sourceObject),
776 result, &retval1, &retval2);
777 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
778 (*cb)(t, retval1, retval2);
780 // called from C, must not let exception escape
781 Exception::handle(HANDLE_EXCEPTION_FATAL);
786 // result = GObject, GAsyncResult, A3, GError
787 template<class T, class F, F *finish, class A1, class A3> struct GAsyncReady4<T, F, finish, A1, GAsyncResult *, A3, GError **>
789 typedef typename boost::remove_pointer<A3>::type A3_t;
790 typedef boost::function<void (T, A3_t, const GError *)> CXXFunctionCB_t;
792 static void handleGLibResult(GObject *sourceObject,
793 GAsyncResult *result,
794 gpointer userData) throw () {
797 A3_t retval = boost::value_initialized<A3_t>();
798 T t = finish(reinterpret_cast<A1>(sourceObject),
799 result, &retval, gerror);
800 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
801 (*cb)(t, retval, gerror);
803 // called from C, must not let exception escape
804 Exception::handle(HANDLE_EXCEPTION_FATAL);
809 // res = GObject, GAsyncResult, GError
810 template <class T, class F, F *finish, class A1> struct GAsyncReady3<T, F, finish, A1, GAsyncResult *, GError **>{
811 typedef boost::function<void (T, const GError *)> CXXFunctionCB_t;
813 static void handleGLibResult(GObject *sourceObject,
814 GAsyncResult *result,
815 gpointer userData) throw () {
818 T t = finish(reinterpret_cast<A1>(sourceObject),
820 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
823 // called from C, must not let exception escape
824 Exception::handle(HANDLE_EXCEPTION_FATAL);
829 // void = GObject, GAsyncResult, GError
830 template<class F, F *finish, class A1> struct GAsyncReady3<void, F, finish, A1, GAsyncResult *, GError **>
832 typedef boost::function<void (const GError *)> CXXFunctionCB_t;
834 static void handleGLibResult(GObject *sourceObject,
835 GAsyncResult *result,
836 gpointer userData) throw () {
839 finish(reinterpret_cast<A1>(sourceObject),
841 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
844 // called from C, must not let exception escape
845 Exception::handle(HANDLE_EXCEPTION_FATAL);
850 // result = GObject, GAsyncResult
851 template<class T, class F, F *finish, class A1> struct GAsyncReady2<T, F, finish, A1, GAsyncResult *>
853 typedef boost::function<void (T)> CXXFunctionCB_t;
855 static void handleGLibResult(GObject *sourceObject,
856 GAsyncResult *result,
857 gpointer userData) throw () {
859 T t = finish(reinterpret_cast<A1>(sourceObject),
861 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
864 // called from C, must not let exception escape
865 Exception::handle(HANDLE_EXCEPTION_FATAL);
870 // result = GAsyncResult, GError
871 template<class T, class F, F *finish> struct GAsyncReady2<T, F, finish, GAsyncResult *, GError **> {
873 typedef boost::function<void (T, const GError *)> CXXFunctionCB_t;
875 static void handleGLibResult(GObject *sourceObject,
876 GAsyncResult *result,
877 gpointer userData) throw () {
880 T t = finish(result, gerror);
881 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
884 // called from C, must not let exception escape
885 Exception::handle(HANDLE_EXCEPTION_FATAL);
890 // void = GObject, GAsyncResult
891 template<class F, F *finish, class A1> struct GAsyncReady2<void, F, finish, A1, GAsyncResult *>
893 typedef boost::function<void ()> CXXFunctionCB_t;
895 static void handleGLibResult(GObject *sourceObject,
896 GAsyncResult *result,
897 gpointer userData) throw () {
899 finish(reinterpret_cast<A1>(sourceObject),
901 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
904 // called from C, must not let exception escape
905 Exception::handle(HANDLE_EXCEPTION_FATAL);
910 // void = GAsyncResult, GError
911 template<class F, F *finish> struct GAsyncReady2<void, F, finish, GAsyncResult *, GError **>
913 typedef boost::function<void (const GError *)> CXXFunctionCB_t;
915 static void handleGLibResult(GObject *sourceObject,
916 GAsyncResult *result,
917 gpointer userData) throw () {
920 finish(result, gerror);
921 std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
924 // called from C, must not let exception escape
925 Exception::handle(HANDLE_EXCEPTION_FATAL);
931 * convenience macro for picking the GAsyncReadyCXX that matches the _prepare call:
932 * first switch based on arity of the finish function, then on its type
934 #define SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare) \
935 GAsyncReadyCXX< boost::remove_pointer<typeof(_prepare ## _finish)>::type, \
936 & _prepare ## _finish, \
937 boost::function_traits<boost::remove_pointer<typeof(_prepare ## _finish)>::type>::arity >
940 * Macro for asynchronous methods which use a GAsyncReadyCallback to
941 * indicate completion. The assumption is that there is a matching
942 * _finish function for the function which starts the operation.
944 * The boost::function callback will be called exactly once, with the
945 * following parameters:
946 * - return value of the _finish call, if non-void
947 * - all return parameters of the _finish call, in the order
948 * in which they appear there
949 * - a GError is passed as "const GError *", with NULL if the
950 * _finish function did not set an error; it does not have to
953 * Other parameters must be freed if required by the _finish semantic.
955 * Use boost::bind() with a boost::weak_ptr as second
956 * parameter when the callback belongs to an instance which is
957 * not guaranteed to be around when the operation completes.
961 * static void asyncCB(const GError *gerror, const char *func, bool &failed, bool &done) {
965 * // log gerror->message or store in GErrorCXX
969 * bool done = false, failed = false;
970 * SYNCEVO_GLIB_CALL_ASYNC(folks_individual_aggregator_prepare,
971 * boost::bind(asyncCB, _1,
972 * "folks_individual_aggregator_prepare",
973 * boost::ref(failed), boost::ref(done)),
976 * // Don't continue unless finished, because the callback will write
977 * // into "done" and possibly "failed".
979 * g_main_context_iteration(NULL, true);
982 * @param _prepare name of the function which starts the operation
983 * @param _cb boost::function with GError pointer and optional result value;
984 * exceptions are considered fatal
985 * @param _args parameters of _prepare, without the final GAsyncReadyCallback + user_data pair;
986 * usually at least a GCancellable pointer is part of the arguments
988 #define SYNCEVO_GLIB_CALL_ASYNC(_prepare, _cb, _args...) \
990 SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare)::handleGLibResult, \
991 new SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare)::CXXFunctionCB_t(_cb))
993 // helper class for finish method with some kind of result other than void
994 template<class T> class GAsyncReadyDoneCXX
997 template<class R> static void storeResult(GErrorCXX &gerrorStorage,
1001 const GError *gerror) {
1003 gerrorStorage = gerror;
1004 resultStorage = result;
1007 template<class R> static boost::function<void (T, const GError *)> createCB(R &result, GErrorCXX &gerror, bool &done) {
1008 return boost::bind(storeResult<R>, boost::ref(gerror), boost::ref(result), boost::ref(done), _1, _2);
1012 // helper class for finish method with void result
1013 template<> class GAsyncReadyDoneCXX<void>
1016 static void storeResult(GErrorCXX &gerrorStorage,
1018 const GError *gerror) {
1020 gerrorStorage = gerror;
1023 static boost::function<void (const GError *)> createCB(const int *dummy, GErrorCXX &gerror, bool &done) {
1024 return boost::bind(storeResult, boost::ref(gerror), boost::ref(done), _1);
1029 * Like SYNCEVO_GLIB_CALL_ASYNC, but blocks until the operation
1032 * @param _res an instance which will hold the result when done, NULL when result is void
1033 * @param _gerror a GErrorCXX instance which will hold an error
1034 * pointer afterwards in case of a failure
1036 #define SYNCEVO_GLIB_CALL_SYNC(_res, _gerror, _prepare, _args...) \
1038 bool done = false; \
1039 SYNCEVO_GLIB_CALL_ASYNC(_prepare, \
1040 GAsyncReadyDoneCXX<boost::function<typeof(_prepare ## _finish)>::result_type>::createCB(_res, _gerror, done), \
1042 GRunWhile(! boost::lambda::var(done)); \
1047 * Process events in the default context while the callback returns
1050 * This must be used instead of g_main_context_iterate() by code which
1051 * may get called in other threads. In that case the check is
1052 * transferred to the main thread which does the actual event
1053 * processing. g_main_context_iterate() would just block because we
1054 * register the main thread as permanent owner of the default context,
1055 * or would suffer from race conditions if we didn't.
1057 * The main thread must also be running GRunWhile().
1059 * Exceptions in the check code are fatal and should be avoided.
1061 void GRunWhile(const boost::function<bool ()> &check);
1067 #endif // INCL_GLIB_SUPPORT