dbus-gmain.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gmain.c GLib main loop integration
00003  *
00004  * Copyright (C) 2002, 2003 CodeFactory AB
00005  * Copyright (C) 2005 Red Hat, Inc.
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include <dbus/dbus-glib.h>
00027 #include <dbus/dbus-glib-lowlevel.h>
00028 #include "dbus-gtest.h"
00029 #include "dbus-gutils.h"
00030 #include "dbus-gvalue.h"
00031 #include "dbus-gobject.h"
00032 #include "dbus-gvalue-utils.h"
00033 #include "dbus-gsignature.h"
00034 #include <string.h>
00035 
00036 #include <libintl.h>
00037 #define _(x) dgettext (GETTEXT_PACKAGE, x)
00038 #define N_(x) x
00039 
00054 typedef struct
00055 {
00056   GSource source; 
00057   DBusConnection *connection; 
00058 } DBusGMessageQueue;
00059 
00060 static gboolean message_queue_prepare  (GSource     *source,
00061                                         gint        *timeout);
00062 static gboolean message_queue_check    (GSource     *source);
00063 static gboolean message_queue_dispatch (GSource     *source,
00064                                         GSourceFunc  callback,
00065                                         gpointer     user_data);
00066 
00067 static const GSourceFuncs message_queue_funcs = {
00068   message_queue_prepare,
00069   message_queue_check,
00070   message_queue_dispatch,
00071   NULL
00072 };
00073 
00074 static gboolean
00075 message_queue_prepare (GSource *source,
00076                        gint    *timeout)
00077 {
00078   DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
00079   
00080   *timeout = -1;
00081 
00082   return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
00083 }
00084 
00085 static gboolean
00086 message_queue_check (GSource *source)
00087 {
00088   return FALSE;
00089 }
00090 
00091 static gboolean
00092 message_queue_dispatch (GSource     *source,
00093                         GSourceFunc  callback,
00094                         gpointer     user_data)
00095 {
00096   DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
00097 
00098   dbus_connection_ref (connection);
00099 
00100   /* Only dispatch once - we don't want to starve other GSource */
00101   dbus_connection_dispatch (connection);
00102   
00103   dbus_connection_unref (connection);
00104 
00105   return TRUE;
00106 }
00107 
00108 typedef struct
00109 {
00110   GMainContext *context;      
00111   GSList *ios;                
00112   GSList *timeouts;           
00113   DBusConnection *connection; 
00114   GSource *message_queue_source; 
00115 } ConnectionSetup;
00116 
00117 
00118 typedef struct
00119 {
00120   ConnectionSetup *cs;
00121   GSource *source;
00122   DBusWatch *watch;
00123 } IOHandler;
00124 
00125 typedef struct
00126 {
00127   ConnectionSetup *cs;
00128   GSource *source;
00129   DBusTimeout *timeout;
00130 } TimeoutHandler;
00131 
00132 dbus_int32_t _dbus_gmain_connection_slot = -1;
00133 static dbus_int32_t server_slot = -1;
00134 
00135 static ConnectionSetup*
00136 connection_setup_new (GMainContext   *context,
00137                       DBusConnection *connection)
00138 {
00139   ConnectionSetup *cs;
00140 
00141   cs = g_new0 (ConnectionSetup, 1);
00142 
00143   g_assert (context != NULL);
00144   
00145   cs->context = context;
00146   g_main_context_ref (cs->context);  
00147 
00148   if (connection)
00149     {
00150       cs->connection = connection;
00151 
00152       cs->message_queue_source = g_source_new ((GSourceFuncs *) &message_queue_funcs,
00153                                                sizeof (DBusGMessageQueue));
00154       ((DBusGMessageQueue*)cs->message_queue_source)->connection = connection;
00155       g_source_attach (cs->message_queue_source, cs->context);
00156       g_source_set_priority (cs->message_queue_source, G_PRIORITY_HIGH);
00157     }
00158   
00159   return cs;
00160 }
00161 
00162 static void
00163 io_handler_source_finalized (gpointer data)
00164 {
00165   IOHandler *handler;
00166 
00167   handler = data;
00168 
00169   if (handler->watch)
00170     dbus_watch_set_data (handler->watch, NULL, NULL);
00171   
00172   g_free (handler);
00173 }
00174 
00175 static void
00176 io_handler_destroy_source (void *data)
00177 {
00178   IOHandler *handler;
00179 
00180   handler = data;
00181 
00182   if (handler->source)
00183     {
00184       GSource *source = handler->source;
00185       handler->source = NULL;
00186       handler->cs->ios = g_slist_remove (handler->cs->ios, handler);
00187       g_source_destroy (source);
00188       g_source_unref (source);
00189     }
00190 }
00191 
00192 static void
00193 io_handler_watch_freed (void *data)
00194 {
00195   IOHandler *handler;
00196 
00197   handler = data;
00198 
00199   handler->watch = NULL;
00200 
00201   io_handler_destroy_source (handler);
00202 }
00203 
00204 static gboolean
00205 io_handler_dispatch (GIOChannel   *source,
00206                      GIOCondition  condition,
00207                      gpointer      data)
00208 {
00209   IOHandler *handler;
00210   guint dbus_condition = 0;
00211   DBusConnection *connection;
00212 
00213   handler = data;
00214 
00215   connection = handler->cs->connection;
00216   
00217   if (connection)
00218     dbus_connection_ref (connection);
00219   
00220   if (condition & G_IO_IN)
00221     dbus_condition |= DBUS_WATCH_READABLE;
00222   if (condition & G_IO_OUT)
00223     dbus_condition |= DBUS_WATCH_WRITABLE;
00224   if (condition & G_IO_ERR)
00225     dbus_condition |= DBUS_WATCH_ERROR;
00226   if (condition & G_IO_HUP)
00227     dbus_condition |= DBUS_WATCH_HANGUP;
00228 
00229   /* Note that we don't touch the handler after this, because
00230    * dbus may have disabled the watch and thus killed the
00231    * handler.
00232    */
00233   dbus_watch_handle (handler->watch, dbus_condition);
00234   handler = NULL;
00235 
00236   if (connection)
00237     dbus_connection_unref (connection);
00238   
00239   return TRUE;
00240 }
00241 
00242 static void
00243 connection_setup_add_watch (ConnectionSetup *cs,
00244                             DBusWatch       *watch)
00245 {
00246   guint flags;
00247   GIOCondition condition;
00248   GIOChannel *channel;
00249   IOHandler *handler;
00250   
00251   if (!dbus_watch_get_enabled (watch))
00252     return;
00253   
00254   g_assert (dbus_watch_get_data (watch) == NULL);
00255   
00256   flags = dbus_watch_get_flags (watch);
00257 
00258   condition = G_IO_ERR | G_IO_HUP;
00259   if (flags & DBUS_WATCH_READABLE)
00260     condition |= G_IO_IN;
00261   if (flags & DBUS_WATCH_WRITABLE)
00262     condition |= G_IO_OUT;
00263 
00264   handler = g_new0 (IOHandler, 1);
00265   handler->cs = cs;
00266   handler->watch = watch;
00267   
00268   channel = g_io_channel_unix_new (dbus_watch_get_fd (watch));
00269   
00270   handler->source = g_io_create_watch (channel, condition);
00271   g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
00272                          io_handler_source_finalized);
00273   g_source_attach (handler->source, cs->context);
00274   g_source_set_priority (handler->source, G_PRIORITY_HIGH);
00275 
00276   cs->ios = g_slist_prepend (cs->ios, handler);
00277   
00278   dbus_watch_set_data (watch, handler, io_handler_watch_freed);
00279   g_io_channel_unref (channel);
00280 }
00281 
00282 static void
00283 connection_setup_remove_watch (ConnectionSetup *cs,
00284                                DBusWatch       *watch)
00285 {
00286   IOHandler *handler;
00287 
00288   handler = dbus_watch_get_data (watch);
00289 
00290   if (handler == NULL)
00291     return;
00292   
00293   io_handler_destroy_source (handler);
00294 }
00295 
00296 static void
00297 timeout_handler_source_finalized (gpointer data)
00298 {
00299   TimeoutHandler *handler;
00300 
00301   handler = data;
00302 
00303   if (handler->timeout)
00304     dbus_timeout_set_data (handler->timeout, NULL, NULL);
00305   
00306   g_free (handler);
00307 }
00308 
00309 static void
00310 timeout_handler_destroy_source (void *data)
00311 {
00312   TimeoutHandler *handler;
00313 
00314   handler = data;
00315 
00316   if (handler->source)
00317     {
00318       GSource *source = handler->source;
00319       handler->source = NULL;
00320       handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
00321       g_source_destroy (source);
00322       g_source_unref (source);
00323     }
00324 }
00325 
00326 static void
00327 timeout_handler_timeout_freed (void *data)
00328 {
00329   TimeoutHandler *handler;
00330 
00331   handler = data;
00332 
00333   handler->timeout = NULL;
00334 
00335   timeout_handler_destroy_source (handler);
00336 }
00337 
00338 static gboolean
00339 timeout_handler_dispatch (gpointer      data)
00340 {
00341   TimeoutHandler *handler;
00342 
00343   handler = data;
00344 
00345   dbus_timeout_handle (handler->timeout);
00346   
00347   return TRUE;
00348 }
00349 
00350 static void
00351 connection_setup_add_timeout (ConnectionSetup *cs,
00352                               DBusTimeout     *timeout)
00353 {
00354   TimeoutHandler *handler;
00355   
00356   if (!dbus_timeout_get_enabled (timeout))
00357     return;
00358   
00359   g_assert (dbus_timeout_get_data (timeout) == NULL);
00360 
00361   handler = g_new0 (TimeoutHandler, 1);
00362   handler->cs = cs;
00363   handler->timeout = timeout;
00364 
00365   handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
00366   g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
00367                          timeout_handler_source_finalized);
00368   g_source_attach (handler->source, handler->cs->context);
00369 
00370   cs->timeouts = g_slist_prepend (cs->timeouts, handler);
00371 
00372   dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
00373 }
00374 
00375 static void
00376 connection_setup_remove_timeout (ConnectionSetup *cs,
00377                                  DBusTimeout       *timeout)
00378 {
00379   TimeoutHandler *handler;
00380   
00381   handler = dbus_timeout_get_data (timeout);
00382 
00383   if (handler == NULL)
00384     return;
00385   
00386   timeout_handler_destroy_source (handler);
00387 }
00388 
00389 static void
00390 connection_setup_free (ConnectionSetup *cs)
00391 {
00392   while (cs->ios)
00393     io_handler_destroy_source (cs->ios->data);
00394 
00395   while (cs->timeouts)
00396     timeout_handler_destroy_source (cs->timeouts->data);
00397 
00398   if (cs->message_queue_source)
00399     {
00400       GSource *source;
00401 
00402       source = cs->message_queue_source;
00403       cs->message_queue_source = NULL;
00404 
00405       g_source_destroy (source);
00406       g_source_unref (source);
00407     }
00408   
00409   g_main_context_unref (cs->context);
00410   g_free (cs);
00411 }
00412 
00413 static dbus_bool_t
00414 add_watch (DBusWatch *watch,
00415            gpointer   data)
00416 {
00417   ConnectionSetup *cs;
00418 
00419   cs = data;
00420 
00421   connection_setup_add_watch (cs, watch);
00422   
00423   return TRUE;
00424 }
00425 
00426 static void
00427 remove_watch (DBusWatch *watch,
00428               gpointer   data)
00429 {
00430   ConnectionSetup *cs;
00431 
00432   cs = data;
00433 
00434   connection_setup_remove_watch (cs, watch);
00435 }
00436 
00437 static void
00438 watch_toggled (DBusWatch *watch,
00439                void      *data)
00440 {
00441   /* Because we just exit on OOM, enable/disable is
00442    * no different from add/remove
00443    */
00444   if (dbus_watch_get_enabled (watch))
00445     add_watch (watch, data);
00446   else
00447     remove_watch (watch, data);
00448 }
00449 
00450 static dbus_bool_t
00451 add_timeout (DBusTimeout *timeout,
00452              void        *data)
00453 {
00454   ConnectionSetup *cs;
00455 
00456   cs = data;
00457   
00458   if (!dbus_timeout_get_enabled (timeout))
00459     return TRUE;
00460 
00461   connection_setup_add_timeout (cs, timeout);
00462 
00463   return TRUE;
00464 }
00465 
00466 static void
00467 remove_timeout (DBusTimeout *timeout,
00468                 void        *data)
00469 {
00470   ConnectionSetup *cs;
00471 
00472   cs = data;
00473 
00474   connection_setup_remove_timeout (cs, timeout);
00475 }
00476 
00477 static void
00478 timeout_toggled (DBusTimeout *timeout,
00479                  void        *data)
00480 {
00481   /* Because we just exit on OOM, enable/disable is
00482    * no different from add/remove
00483    */
00484   if (dbus_timeout_get_enabled (timeout))
00485     add_timeout (timeout, data);
00486   else
00487     remove_timeout (timeout, data);
00488 }
00489 
00490 static void
00491 wakeup_main (void *data)
00492 {
00493   ConnectionSetup *cs = data;
00494 
00495   g_main_context_wakeup (cs->context);
00496 }
00497 
00498 
00499 /* Move to a new context */
00500 static ConnectionSetup*
00501 connection_setup_new_from_old (GMainContext    *context,
00502                                ConnectionSetup *old)
00503 {
00504   GSList *tmp;
00505   ConnectionSetup *cs;
00506 
00507   g_assert (old->context != context);
00508   
00509   cs = connection_setup_new (context, old->connection);
00510   
00511   tmp = old->ios;
00512   while (tmp != NULL)
00513     {
00514       IOHandler *handler = tmp->data;
00515 
00516       connection_setup_add_watch (cs, handler->watch);
00517       
00518       tmp = tmp->next;
00519     }
00520 
00521   tmp = old->timeouts;
00522   while (tmp != NULL)
00523     {
00524       TimeoutHandler *handler = tmp->data;
00525 
00526       connection_setup_add_timeout (cs, handler->timeout);
00527       
00528       tmp = tmp->next;
00529     }
00530 
00531   return cs;
00532 }
00533  /* End of GLib bindings internals */
00535 
00555 void
00556 dbus_connection_setup_with_g_main (DBusConnection *connection,
00557                                    GMainContext   *context)
00558 {
00559   ConnectionSetup *old_setup;
00560   ConnectionSetup *cs;
00561   
00562   /* FIXME we never free the slot, so its refcount just keeps growing,
00563    * which is kind of broken.
00564    */
00565   dbus_connection_allocate_data_slot (&_dbus_gmain_connection_slot);
00566   if (_dbus_gmain_connection_slot < 0)
00567     goto nomem;
00568 
00569   if (context == NULL)
00570     context = g_main_context_default ();
00571 
00572   cs = NULL;
00573   
00574   old_setup = dbus_connection_get_data (connection, _dbus_gmain_connection_slot);
00575   if (old_setup != NULL)
00576     {
00577       if (old_setup->context == context)
00578         return; /* nothing to do */
00579 
00580       cs = connection_setup_new_from_old (context, old_setup);
00581       
00582       /* Nuke the old setup */
00583       dbus_connection_set_data (connection, _dbus_gmain_connection_slot, NULL, NULL);
00584       old_setup = NULL;
00585     }
00586 
00587   if (cs == NULL)
00588     cs = connection_setup_new (context, connection);
00589 
00590   if (!dbus_connection_set_data (connection, _dbus_gmain_connection_slot, cs,
00591                                  (DBusFreeFunction)connection_setup_free))
00592     goto nomem;
00593   
00594   if (!dbus_connection_set_watch_functions (connection,
00595                                             add_watch,
00596                                             remove_watch,
00597                                             watch_toggled,
00598                                             cs, NULL))
00599     goto nomem;
00600 
00601   if (!dbus_connection_set_timeout_functions (connection,
00602                                               add_timeout,
00603                                               remove_timeout,
00604                                               timeout_toggled,
00605                                               cs, NULL))
00606     goto nomem;
00607     
00608   dbus_connection_set_wakeup_main_function (connection,
00609                                             wakeup_main,
00610                                             cs, NULL);
00611       
00612   return;
00613 
00614  nomem:
00615   g_error ("Not enough memory to set up DBusConnection for use with GLib");
00616 }
00617 
00632 void
00633 dbus_server_setup_with_g_main (DBusServer   *server,
00634                                GMainContext *context)
00635 {
00636   ConnectionSetup *old_setup;
00637   ConnectionSetup *cs;
00638   
00639   /* FIXME we never free the slot, so its refcount just keeps growing,
00640    * which is kind of broken.
00641    */
00642   dbus_server_allocate_data_slot (&server_slot);
00643   if (server_slot < 0)
00644     goto nomem;
00645 
00646   if (context == NULL)
00647     context = g_main_context_default ();
00648 
00649   cs = NULL;
00650   
00651   old_setup = dbus_server_get_data (server, server_slot);
00652   if (old_setup != NULL)
00653     {
00654       if (old_setup->context == context)
00655         return; /* nothing to do */
00656 
00657       cs = connection_setup_new_from_old (context, old_setup);
00658       
00659       /* Nuke the old setup */
00660       dbus_server_set_data (server, server_slot, NULL, NULL);
00661       old_setup = NULL;
00662     }
00663 
00664   if (cs == NULL)
00665     cs = connection_setup_new (context, NULL);
00666 
00667   if (!dbus_server_set_data (server, server_slot, cs,
00668                              (DBusFreeFunction)connection_setup_free))
00669     goto nomem;
00670   
00671   if (!dbus_server_set_watch_functions (server,
00672                                         add_watch,
00673                                         remove_watch,
00674                                         watch_toggled,
00675                                         cs, NULL))
00676     goto nomem;
00677 
00678   if (!dbus_server_set_timeout_functions (server,
00679                                           add_timeout,
00680                                           remove_timeout,
00681                                           timeout_toggled,
00682                                           cs, NULL))
00683     goto nomem;
00684       
00685   return;
00686 
00687  nomem:
00688   g_error ("Not enough memory to set up DBusServer for use with GLib");
00689 }
00690 
00703 DBusGConnection*
00704 dbus_g_connection_open (const gchar  *address,
00705                         GError      **error)
00706 {
00707   DBusConnection *connection;
00708   DBusError derror;
00709 
00710   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00711 
00712   _dbus_g_value_types_init ();
00713 
00714   dbus_error_init (&derror);
00715 
00716   connection = dbus_connection_open (address, &derror);
00717   if (connection == NULL)
00718     {
00719       dbus_set_g_error (error, &derror);
00720       dbus_error_free (&derror);
00721       return NULL;
00722     }
00723 
00724   /* does nothing if it's already been done */
00725   dbus_connection_setup_with_g_main (connection, NULL);
00726 
00727   return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00728 }
00729 
00743 DBusGConnection*
00744 dbus_g_bus_get (DBusBusType     type,
00745                 GError        **error)
00746 {
00747   DBusConnection *connection;
00748   DBusError derror;
00749 
00750   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00751 
00752   _dbus_g_value_types_init ();
00753   
00754   dbus_error_init (&derror);
00755 
00756   connection = dbus_bus_get (type, &derror);
00757   if (connection == NULL)
00758     {
00759       dbus_set_g_error (error, &derror);
00760       dbus_error_free (&derror);
00761       return NULL;
00762     }
00763 
00764   /* does nothing if it's already been done */
00765   dbus_connection_setup_with_g_main (connection, NULL);
00766 
00767   return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00768 }
00769  /* end of public API */
00771 
00772 #ifdef DBUS_BUILD_TESTS
00773 
00779 gboolean
00780 _dbus_gmain_test (const char *test_data_dir)
00781 {
00782   GType type;
00783   GType rectype;
00784 
00785   g_type_init ();
00786   _dbus_g_value_types_init ();
00787 
00788   rectype = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
00789   g_assert (rectype != G_TYPE_INVALID);
00790   g_assert (!strcmp (g_type_name (rectype), "GArray_guint_"));
00791 
00792   type = _dbus_gtype_from_signature ("au", TRUE);
00793   g_assert (type == rectype);
00794 
00795   rectype = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
00796   g_assert (rectype != G_TYPE_INVALID);
00797   g_assert (!strcmp (g_type_name (rectype), "GHashTable_gchararray+gchararray_"));
00798 
00799   type = _dbus_gtype_from_signature ("a{ss}", TRUE);
00800   g_assert (type == rectype);
00801 
00802   type = _dbus_gtype_from_signature ("o", FALSE);
00803   g_assert (type == DBUS_TYPE_G_OBJECT_PATH);
00804   type = _dbus_gtype_from_signature ("o", TRUE);
00805   g_assert (type == DBUS_TYPE_G_OBJECT_PATH);
00806   
00807   return TRUE;
00808 }
00809 
00810 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Oct 3 10:04:23 2007 for D-BUSGLibBindings by  doxygen 1.5.1