Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

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 
00066 typedef struct
00067 {
00068   GSource source; 
00069   DBusConnection *connection; 
00070 } DBusGMessageQueue;
00071 
00072 static gboolean message_queue_prepare  (GSource     *source,
00073                                         gint        *timeout);
00074 static gboolean message_queue_check    (GSource     *source);
00075 static gboolean message_queue_dispatch (GSource     *source,
00076                                         GSourceFunc  callback,
00077                                         gpointer     user_data);
00078 
00079 static GSourceFuncs message_queue_funcs = {
00080   message_queue_prepare,
00081   message_queue_check,
00082   message_queue_dispatch,
00083   NULL
00084 };
00085 
00086 static gboolean
00087 message_queue_prepare (GSource *source,
00088                        gint    *timeout)
00089 {
00090   DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
00091   
00092   *timeout = -1;
00093 
00094   return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
00095 }
00096 
00097 static gboolean
00098 message_queue_check (GSource *source)
00099 {
00100   return FALSE;
00101 }
00102 
00103 static gboolean
00104 message_queue_dispatch (GSource     *source,
00105                         GSourceFunc  callback,
00106                         gpointer     user_data)
00107 {
00108   DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
00109 
00110   dbus_connection_ref (connection);
00111 
00112   /* Only dispatch once - we don't want to starve other GSource */
00113   dbus_connection_dispatch (connection);
00114   
00115   dbus_connection_unref (connection);
00116 
00117   return TRUE;
00118 }
00119 
00120 typedef struct
00121 {
00122   GMainContext *context;      
00123   GSList *ios;                
00124   GSList *timeouts;           
00125   DBusConnection *connection; 
00126   GSource *message_queue_source; 
00127 } ConnectionSetup;
00128 
00129 
00130 typedef struct
00131 {
00132   ConnectionSetup *cs;
00133   GSource *source;
00134   DBusWatch *watch;
00135 } IOHandler;
00136 
00137 typedef struct
00138 {
00139   ConnectionSetup *cs;
00140   GSource *source;
00141   DBusTimeout *timeout;
00142 } TimeoutHandler;
00143 
00144 static dbus_int32_t connection_slot = -1;
00145 static dbus_int32_t server_slot = -1;
00146 
00147 static ConnectionSetup*
00148 connection_setup_new (GMainContext   *context,
00149                       DBusConnection *connection)
00150 {
00151   ConnectionSetup *cs;
00152 
00153   cs = g_new0 (ConnectionSetup, 1);
00154 
00155   g_assert (context != NULL);
00156   
00157   cs->context = context;
00158   g_main_context_ref (cs->context);  
00159 
00160   if (connection)
00161     {
00162       cs->connection = connection;
00163 
00164       cs->message_queue_source = g_source_new (&message_queue_funcs,
00165                                                sizeof (DBusGMessageQueue));
00166       ((DBusGMessageQueue*)cs->message_queue_source)->connection = connection;
00167       g_source_attach (cs->message_queue_source, cs->context);
00168     }
00169   
00170   return cs;
00171 }
00172 
00173 static void
00174 io_handler_source_finalized (gpointer data)
00175 {
00176   IOHandler *handler;
00177 
00178   handler = data;
00179 
00180   if (handler->watch)
00181     dbus_watch_set_data (handler->watch, NULL, NULL);
00182   
00183   g_free (handler);
00184 }
00185 
00186 static void
00187 io_handler_destroy_source (void *data)
00188 {
00189   IOHandler *handler;
00190 
00191   handler = data;
00192 
00193   if (handler->source)
00194     {
00195       GSource *source = handler->source;
00196       handler->source = NULL;
00197       handler->cs->ios = g_slist_remove (handler->cs->ios, handler);
00198       g_source_destroy (source);
00199       g_source_unref (source);
00200     }
00201 }
00202 
00203 static void
00204 io_handler_watch_freed (void *data)
00205 {
00206   IOHandler *handler;
00207 
00208   handler = data;
00209 
00210   handler->watch = NULL;
00211 
00212   io_handler_destroy_source (handler);
00213 }
00214 
00215 static gboolean
00216 io_handler_dispatch (GIOChannel   *source,
00217                      GIOCondition  condition,
00218                      gpointer      data)
00219 {
00220   IOHandler *handler;
00221   guint dbus_condition = 0;
00222   DBusConnection *connection;
00223 
00224   handler = data;
00225 
00226   connection = handler->cs->connection;
00227   
00228   if (connection)
00229     dbus_connection_ref (connection);
00230   
00231   if (condition & G_IO_IN)
00232     dbus_condition |= DBUS_WATCH_READABLE;
00233   if (condition & G_IO_OUT)
00234     dbus_condition |= DBUS_WATCH_WRITABLE;
00235   if (condition & G_IO_ERR)
00236     dbus_condition |= DBUS_WATCH_ERROR;
00237   if (condition & G_IO_HUP)
00238     dbus_condition |= DBUS_WATCH_HANGUP;
00239 
00240   /* Note that we don't touch the handler after this, because
00241    * dbus may have disabled the watch and thus killed the
00242    * handler.
00243    */
00244   dbus_watch_handle (handler->watch, dbus_condition);
00245   handler = NULL;
00246 
00247   if (connection)
00248     dbus_connection_unref (connection);
00249   
00250   return TRUE;
00251 }
00252 
00253 static void
00254 connection_setup_add_watch (ConnectionSetup *cs,
00255                             DBusWatch       *watch)
00256 {
00257   guint flags;
00258   GIOCondition condition;
00259   GIOChannel *channel;
00260   IOHandler *handler;
00261   
00262   if (!dbus_watch_get_enabled (watch))
00263     return;
00264   
00265   g_assert (dbus_watch_get_data (watch) == NULL);
00266   
00267   flags = dbus_watch_get_flags (watch);
00268 
00269   condition = G_IO_ERR | G_IO_HUP;
00270   if (flags & DBUS_WATCH_READABLE)
00271     condition |= G_IO_IN;
00272   if (flags & DBUS_WATCH_WRITABLE)
00273     condition |= G_IO_OUT;
00274 
00275   handler = g_new0 (IOHandler, 1);
00276   handler->cs = cs;
00277   handler->watch = watch;
00278   
00279   channel = g_io_channel_unix_new (dbus_watch_get_fd (watch));
00280   
00281   handler->source = g_io_create_watch (channel, condition);
00282   g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
00283                          io_handler_source_finalized);
00284   g_source_attach (handler->source, cs->context);
00285 
00286   cs->ios = g_slist_prepend (cs->ios, handler);
00287   
00288   dbus_watch_set_data (watch, handler, io_handler_watch_freed);
00289 }
00290 
00291 static void
00292 connection_setup_remove_watch (ConnectionSetup *cs,
00293                                DBusWatch       *watch)
00294 {
00295   IOHandler *handler;
00296 
00297   handler = dbus_watch_get_data (watch);
00298 
00299   if (handler == NULL)
00300     return;
00301   
00302   io_handler_destroy_source (handler);
00303 }
00304 
00305 static void
00306 timeout_handler_source_finalized (gpointer data)
00307 {
00308   TimeoutHandler *handler;
00309 
00310   handler = data;
00311 
00312   if (handler->timeout)
00313     dbus_timeout_set_data (handler->timeout, NULL, NULL);
00314   
00315   g_free (handler);
00316 }
00317 
00318 static void
00319 timeout_handler_destroy_source (void *data)
00320 {
00321   TimeoutHandler *handler;
00322 
00323   handler = data;
00324 
00325   if (handler->source)
00326     {
00327       GSource *source = handler->source;
00328       handler->source = NULL;
00329       handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
00330       g_source_destroy (source);
00331       g_source_unref (source);
00332     }
00333 }
00334 
00335 static void
00336 timeout_handler_timeout_freed (void *data)
00337 {
00338   TimeoutHandler *handler;
00339 
00340   handler = data;
00341 
00342   handler->timeout = NULL;
00343 
00344   timeout_handler_destroy_source (handler);
00345 }
00346 
00347 static gboolean
00348 timeout_handler_dispatch (gpointer      data)
00349 {
00350   TimeoutHandler *handler;
00351 
00352   handler = data;
00353 
00354   dbus_timeout_handle (handler->timeout);
00355   
00356   return TRUE;
00357 }
00358 
00359 static void
00360 connection_setup_add_timeout (ConnectionSetup *cs,
00361                               DBusTimeout     *timeout)
00362 {
00363   TimeoutHandler *handler;
00364   
00365   if (!dbus_timeout_get_enabled (timeout))
00366     return;
00367   
00368   g_assert (dbus_timeout_get_data (timeout) == NULL);
00369 
00370   handler = g_new0 (TimeoutHandler, 1);
00371   handler->cs = cs;
00372   handler->timeout = timeout;
00373 
00374   handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
00375   g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
00376                          timeout_handler_source_finalized);
00377   g_source_attach (handler->source, handler->cs->context);
00378 
00379   cs->timeouts = g_slist_prepend (cs->timeouts, handler);
00380 
00381   dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
00382 }
00383 
00384 static void
00385 connection_setup_remove_timeout (ConnectionSetup *cs,
00386                                  DBusTimeout       *timeout)
00387 {
00388   TimeoutHandler *handler;
00389   
00390   handler = dbus_timeout_get_data (timeout);
00391 
00392   if (handler == NULL)
00393     return;
00394   
00395   timeout_handler_destroy_source (handler);
00396 }
00397 
00398 static void
00399 connection_setup_free (ConnectionSetup *cs)
00400 {
00401   while (cs->ios)
00402     io_handler_destroy_source (cs->ios->data);
00403 
00404   while (cs->timeouts)
00405     timeout_handler_destroy_source (cs->timeouts->data);
00406 
00407   if (cs->message_queue_source)
00408     {
00409       GSource *source;
00410 
00411       source = cs->message_queue_source;
00412       cs->message_queue_source = NULL;
00413 
00414       g_source_destroy (source);
00415       g_source_unref (source);
00416     }
00417   
00418   g_main_context_unref (cs->context);
00419   g_free (cs);
00420 }
00421 
00422 static dbus_bool_t
00423 add_watch (DBusWatch *watch,
00424            gpointer   data)
00425 {
00426   ConnectionSetup *cs;
00427 
00428   cs = data;
00429 
00430   connection_setup_add_watch (cs, watch);
00431   
00432   return TRUE;
00433 }
00434 
00435 static void
00436 remove_watch (DBusWatch *watch,
00437               gpointer   data)
00438 {
00439   ConnectionSetup *cs;
00440 
00441   cs = data;
00442 
00443   connection_setup_remove_watch (cs, watch);
00444 }
00445 
00446 static void
00447 watch_toggled (DBusWatch *watch,
00448                void      *data)
00449 {
00450   /* Because we just exit on OOM, enable/disable is
00451    * no different from add/remove
00452    */
00453   if (dbus_watch_get_enabled (watch))
00454     add_watch (watch, data);
00455   else
00456     remove_watch (watch, data);
00457 }
00458 
00459 static dbus_bool_t
00460 add_timeout (DBusTimeout *timeout,
00461              void        *data)
00462 {
00463   ConnectionSetup *cs;
00464 
00465   cs = data;
00466   
00467   if (!dbus_timeout_get_enabled (timeout))
00468     return TRUE;
00469 
00470   connection_setup_add_timeout (cs, timeout);
00471 
00472   return TRUE;
00473 }
00474 
00475 static void
00476 remove_timeout (DBusTimeout *timeout,
00477                 void        *data)
00478 {
00479   ConnectionSetup *cs;
00480 
00481   cs = data;
00482 
00483   connection_setup_remove_timeout (cs, timeout);
00484 }
00485 
00486 static void
00487 timeout_toggled (DBusTimeout *timeout,
00488                  void        *data)
00489 {
00490   /* Because we just exit on OOM, enable/disable is
00491    * no different from add/remove
00492    */
00493   if (dbus_timeout_get_enabled (timeout))
00494     add_timeout (timeout, data);
00495   else
00496     remove_timeout (timeout, data);
00497 }
00498 
00499 static void
00500 wakeup_main (void *data)
00501 {
00502   ConnectionSetup *cs = data;
00503 
00504   g_main_context_wakeup (cs->context);
00505 }
00506 
00507 
00508 /* Move to a new context */
00509 static ConnectionSetup*
00510 connection_setup_new_from_old (GMainContext    *context,
00511                                ConnectionSetup *old)
00512 {
00513   GSList *tmp;
00514   ConnectionSetup *cs;
00515 
00516   g_assert (old->context != context);
00517   
00518   cs = connection_setup_new (context, old->connection);
00519   
00520   tmp = old->ios;
00521   while (tmp != NULL)
00522     {
00523       IOHandler *handler = tmp->data;
00524 
00525       connection_setup_add_watch (cs, handler->watch);
00526       
00527       tmp = tmp->next;
00528     }
00529 
00530   tmp = old->timeouts;
00531   while (tmp != NULL)
00532     {
00533       TimeoutHandler *handler = tmp->data;
00534 
00535       connection_setup_add_timeout (cs, handler->timeout);
00536       
00537       tmp = tmp->next;
00538     }
00539 
00540   return cs;
00541 }
00542  /* End of GLib bindings internals */
00544 
00563 void
00564 dbus_connection_setup_with_g_main (DBusConnection *connection,
00565                                    GMainContext   *context)
00566 {
00567   ConnectionSetup *old_setup;
00568   ConnectionSetup *cs;
00569   
00570   /* FIXME we never free the slot, so its refcount just keeps growing,
00571    * which is kind of broken.
00572    */
00573   dbus_connection_allocate_data_slot (&connection_slot);
00574   if (connection_slot < 0)
00575     goto nomem;
00576 
00577   if (context == NULL)
00578     context = g_main_context_default ();
00579 
00580   cs = NULL;
00581   
00582   old_setup = dbus_connection_get_data (connection, connection_slot);
00583   if (old_setup != NULL)
00584     {
00585       if (old_setup->context == context)
00586         return; /* nothing to do */
00587 
00588       cs = connection_setup_new_from_old (context, old_setup);
00589       
00590       /* Nuke the old setup */
00591       dbus_connection_set_data (connection, connection_slot, NULL, NULL);
00592       old_setup = NULL;
00593     }
00594 
00595   if (cs == NULL)
00596     cs = connection_setup_new (context, connection);
00597 
00598   if (!dbus_connection_set_data (connection, connection_slot, cs,
00599                                  (DBusFreeFunction)connection_setup_free))
00600     goto nomem;
00601   
00602   if (!dbus_connection_set_watch_functions (connection,
00603                                             add_watch,
00604                                             remove_watch,
00605                                             watch_toggled,
00606                                             cs, NULL))
00607     goto nomem;
00608 
00609   if (!dbus_connection_set_timeout_functions (connection,
00610                                               add_timeout,
00611                                               remove_timeout,
00612                                               timeout_toggled,
00613                                               cs, NULL))
00614     goto nomem;
00615     
00616   dbus_connection_set_wakeup_main_function (connection,
00617                                             wakeup_main,
00618                                             cs, NULL);
00619       
00620   return;
00621 
00622  nomem:
00623   g_error ("Not enough memory to set up DBusConnection for use with GLib");
00624 }
00625 
00639 void
00640 dbus_server_setup_with_g_main (DBusServer   *server,
00641                                GMainContext *context)
00642 {
00643   ConnectionSetup *old_setup;
00644   ConnectionSetup *cs;
00645   
00646   /* FIXME we never free the slot, so its refcount just keeps growing,
00647    * which is kind of broken.
00648    */
00649   dbus_server_allocate_data_slot (&server_slot);
00650   if (server_slot < 0)
00651     goto nomem;
00652 
00653   if (context == NULL)
00654     context = g_main_context_default ();
00655 
00656   cs = NULL;
00657   
00658   old_setup = dbus_server_get_data (server, server_slot);
00659   if (old_setup != NULL)
00660     {
00661       if (old_setup->context == context)
00662         return; /* nothing to do */
00663 
00664       cs = connection_setup_new_from_old (context, old_setup);
00665       
00666       /* Nuke the old setup */
00667       dbus_server_set_data (server, server_slot, NULL, NULL);
00668       old_setup = NULL;
00669     }
00670 
00671   if (cs == NULL)
00672     cs = connection_setup_new (context, NULL);
00673 
00674   if (!dbus_server_set_data (server, server_slot, cs,
00675                              (DBusFreeFunction)connection_setup_free))
00676     goto nomem;
00677   
00678   if (!dbus_server_set_watch_functions (server,
00679                                         add_watch,
00680                                         remove_watch,
00681                                         watch_toggled,
00682                                         cs, NULL))
00683     goto nomem;
00684 
00685   if (!dbus_server_set_timeout_functions (server,
00686                                           add_timeout,
00687                                           remove_timeout,
00688                                           timeout_toggled,
00689                                           cs, NULL))
00690     goto nomem;
00691       
00692   return;
00693 
00694  nomem:
00695   g_error ("Not enough memory to set up DBusServer for use with GLib");
00696 }
00697 
00709 DBusGConnection*
00710 dbus_g_bus_get (DBusBusType     type,
00711                 GError        **error)
00712 {
00713   DBusConnection *connection;
00714   DBusError derror;
00715 
00716   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00717 
00718   _dbus_g_value_types_init ();
00719   
00720   dbus_error_init (&derror);
00721 
00722   connection = dbus_bus_get (type, &derror);
00723   if (connection == NULL)
00724     {
00725       dbus_set_g_error (error, &derror);
00726       dbus_error_free (&derror);
00727       return NULL;
00728     }
00729 
00730   /* does nothing if it's already been done */
00731   dbus_connection_setup_with_g_main (connection, NULL);
00732 
00733   return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00734 }
00735  /* end of public API */
00737 
00738 #ifdef DBUS_BUILD_TESTS
00739 
00745 gboolean
00746 _dbus_gmain_test (const char *test_data_dir)
00747 {
00748   GType type;
00749   GType rectype;
00750 
00751   g_type_init ();
00752   _dbus_g_value_types_init ();
00753 
00754   rectype = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
00755   g_assert (rectype != G_TYPE_INVALID);
00756   g_assert (!strcmp (g_type_name (rectype), "GArray+guint"));
00757 
00758   type = _dbus_gtype_from_signature ("au", TRUE);
00759   g_assert (type == rectype);
00760 
00761   rectype = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
00762   g_assert (rectype != G_TYPE_INVALID);
00763   g_assert (!strcmp (g_type_name (rectype), "GHashTable+gchararray+gchararray"));
00764 
00765   type = _dbus_gtype_from_signature ("a{ss}", TRUE);
00766   g_assert (type == rectype);
00767 
00768   type = _dbus_gtype_from_signature ("o", FALSE);
00769   g_assert (type == DBUS_TYPE_G_OBJECT_PATH);
00770   type = _dbus_gtype_from_signature ("o", TRUE);
00771   g_assert (type == DBUS_TYPE_G_OBJECT_PATH);
00772   
00773   return TRUE;
00774 }
00775 
00776 #endif /* DBUS_BUILD_TESTS */

Generated on Fri Sep 30 19:45:35 2005 for D-BUS by  doxygen 1.4.4