11d0fb80af087b85d4e11c15e6d9072d9d21a82f
[platform/upstream/syncevolution.git] / src / syncevo / GLibSupport.h
1 /*
2  * Copyright (C) 2011 Intel Corporation
3  *
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.
8  *
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.
13  *
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
17  * 02110-1301  USA
18  */
19
20 #ifndef INCL_GLIB_SUPPORT
21 # define INCL_GLIB_SUPPORT
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <syncevo/util.h>
28
29 #ifdef HAVE_GLIB
30 # include <glib-object.h>
31 # include <gio/gio.h>
32 #else
33 typedef void *GMainLoop;
34 #endif
35
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>
46
47 #include <iterator>
48 #include <memory>
49
50 #include <syncevo/declarations.h>
51 SE_BEGIN_CXX
52
53 enum {
54     GLIB_SELECT_NONE = 0,
55     GLIB_SELECT_READ = 1,
56     GLIB_SELECT_WRITE = 2
57 };
58
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 */
63 };
64
65 /**
66  * Waits for one particular file descriptor to become ready for reading
67  * and/or writing. Keeps the given loop running while waiting.
68  *
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
74  */
75 GLibSelectResult GLibSelect(GMainLoop *loop, int fd, int direction, Timespec *timeout);
76
77 #ifdef HAVE_GLIB
78
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.
83 };
84
85 template<> struct GObjectSignalHandler<void ()> {
86     static void handler(gpointer data) throw () {
87         try {
88             (*reinterpret_cast< boost::function<void ()> *>(data))();
89         } catch (...) {
90             Exception::handle(HANDLE_EXCEPTION_FATAL);
91         }
92     }
93 };
94 template<class A1> struct GObjectSignalHandler<void (A1)> {
95     static void handler(A1 a1, gpointer data) throw () {
96         try {
97             (*reinterpret_cast< boost::function<void (A1)> *>(data))(a1);
98         } catch (...) {
99             Exception::handle(HANDLE_EXCEPTION_FATAL);
100         }
101     }
102 };
103 template<class A1, class A2> struct GObjectSignalHandler<void (A1, A2)> {
104     static void handler(A1 a1, A2 a2, gpointer data) throw () {
105         try {
106             (*reinterpret_cast< boost::function<void (A1, A2)> *>(data))(a1, a2);
107         } catch (...) {
108             Exception::handle(HANDLE_EXCEPTION_FATAL);
109         }
110     }
111 };
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 () {
114         try {
115             (*reinterpret_cast< boost::function<void (A1, A2, A3)> *>(data))(a1, a2, a3);
116         } catch (...) {
117             Exception::handle(HANDLE_EXCEPTION_FATAL);
118         }
119     }
120 };
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 () {
123         try {
124             (*reinterpret_cast< boost::function<void (A1, A2, A3, A4)> *>(data))(a1, a2, a3, a4);
125         } catch (...) {
126             Exception::handle(HANDLE_EXCEPTION_FATAL);
127         }
128     }
129 };
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 () {
132         try {
133             (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5)> *>(data))(a1, a2, a3, a4, a5);
134         } catch (...) {
135             Exception::handle(HANDLE_EXCEPTION_FATAL);
136         }
137     }
138 };
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 () {
141         try {
142             (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6)> *>(data))(a1, a2, a3, a4, a5, a6);
143         } catch (...) {
144             Exception::handle(HANDLE_EXCEPTION_FATAL);
145         }
146     }
147 };
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 () {
150         try {
151             (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7)> *>(data))(a1, a2, a3, a4, a5, a6, a7);
152         } catch (...) {
153             Exception::handle(HANDLE_EXCEPTION_FATAL);
154         }
155     }
156 };
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 () {
159         try {
160             (*reinterpret_cast< boost::function<void (A1, A2, A3, A4, A5, A6, A7, A8)> *>(data))(a1, a2, a3, a4, a5, a6, a7, a8);
161         } catch (...) {
162             Exception::handle(HANDLE_EXCEPTION_FATAL);
163         }
164     }
165 };
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 () {
168         try {
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);
170         } catch (...) {
171             Exception::handle(HANDLE_EXCEPTION_FATAL);
172         }
173     }
174 };
175
176 enum RefOwnership
177 {
178     TRANSFER_REF = false, /**<
179                            * Create new smart pointer which steals an existing reference without
180                            * increasing the reference count of the object.
181                            */
182     ADD_REF = true        /**<
183                            * Create new smart pointer which increases the reference count when
184                            * storing the pointer to the object.
185                            */
186 };
187
188
189 template<class C> class TrackGObject : public boost::intrusive_ptr<C> {
190     typedef boost::intrusive_ptr<C> Base_t;
191
192     // Frees the instance of boost::function which was allocated
193     // by connectSignal.
194     template<class S> static void signalDestroy(gpointer data, GClosure *closure) throw () {
195         try {
196             delete reinterpret_cast< boost::function<void ()> *>(data);
197         } catch (...) {
198             Exception::handle(HANDLE_EXCEPTION_FATAL);
199         }
200     }
201
202  public:
203     TrackGObject(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
204     TrackGObject() {}
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())); }
209
210     static  TrackGObject steal(C *ptr) { return TrackGObject(ptr, TRANSFER_REF); }
211
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),
217                                      &signalDestroy<S>,
218                                      GConnectFlags(0));
219     }
220     void disconnectSignal(guint handlerID) {
221         g_signal_handler_disconnect(static_cast<gpointer>(Base_t::get()),
222                                     handlerID);
223     }
224 };
225
226 template<class C> class StealGObject : public TrackGObject<C> {
227  public:
228     StealGObject(C *ptr) : TrackGObject<C>(ptr, TRANSFER_REF) {}
229     StealGObject() {}
230     StealGObject(const StealGObject &other) : TrackGObject<C>(other) {}
231 };
232
233 template<class C> class TrackGLib : public boost::intrusive_ptr<C> {
234     typedef boost::intrusive_ptr<C> Base_t;
235
236  public:
237  TrackGLib(C *ptr, RefOwnership ownership) : Base_t(ptr, (bool)ownership) {}
238     TrackGLib() {}
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())); }
243
244     static  TrackGLib steal(C *ptr) { return TrackGLib(ptr, TRANSFER_REF); }
245 };
246
247 template<class C> class StealGLib : public TrackGLib<C> {
248  public:
249     StealGLib(C *ptr) : TrackGLib<C>(ptr, TRANSFER_REF) {}
250     StealGLib() {}
251     StealGLib(const StealGLib &other) : TrackGLib<C>(other) {}
252 };
253
254 /**
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.
260  *
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.
264  *
265  * Example:
266  * SE_GOBJECT_TYPE(GFile)
267  * SE_GOBJECT_TYPE(GObject)
268  * SE_BEGIN_CXX
269  * {
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
275  * }
276  *
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",
281  *                                                                  boost::bind(...));
282  * // Signature is taken from boost::function parameter.
283  * guint handlerID =
284  *     object.connectSignal("notify",
285  *                          boost::function<void (GObject *, GParamSpec *)>(boost::bind(...)));
286  * object.disconnectSignal(handlerID);
287  * SE_END_CXX
288  */
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); } \
292     SE_BEGIN_CXX \
293     typedef TrackGObject<_x> _x ## CXX; \
294     typedef StealGObject<_x> _x ## StealCXX; \
295     SE_END_CXX \
296
297 /**
298  * Defines a CXX smart pointer similar to SE_GOBJECT_TYPE,
299  * but for types which have their own _ref and _unref
300  * calls.
301  *
302  * Example:
303  * SE_GLIB_TYPE(GMainLoop, g_main_loop)
304  */
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); } \
308     SE_BEGIN_CXX \
309     typedef TrackGLib<_x> _x ## CXX; \
310     typedef StealGLib<_x> _x ## StealCXX; \
311     SE_END_CXX
312
313 SE_END_CXX
314
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)
319
320 SE_BEGIN_CXX
321
322 /**
323  * Wrapper around g_file_monitor_file().
324  * Not copyable because monitor is tied to specific callback
325  * via memory address.
326  */
327 class GLibNotify : public boost::noncopyable
328 {
329  public:
330     typedef boost::function<void (GFile *, GFile *, GFileMonitorEvent)> callback_t;
331
332     GLibNotify(const char *file, 
333                const callback_t &callback);
334  private:
335     GFileMonitorCXX m_monitor;
336     callback_t m_callback;
337 };
338
339 /**
340  * Wraps GError. Where a GError** is expected, simply pass
341  * a GErrorCXX instance.
342  */
343 struct GErrorCXX {
344     GError *m_gerror;
345
346     /** empty error, NULL pointer */
347     GErrorCXX() : m_gerror(NULL) {}
348
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) {
353             if (m_gerror) {
354                 g_clear_error(&m_gerror);
355             }
356             if (other.m_gerror) {
357                 m_gerror = g_error_copy(other.m_gerror);
358             }
359         }
360         return *this;
361     }
362     GErrorCXX &operator =(const GError* err) {
363         if (err != m_gerror) {
364             if (m_gerror) {
365                 g_clear_error(&m_gerror);
366             }
367             if (err) {
368                 m_gerror = g_error_copy(err);
369             }
370         }
371         return *this;
372     }
373
374     /** takes over ownership */
375     void take (GError *err) {
376         if (err != m_gerror) {
377             if (m_gerror) {
378                 g_clear_error(&m_gerror);
379             }
380             m_gerror = err;
381         }
382     }
383
384     /** For convenient access to GError members (message, domain, ...) */
385     const GError * operator-> () const { return m_gerror; }
386
387     /**
388      * For passing to C functions. They must not free the GError,
389      * because GErrorCXX retains ownership.
390      */
391     operator const GError * () const { return m_gerror; }
392
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>>"; }
395
396     /** clear error */
397     ~GErrorCXX() { g_clear_error(&m_gerror); }
398
399     /** clear error if any is set */
400     void clear() { g_clear_error(&m_gerror); }
401
402     /** transfer ownership of error back to caller */
403     GError *release() { GError *gerror = m_gerror; m_gerror = NULL; return gerror; }
404
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); }
407
408     /**
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.
413      */
414     operator GError ** () { return &m_gerror; }
415
416     /** true if error set */
417     operator bool () { return m_gerror != NULL; }
418
419     /**
420      * always throws an exception, including information from GError if available:
421      * <action>: <error message>|failure
422      */
423     void throwError(const std::string &action);
424     static void throwError(const std::string &action, const GError *err);
425 };
426
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)); }
430
431 /**
432  * Copies strings from a collection into a newly allocated, NULL
433  * terminated array. Copying the strings is optional. Suggested
434  * usage is:
435  *
436  * C collection;
437  * collection.push_back(...);
438  * boost::scoped_array<char *> array(AllocStringArray(collection));
439  *
440  */
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)
446 {
447     size_t arraySize = strings.size() + 1;
448     const char **array = NULL;
449     array = allocArray ? allocArray(arraySize) : new const char *[arraySize];
450     if (!array) {
451         throw std::bad_alloc();
452     }
453     try {
454         memset(array, 0, sizeof(*array) * arraySize);
455         size_t i = 0;
456         BOOST_FOREACH(const std::string &str, strings) {
457             array[i] = copyString ? copyString(str.c_str()) : str.c_str();
458             if (!array[i]) {
459                 throw std::bad_alloc();
460             }
461             i++;
462         }
463     } catch (...) {
464         if (freeString) {
465             for (const char **ptr = array;
466                  *ptr;
467                  ptr++) {
468                 freeString(const_cast<char *>(*ptr));
469             }
470         }
471         if (freeArray) {
472             freeArray(array);
473         }
474         throw;
475     }
476     return const_cast<char **>(array);
477 }
478
479
480 /**
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.
487  *
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
491  */
492 template< class T, class L, void (*D)(T*) = NoopDestructor<T> > struct GListCXX : boost::noncopyable {
493     L *m_list;
494
495     static void listFree(GSList *l) { g_slist_free(l); }
496     static void listFree(GList *l) { g_list_free(l); }
497
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); }
500
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); }
503
504  public:
505     typedef T * value_type;
506
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) {}
510
511     /** free list */
512     ~GListCXX() { clear(); }
513
514     /** free old content, take owership of new one */
515     void reset(L *list = NULL) {
516         clear();
517         m_list = list;
518     }
519
520     bool empty() { return m_list == NULL; }
521
522     /** clear error if any is set */
523     void clear() {
524 #if 1
525         BOOST_FOREACH(T *entry, *this) {
526             D(entry);
527         }
528 #else
529         for (iterator it = begin();
530              it != end();
531              ++it) {
532             D(*it);
533         }
534 #endif
535         listFree(m_list);
536         m_list = NULL;
537     }
538
539     /**
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).
542      */
543     operator L ** () { return &m_list; }
544
545     /**
546      * Cast to plain G[S]List, for use in functions which do not modify the list.
547      */
548     operator L * () { return m_list; }
549
550     class iterator : public std::iterator<std::forward_iterator_tag, T *> {
551         L *m_entry;
552     public:
553         iterator(L *list) : m_entry(list) {}
554         iterator(const iterator &other) : m_entry(other.m_entry) {}
555         /**
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.
561          */
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; }
568
569     private:
570         /**
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".
575          *
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.
579          */
580         T** getEntryPtr() const { return (T **)&m_entry->data; }
581     };
582     iterator begin() { return iterator(m_list); }
583     iterator end() { return iterator(NULL); }
584
585     class const_iterator : public std::iterator<std::forward_iterator_tag, T *> {
586         L *m_entry;
587         T *m_value;
588
589     public:
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; }
598
599     private:
600         T** getEntryPtr() const { return (T **)&m_entry->data; }
601     };
602
603     const_iterator begin() const { return const_iterator(m_list); }
604     const_iterator end() const { return const_iterator(NULL); }
605
606     void push_back(T *entry) { m_list = listAppend(m_list, entry); }
607     void push_front(T *entry) { m_list = listPrepend(m_list, entry); }
608 };
609
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;
614
615 /**
616  * Wraps a C gchar array and takes care of freeing the memory.
617  */
618 class PlainGStr : public boost::shared_ptr<gchar>
619 {
620     public:
621         PlainGStr() {}
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; }
626 };
627
628 /**
629  * Wraps a glib string array, frees with g_strfreev().
630  */
631 class PlainGStrArray : public boost::shared_ptr<gchar *>
632 {
633     public:
634         PlainGStrArray() {}
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]; }
639  private:
640         // Hide this operator because boost::shared_ptr has problems with it,
641         // probably because of missing traits for a pointer type. Instead use
642         // at().
643         gchar * operator[] (size_t index);
644 };
645
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 {};
652
653 // empty template, need specializations based on arity
654 template<class F, F *finish, int arity> struct GAsyncReadyCXX {};
655
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,
659                         F, finish,
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>
665 {
666 };
667
668 // four parameters
669 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 4> :
670     public GAsyncReady4<typename boost::function_traits<F>::result_type,
671                         F, finish,
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>
676 {
677 };
678
679 // three parameters
680 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 3> :
681     public GAsyncReady3<typename boost::function_traits<F>::result_type,
682                         F, finish,
683                         typename boost::function_traits<F>::arg1_type,
684                         typename boost::function_traits<F>::arg2_type,
685                         typename boost::function_traits<F>::arg3_type>
686 {
687 };
688
689 // two parameters
690 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 2> :
691     public GAsyncReady2<typename boost::function_traits<F>::result_type,
692                         F, finish,
693                         typename boost::function_traits<F>::arg1_type,
694                         typename boost::function_traits<F>::arg2_type>
695 {
696 };
697
698 // one parameter
699 template<class F, F *finish> struct GAsyncReadyCXX<F, finish, 1> :
700     public GAsyncReady1<typename boost::function_traits<F>::result_type,
701                         F, finish,
702                         typename boost::function_traits<F>::arg1_type>
703 {
704 };
705
706
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.
710 //
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>
713 {
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;
718
719     static void handleGLibResult(GObject *sourceObject,
720                                  GAsyncResult *result,
721                                  gpointer userData) throw () {
722         try {
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);
730         } catch (...) {
731             // called from C, must not let exception escape
732             Exception::handle(HANDLE_EXCEPTION_FATAL);
733         }
734     }
735 };
736
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 **>
739 {
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;
743
744     static void handleGLibResult(GObject *sourceObject,
745                                  GAsyncResult *result,
746                                  gpointer userData) throw () {
747         try {
748             GErrorCXX gerror;
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);
755         } catch (...) {
756             // called from C, must not let exception escape
757             Exception::handle(HANDLE_EXCEPTION_FATAL);
758         }
759     }
760 };
761
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>
764 {
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;
768
769     static void handleGLibResult(GObject *sourceObject,
770                                  GAsyncResult *result,
771                                  gpointer userData) throw () {
772         try {
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);
779         } catch (...) {
780             // called from C, must not let exception escape
781             Exception::handle(HANDLE_EXCEPTION_FATAL);
782         }
783     }
784 };
785
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 **>
788 {
789     typedef typename boost::remove_pointer<A3>::type A3_t;
790     typedef boost::function<void (T, A3_t, const GError *)> CXXFunctionCB_t;
791
792     static void handleGLibResult(GObject *sourceObject,
793                                  GAsyncResult *result,
794                                  gpointer userData) throw () {
795         try {
796             GErrorCXX gerror;
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);
802         } catch (...) {
803             // called from C, must not let exception escape
804             Exception::handle(HANDLE_EXCEPTION_FATAL);
805         }
806     }
807 };
808
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;
812
813     static void handleGLibResult(GObject *sourceObject,
814                                  GAsyncResult *result,
815                                  gpointer userData) throw () {
816         try {
817             GErrorCXX gerror;
818             T t = finish(reinterpret_cast<A1>(sourceObject),
819                          result, gerror);
820             std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
821             (*cb)(t, gerror);
822         } catch (...) {
823             // called from C, must not let exception escape
824             Exception::handle(HANDLE_EXCEPTION_FATAL);
825         }
826     }
827 };
828
829 // void = GObject, GAsyncResult, GError
830 template<class F, F *finish, class A1> struct GAsyncReady3<void, F, finish, A1, GAsyncResult *, GError **>
831 {
832     typedef boost::function<void (const GError *)> CXXFunctionCB_t;
833
834     static void handleGLibResult(GObject *sourceObject,
835                                  GAsyncResult *result,
836                                  gpointer userData) throw () {
837         try {
838             GErrorCXX gerror;
839             finish(reinterpret_cast<A1>(sourceObject),
840                    result, gerror);
841             std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
842             (*cb)(gerror);
843         } catch (...) {
844             // called from C, must not let exception escape
845             Exception::handle(HANDLE_EXCEPTION_FATAL);
846         }
847     }
848 };
849
850 // result = GObject, GAsyncResult
851 template<class T, class F, F *finish, class A1> struct GAsyncReady2<T, F, finish, A1, GAsyncResult *>
852 {
853     typedef boost::function<void (T)> CXXFunctionCB_t;
854
855     static void handleGLibResult(GObject *sourceObject,
856                                  GAsyncResult *result,
857                                  gpointer userData) throw () {
858         try {
859             T t = finish(reinterpret_cast<A1>(sourceObject),
860                          result);
861             std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
862             (*cb)(t);
863         } catch (...) {
864             // called from C, must not let exception escape
865             Exception::handle(HANDLE_EXCEPTION_FATAL);
866         }
867     }
868 };
869
870 // result = GAsyncResult, GError
871 template<class T, class F, F *finish> struct GAsyncReady2<T, F, finish, GAsyncResult *, GError **> {
872  public:
873     typedef boost::function<void (T, const GError *)> CXXFunctionCB_t;
874
875     static void handleGLibResult(GObject *sourceObject,
876                                  GAsyncResult *result,
877                                  gpointer userData) throw () {
878         try {
879             GErrorCXX gerror;
880             T t = finish(result, gerror);
881             std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
882             (*cb)(t, gerror);
883         } catch (...) {
884             // called from C, must not let exception escape
885             Exception::handle(HANDLE_EXCEPTION_FATAL);
886         }
887     }
888 };
889
890 // void  = GObject, GAsyncResult
891 template<class F, F *finish, class A1> struct GAsyncReady2<void, F, finish, A1, GAsyncResult *>
892 {
893     typedef boost::function<void ()> CXXFunctionCB_t;
894
895     static void handleGLibResult(GObject *sourceObject,
896                                  GAsyncResult *result,
897                                  gpointer userData) throw () {
898         try {
899             finish(reinterpret_cast<A1>(sourceObject),
900                    result);
901             std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
902             (*cb)();
903         } catch (...) {
904             // called from C, must not let exception escape
905             Exception::handle(HANDLE_EXCEPTION_FATAL);
906         }
907     }
908 };
909
910 // void = GAsyncResult, GError
911 template<class F, F *finish> struct GAsyncReady2<void, F, finish, GAsyncResult *, GError **>
912 {
913     typedef boost::function<void (const GError *)> CXXFunctionCB_t;
914
915     static void handleGLibResult(GObject *sourceObject,
916                                  GAsyncResult *result,
917                                  gpointer userData) throw () {
918         try {
919             GErrorCXX gerror;
920             finish(result, gerror);
921             std::auto_ptr<CXXFunctionCB_t> cb(static_cast<CXXFunctionCB_t *>(userData));
922             (*cb)(gerror);
923         } catch (...) {
924             // called from C, must not let exception escape
925             Exception::handle(HANDLE_EXCEPTION_FATAL);
926         }
927     }
928 };
929
930 /**
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
933  */
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 >
938
939 /**
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.
943  *
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
951  *   be freed.
952  *
953  * Other parameters must be freed if required by the _finish semantic.
954  *
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.
958  *
959  * Example:
960  *
961  *  static void asyncCB(const GError *gerror, const char *func, bool &failed, bool &done) {
962  *      done = true;
963  *      if (gerror) {
964  *          failed = true;
965  *          // log gerror->message or store in GErrorCXX
966  *      }
967  *  }
968  *
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)),
974  *                          aggregator);
975  *
976  *  // Don't continue unless finished, because the callback will write
977  *  // into "done" and possibly "failed".
978  *  while (!done) {
979  *      g_main_context_iteration(NULL, true);
980  *  }
981  *
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
987  */
988 #define SYNCEVO_GLIB_CALL_ASYNC(_prepare, _cb, _args...) \
989     _prepare(_args, \
990              SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare)::handleGLibResult, \
991              new SYNCEVO_GLIB_CALL_ASYNC_CXX(_prepare)::CXXFunctionCB_t(_cb))
992
993 // helper class for finish method with some kind of result other than void
994 template<class T> class GAsyncReadyDoneCXX
995 {
996  public:
997     template<class R> static void storeResult(GErrorCXX &gerrorStorage,
998                                               R &resultStorage,
999                                               bool &done,
1000                                               T result,
1001                                               const GError *gerror) {
1002         done = true;
1003         gerrorStorage = gerror;
1004         resultStorage = result;
1005     }
1006
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);
1009     }
1010 };
1011
1012 // helper class for finish method with void result
1013 template<> class GAsyncReadyDoneCXX<void>
1014 {
1015  public:
1016     static void storeResult(GErrorCXX &gerrorStorage,
1017                             bool &done,
1018                             const GError *gerror) {
1019         done = true;
1020         gerrorStorage = gerror;
1021     }
1022
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);
1025     }
1026 };
1027
1028 /**
1029  * Like SYNCEVO_GLIB_CALL_ASYNC, but blocks until the operation
1030  * has finished.
1031  *
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
1035  */
1036 #define SYNCEVO_GLIB_CALL_SYNC(_res, _gerror, _prepare, _args...) \
1037     do { \
1038         bool done = false; \
1039         SYNCEVO_GLIB_CALL_ASYNC(_prepare, \
1040                                 GAsyncReadyDoneCXX<boost::function<typeof(_prepare ## _finish)>::result_type>::createCB(_res, _gerror, done), \
1041                                 _args); \
1042         GRunWhile(! boost::lambda::var(done)); \
1043     } while (false); \
1044
1045
1046 /**
1047  * Process events in the default context while the callback returns
1048  * true.
1049  *
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.
1056  *
1057  * The main thread must also be running GRunWhile().
1058  *
1059  * Exceptions in the check code are fatal and should be avoided.
1060  */
1061 void GRunWhile(const boost::function<bool ()> &check);
1062
1063 #endif // HAVE_GLIB
1064
1065 SE_END_CXX
1066
1067 #endif // INCL_GLIB_SUPPORT
1068