2005-01-30 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / glib / dbus-gmain.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gmain.c GLib main loop integration
3  *
4  * Copyright (C) 2002, 2003 CodeFactory AB
5  * Copyright (C) 2005 Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 2.1
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include <config.h>
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28 #include "dbus-gtest.h"
29 #include "dbus-gutils.h"
30
31 #include <libintl.h>
32 #define _(x) dgettext (GETTEXT_PACKAGE, x)
33 #define N_(x) x
34
35 /**
36  * @defgroup DBusGLib GLib bindings
37  * @brief API for using D-BUS with GLib
38  *
39  * libdbus proper is a low-level API, these GLib bindings wrap libdbus
40  * with a much higher-level approach. The higher level approach is
41  * possible because GLib defines a main loop, an object/type system,
42  * and an out-of-memory handling policy (it exits the program).
43  * See http://www.gtk.org for GLib information.
44  *
45  * To manipulate remote objects, use #DBusGProxy.
46  */
47
48 /**
49  * @defgroup DBusGLibInternals GLib bindings implementation details
50  * @ingroup  DBusInternals
51  * @brief Implementation details of GLib bindings
52  *
53  * @{
54  */
55
56 /** @typedef DBusGSource
57  * A GSource representing a #DBusConnection or #DBusServer
58  */
59 typedef struct DBusGSource DBusGSource;
60
61 /**
62  * A GSource subclass for a DBusConnection.
63  */
64 struct DBusGSource
65 {
66   GSource source; /**< the parent GSource */
67
68   GList *watch_fds;      /**< descriptors we're watching */
69
70   GMainContext *context; /**< the GMainContext to use, NULL for default */
71
72   void *connection_or_server; /**< DBusConnection or DBusServer */
73 };
74
75 /**
76  * Auxillary struct for pairing up a #DBusWatch and associated
77  * #GPollFD
78  */
79 typedef struct
80 {
81   int refcount;     /**< reference count */
82
83   GPollFD poll_fd;  /**< the #GPollFD to use with g_source_add_poll() */
84   DBusWatch *watch; /**< the corresponding DBusWatch*/
85   
86   unsigned int removed : 1; /**< true if this #WatchFD has been removed */
87 } WatchFD;
88
89 static WatchFD *
90 watch_fd_new (void)
91 {
92   WatchFD *watch_fd;
93
94   watch_fd = g_new0 (WatchFD, 1);
95   watch_fd->refcount = 1;
96
97   return watch_fd;
98 }
99
100 static WatchFD * 
101 watch_fd_ref (WatchFD *watch_fd)
102 {
103   g_assert (watch_fd->refcount > 0);
104   
105   watch_fd->refcount += 1;
106
107   return watch_fd;
108 }
109
110 static void
111 watch_fd_unref (WatchFD *watch_fd)
112 {
113   g_assert (watch_fd->refcount > 0);
114   
115   watch_fd->refcount -= 1;
116
117   if (watch_fd->refcount == 0)
118     {
119       g_assert (watch_fd->removed);
120   
121       g_free (watch_fd);
122     }
123 }
124
125 static dbus_int32_t connection_slot = -1;
126 static dbus_int32_t server_slot = -1;
127
128 static gboolean gsource_connection_prepare  (GSource     *source,
129                                              gint        *timeout);
130 static gboolean gsource_connection_check    (GSource     *source);
131 static gboolean gsource_connection_dispatch (GSource     *source,
132                                              GSourceFunc  callback,
133                                              gpointer     user_data);
134 static void     gsource_connection_finalize (GSource     *source);
135 static gboolean gsource_server_prepare      (GSource     *source,
136                                              gint        *timeout);
137 static gboolean gsource_server_check        (GSource     *source);
138 static gboolean gsource_server_dispatch     (GSource     *source,
139                                              GSourceFunc  callback,
140                                              gpointer     user_data);
141 static void     gsource_server_finalize     (GSource     *source);
142
143 static GSourceFuncs dbus_connection_funcs = {
144   gsource_connection_prepare,
145   gsource_connection_check,
146   gsource_connection_dispatch,
147   gsource_connection_finalize
148 };
149
150 static GSourceFuncs dbus_server_funcs = {
151   gsource_server_prepare,
152   gsource_server_check,
153   gsource_server_dispatch,
154   gsource_server_finalize
155 };
156
157 static gboolean
158 gsource_connection_prepare (GSource *source,
159                             gint    *timeout)
160 {
161   DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
162   
163   *timeout = -1;
164
165   return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
166 }
167
168 static gboolean
169 gsource_server_prepare (GSource *source,
170                         gint    *timeout)
171 {
172   *timeout = -1;
173
174   return FALSE;
175 }
176
177 static gboolean
178 dbus_gsource_check (GSource *source)
179 {
180   DBusGSource *dbus_source = (DBusGSource *)source;
181   GList *list;
182
183   list = dbus_source->watch_fds;
184
185   while (list)
186     {
187       WatchFD *watch_fd = list->data;
188
189       if (watch_fd->poll_fd.revents != 0)
190         return TRUE;
191
192       list = list->next;
193     }
194
195   return FALSE;  
196 }
197
198 static gboolean
199 gsource_connection_check (GSource *source)
200 {
201   return dbus_gsource_check (source);
202 }
203
204 static gboolean
205 gsource_server_check (GSource *source)
206 {
207   return dbus_gsource_check (source);
208 }
209
210 static gboolean
211 dbus_gsource_dispatch (GSource     *source,
212                        GSourceFunc  callback,
213                        gpointer     user_data,
214                        dbus_bool_t  is_server)
215 {
216    DBusGSource *dbus_source = (DBusGSource *)source;
217    GList *copy, *list;
218
219    /* Make a copy of the list and ref all WatchFDs */
220    copy = g_list_copy (dbus_source->watch_fds);
221    g_list_foreach (copy, (GFunc)watch_fd_ref, NULL);
222    
223    list = copy;
224    while (list)
225      {
226        WatchFD *watch_fd = list->data;
227
228        if (!watch_fd->removed && watch_fd->poll_fd.revents != 0)
229          {
230            guint condition = 0;
231            
232            if (watch_fd->poll_fd.revents & G_IO_IN)
233              condition |= DBUS_WATCH_READABLE;
234            if (watch_fd->poll_fd.revents & G_IO_OUT)
235              condition |= DBUS_WATCH_WRITABLE;
236            if (watch_fd->poll_fd.revents & G_IO_ERR)
237              condition |= DBUS_WATCH_ERROR;
238            if (watch_fd->poll_fd.revents & G_IO_HUP)
239              condition |= DBUS_WATCH_HANGUP;
240
241            dbus_watch_handle (watch_fd->watch, condition);
242          }
243
244        list = list->next;
245      }
246
247    g_list_foreach (copy, (GFunc)watch_fd_unref, NULL);   
248    g_list_free (copy);   
249
250    return TRUE;
251 }
252
253 static gboolean
254 gsource_connection_dispatch (GSource     *source,
255                              GSourceFunc  callback,
256                              gpointer     user_data)
257 {
258   DBusGSource *dbus_source = (DBusGSource *)source;
259   DBusConnection *connection = dbus_source->connection_or_server;
260
261   dbus_connection_ref (connection);
262
263   dbus_gsource_dispatch (source, callback, user_data,
264                          FALSE);
265   
266   /* Dispatch messages */
267   while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS)
268     ;
269
270    dbus_connection_unref (connection);
271    
272    return TRUE;
273 }
274
275 static gboolean
276 gsource_server_dispatch (GSource     *source,
277                          GSourceFunc  callback,
278                          gpointer     user_data)
279 {
280   DBusGSource *dbus_source = (DBusGSource *)source;
281   DBusServer *server = dbus_source->connection_or_server;
282
283   dbus_server_ref (server);
284
285   dbus_gsource_dispatch (source, callback, user_data,
286                          TRUE);
287
288   dbus_server_unref (server);
289    
290   return TRUE;
291 }
292      
293 static dbus_bool_t
294 add_watch (DBusWatch *watch,
295            gpointer   data)
296 {
297   WatchFD *watch_fd;
298   DBusGSource *dbus_source;
299   guint flags;
300
301   if (!dbus_watch_get_enabled (watch))
302     return TRUE;
303
304   g_assert (dbus_watch_get_data (watch) == NULL);
305   
306   dbus_source = data;
307
308   watch_fd = watch_fd_new ();
309   watch_fd->poll_fd.fd = dbus_watch_get_fd (watch);
310   watch_fd->poll_fd.events = 0;
311   flags = dbus_watch_get_flags (watch);
312   dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref);
313
314   if (flags & DBUS_WATCH_READABLE)
315     watch_fd->poll_fd.events |= G_IO_IN;
316   if (flags & DBUS_WATCH_WRITABLE)
317     watch_fd->poll_fd.events |= G_IO_OUT;
318   watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP;
319
320   watch_fd->watch = watch;
321   
322   g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
323
324   dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd);
325   g_assert (!watch_fd->removed);
326
327   return TRUE;
328 }
329
330 static void
331 source_remove_watch_fd (DBusGSource *dbus_source,
332                         WatchFD     *watch_fd)
333 {
334   g_assert (g_list_find (dbus_source->watch_fds, watch_fd) != NULL);
335   g_assert (!watch_fd->removed);
336
337   watch_fd_ref (watch_fd);
338   
339   watch_fd->removed = TRUE;
340   dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd);
341
342   g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
343
344   g_assert (watch_fd->watch != NULL);
345   dbus_watch_set_data (watch_fd->watch, NULL, NULL); /* needed due to watch_toggled
346                                                       * breaking add/remove symmetry
347                                                       */
348
349   watch_fd->watch = NULL;
350
351   watch_fd_unref (watch_fd);
352 }
353
354 static void
355 remove_watch (DBusWatch *watch,
356               gpointer   data)
357 {
358   DBusGSource *dbus_source = data;
359   WatchFD *watch_fd;
360   
361   watch_fd = dbus_watch_get_data (watch);
362   if (watch_fd == NULL)
363     return; /* probably a not-enabled watch that was added,
364              * or the source has been finalized
365              */
366
367   g_assert (watch_fd->watch == watch);
368
369   source_remove_watch_fd (dbus_source, watch_fd);
370 }
371
372 static void
373 watch_toggled (DBusWatch *watch,
374                void      *data)
375 {
376   /* Because we just exit on OOM, enable/disable is
377    * no different from add/remove
378    */
379   if (dbus_watch_get_enabled (watch))
380     add_watch (watch, data);
381   else
382     remove_watch (watch, data);
383 }
384
385 static gboolean
386 timeout_handler (gpointer data)
387 {
388   DBusTimeout *timeout = data;
389
390   dbus_timeout_handle (timeout);
391
392   return TRUE;
393 }
394
395 static dbus_bool_t
396 add_timeout (DBusTimeout *timeout,
397              void        *data)
398 {
399   GSource *source;
400   GMainContext *context;
401
402   context = data;
403   
404   if (!dbus_timeout_get_enabled (timeout))
405     return TRUE;
406   
407   source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
408   g_source_set_callback (source, timeout_handler, timeout, NULL);
409   g_source_attach (source, context);
410   
411   dbus_timeout_set_data (timeout, GUINT_TO_POINTER (g_source_get_id (source)),
412                          NULL);
413
414   return TRUE;
415 }
416
417 static void
418 remove_timeout (DBusTimeout *timeout,
419                 void        *data)
420 {
421   guint timeout_tag;
422   
423   timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
424
425   if (timeout_tag != 0) /* if 0, probably timeout was disabled */
426     g_source_remove (timeout_tag);
427 }
428
429 static void
430 timeout_toggled (DBusTimeout *timeout,
431                  void        *data)
432 {
433   /* Because we just exit on OOM, enable/disable is
434    * no different from add/remove
435    */
436   if (dbus_timeout_get_enabled (timeout))
437     add_timeout (timeout, data);
438   else
439     remove_timeout (timeout, data);
440 }
441
442
443 static void
444 free_source (GSource *source)
445 {  
446   g_source_destroy (source);
447 }
448
449 static void
450 wakeup_main (void *data)
451 {
452   DBusGSource *dbus_source = data;
453
454   g_main_context_wakeup (dbus_source->context);
455 }
456
457 static void
458 remove_all_watch_fd (DBusGSource *dbus_source)
459 {
460   while (dbus_source->watch_fds)
461     {
462       WatchFD *watch_fd = dbus_source->watch_fds->data;
463
464       g_assert (!watch_fd->removed); /* should not be in the list if removed */
465       source_remove_watch_fd (dbus_source, watch_fd);
466     }
467 }
468
469 static void
470 gsource_connection_finalize (GSource *source)
471 {
472   DBusGSource *dbus_source = (DBusGSource *)source;
473
474   remove_all_watch_fd (dbus_source);
475 }
476
477 static void
478 gsource_server_finalize (GSource *source)
479 {
480   DBusGSource *dbus_source = (DBusGSource *)source;
481
482   remove_all_watch_fd (dbus_source);
483 }
484
485 /** @} */ /* End of GLib bindings internals */
486
487 /** @addtogroup DBusGLib
488  * @{
489  */
490
491 static GSource*
492 create_source (void         *connection_or_server,
493                GSourceFuncs *funcs,
494                GMainContext *context)
495 {
496   GSource *source;
497   DBusGSource *dbus_source;
498
499   source = g_source_new (funcs, sizeof (DBusGSource));
500   
501   dbus_source = (DBusGSource *)source;  
502   dbus_source->connection_or_server = connection_or_server;
503   dbus_source->context = context;
504
505   return source;
506 }
507
508 /**
509  * Sets the watch and timeout functions of a #DBusConnection
510  * to integrate the connection with the GLib main loop.
511  * Pass in #NULL for the #GMainContext unless you're
512  * doing something specialized.
513  *
514  * If called twice for the same context, does nothing the second
515  * time. If called once with context A and once with context B,
516  * context B replaces context A as the context monitoring the
517  * connection.
518  *
519  * @param connection the connection
520  * @param context the #GMainContext or #NULL for default context
521  */
522 void
523 dbus_connection_setup_with_g_main (DBusConnection *connection,
524                                    GMainContext   *context)
525 {
526   GSource *source;
527   
528   /* FIXME we never free the slot, so its refcount just keeps growing,
529    * which is kind of broken.
530    */
531   dbus_connection_allocate_data_slot (&connection_slot);
532   if (connection_slot < 0)
533     goto nomem;
534
535   /* So we can test for equality below */
536   if (context == NULL)
537     context = g_main_context_default ();
538   
539   source = dbus_connection_get_data (connection, connection_slot);
540   if (source != NULL)
541     {
542       if (source->context == context)
543         return; /* nothing to do */
544
545       /* Remove the previous source and move to a new context */
546       dbus_connection_set_data (connection, connection_slot, NULL, NULL);
547       source = NULL;
548     }
549   
550   source = create_source (connection, &dbus_connection_funcs, context);
551
552   if (!dbus_connection_set_watch_functions (connection,
553                                             add_watch,
554                                             remove_watch,
555                                             watch_toggled,
556                                             source, NULL))
557     goto nomem;
558
559   if (!dbus_connection_set_timeout_functions (connection,
560                                               add_timeout,
561                                               remove_timeout,
562                                               timeout_toggled,
563                                               context, NULL))
564     goto nomem;
565     
566   dbus_connection_set_wakeup_main_function (connection,
567                                             wakeup_main,
568                                             source, NULL);
569       
570   g_source_attach (source, context);
571
572   if (!dbus_connection_set_data (connection, connection_slot, source,
573                                  (DBusFreeFunction)free_source))
574     goto nomem;
575
576   return;
577
578  nomem:
579   g_error ("Not enough memory to set up DBusConnection for use with GLib");
580 }
581
582 /**
583  * Sets the watch and timeout functions of a #DBusServer
584  * to integrate the server with the GLib main loop.
585  * In most cases the context argument should be #NULL.
586  *
587  * If called twice for the same context, does nothing the second
588  * time. If called once with context A and once with context B,
589  * context B replaces context A as the context monitoring the
590  * connection.
591  *
592  * @param server the server
593  * @param context the #GMainContext or #NULL for default
594  */
595 void
596 dbus_server_setup_with_g_main (DBusServer   *server,
597                                GMainContext *context)
598 {
599   GSource *source;
600
601   dbus_server_allocate_data_slot (&server_slot);
602   if (server_slot < 0)
603     goto nomem;
604
605   /* So we can test for equality below */
606   if (context == NULL)
607     context = g_main_context_default ();
608   
609   source = dbus_server_get_data (server, server_slot);
610   if (source != NULL)
611     {
612       if (source->context == context)
613         return; /* nothing to do */
614
615       /* Remove the previous source and move to a new context */
616       dbus_server_set_data (server, server_slot, NULL, NULL);
617       source = NULL;
618     }
619   
620   source = create_source (server, &dbus_server_funcs, context);
621
622   dbus_server_set_watch_functions (server,
623                                    add_watch,
624                                    remove_watch,
625                                    watch_toggled,
626                                    source, NULL);
627
628   dbus_server_set_timeout_functions (server,
629                                      add_timeout,
630                                      remove_timeout,
631                                      timeout_toggled,
632                                      context, NULL);
633   
634   g_source_attach (source, context);
635
636   if (!dbus_server_set_data (server, server_slot, source,
637                              (DBusFreeFunction)free_source))
638     goto nomem;
639
640   return;
641
642  nomem:
643   g_error ("Not enough memory to set up DBusServer for use with GLib");
644 }
645
646 /**
647  * Returns a connection to the given bus. The connection is a global variable
648  * shared with other callers of this function.
649  * 
650  * (Internally, calls dbus_bus_get() then calls
651  * dbus_connection_setup_with_g_main() on the result.)
652  *
653  * @param type bus type
654  * @param error address where an error can be returned.
655  * @returns a DBusConnection
656  */
657 DBusGConnection*
658 dbus_g_bus_get (DBusBusType     type,
659                 GError        **error)
660 {
661   DBusConnection *connection;
662   DBusError derror;
663
664   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
665   
666   dbus_error_init (&derror);
667
668   connection = dbus_bus_get (type, &derror);
669   if (connection == NULL)
670     {
671       dbus_set_g_error (error, &derror);
672       dbus_error_free (&derror);
673       return NULL;
674     }
675
676   /* does nothing if it's already been done */
677   dbus_connection_setup_with_g_main (connection, NULL);
678
679   return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
680 }
681
682 /**
683  * The implementation of DBUS_GERROR error domain. See documentation
684  * for GError in GLib reference manual.
685  *
686  * @returns the error domain quark for use with GError
687  */
688 GQuark
689 dbus_g_error_quark (void)
690 {
691   static GQuark quark = 0;
692   if (quark == 0)
693     quark = g_quark_from_static_string ("g-exec-error-quark");
694   return quark;
695 }
696
697
698 /**
699  * Set a GError return location from a DBusError.
700  *
701  * @todo expand the DBUS_GERROR enum and take advantage of it here
702  * 
703  * @param gerror location to store a GError, or #NULL
704  * @param derror the DBusError
705  */
706 void
707 dbus_set_g_error (GError   **gerror,
708                   DBusError *derror)
709 {
710   g_return_if_fail (derror != NULL);
711   g_return_if_fail (dbus_error_is_set (derror));
712   
713   g_set_error (gerror, DBUS_GERROR,
714                DBUS_GERROR_FAILED,
715                _("D-BUS error %s: %s"),
716                derror->name, derror->message);  
717 }
718
719 /**
720  * Get the GLib type ID for a DBusConnection boxed type.
721  *
722  * @returns GLib type
723  */
724 GType
725 dbus_connection_get_g_type (void)
726 {
727   static GType our_type = 0;
728   
729   if (our_type == 0)
730     our_type = g_boxed_type_register_static ("DBusConnection",
731                                              (GBoxedCopyFunc) dbus_connection_ref,
732                                              (GBoxedFreeFunc) dbus_connection_unref);
733
734   return our_type;
735 }
736
737 /**
738  * Get the GLib type ID for a DBusMessage boxed type.
739  *
740  * @returns GLib type
741  */
742 GType
743 dbus_message_get_g_type (void)
744 {
745   static GType our_type = 0;
746   
747   if (our_type == 0)
748     our_type = g_boxed_type_register_static ("DBusMessage",
749                                              (GBoxedCopyFunc) dbus_message_ref,
750                                              (GBoxedFreeFunc) dbus_message_unref);
751
752   return our_type;
753 }
754
755 static DBusGConnection*
756 dbus_g_connection_ref (DBusGConnection *gconnection)
757 {
758   DBusConnection *c;
759
760   c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
761   dbus_connection_ref (c);
762   return gconnection;
763 }
764
765 static void
766 dbus_g_connection_unref (DBusGConnection *gconnection)
767 {
768   DBusConnection *c;
769
770   c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
771   dbus_connection_unref (c);
772 }
773
774
775 static DBusGMessage*
776 dbus_g_message_ref (DBusGMessage *gmessage)
777 {
778   DBusMessage *c;
779
780   c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
781   dbus_message_ref (c);
782   return gmessage;
783 }
784
785 static void
786 dbus_g_message_unref (DBusGMessage *gmessage)
787 {
788   DBusMessage *c;
789
790   c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
791   dbus_message_unref (c);
792 }
793
794 /**
795  * Get the GLib type ID for a DBusGConnection boxed type.
796  *
797  * @returns GLib type
798  */
799 GType
800 dbus_g_connection_get_g_type (void)
801 {
802   static GType our_type = 0;
803   
804   if (our_type == 0)
805     our_type = g_boxed_type_register_static ("DBusGConnection",
806                                              (GBoxedCopyFunc) dbus_g_connection_ref,
807                                              (GBoxedFreeFunc) dbus_g_connection_unref);
808
809   return our_type;
810 }
811
812 /**
813  * Get the GLib type ID for a DBusGMessage boxed type.
814  *
815  * @returns GLib type
816  */
817 GType
818 dbus_g_message_get_g_type (void)
819 {
820   static GType our_type = 0;
821   
822   if (our_type == 0)
823     our_type = g_boxed_type_register_static ("DBusGMessage",
824                                              (GBoxedCopyFunc) dbus_g_message_ref,
825                                              (GBoxedFreeFunc) dbus_g_message_unref);
826
827   return our_type;
828 }
829
830 /**
831  * Get the DBusConnection corresponding to this DBusGConnection.
832  * The return value does not have its refcount incremented.
833  *
834  * @returns DBusConnection 
835  */
836 DBusConnection*
837 dbus_g_connection_get_connection (DBusGConnection *gconnection)
838 {
839   return DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
840 }
841
842 /**
843  * Get the DBusMessage corresponding to this DBusGMessage.
844  * The return value does not have its refcount incremented.
845  *
846  * @returns DBusMessage 
847  */
848 DBusMessage*
849 dbus_g_message_get_message (DBusGMessage *gmessage)
850 {
851   return DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
852 }
853
854 /** @} */ /* end of public API */
855
856 #ifdef DBUS_BUILD_TESTS
857
858 /**
859  * @ingroup DBusGLibInternals
860  * Unit test for GLib main loop integration
861  * @returns #TRUE on success.
862  */
863 gboolean
864 _dbus_gmain_test (const char *test_data_dir)
865 {
866   
867   return TRUE;
868 }
869
870 #endif /* DBUS_BUILD_TESTS */