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 const 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   g_io_channel_unref (channel);
00290 }
00291 
00292 static void
00293 connection_setup_remove_watch (ConnectionSetup *cs,
00294                                DBusWatch       *watch)
00295 {
00296   IOHandler *handler;
00297 
00298   handler = dbus_watch_get_data (watch);
00299 
00300   if (handler == NULL)
00301     return;
00302   
00303   io_handler_destroy_source (handler);
00304 }
00305 
00306 static void
00307 timeout_handler_source_finalized (gpointer data)
00308 {
00309   TimeoutHandler *handler;
00310 
00311   handler = data;
00312 
00313   if (handler->timeout)
00314     dbus_timeout_set_data (handler->timeout, NULL, NULL);
00315   
00316   g_free (handler);
00317 }
00318 
00319 static void
00320 timeout_handler_destroy_source (void *data)
00321 {
00322   TimeoutHandler *handler;
00323 
00324   handler = data;
00325 
00326   if (handler->source)
00327     {
00328       GSource *source = handler->source;
00329       handler->source = NULL;
00330       handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
00331       g_source_destroy (source);
00332       g_source_unref (source);
00333     }
00334 }
00335 
00336 static void
00337 timeout_handler_timeout_freed (void *data)
00338 {
00339   TimeoutHandler *handler;
00340 
00341   handler = data;
00342 
00343   handler->timeout = NULL;
00344 
00345   timeout_handler_destroy_source (handler);
00346 }
00347 
00348 static gboolean
00349 timeout_handler_dispatch (gpointer      data)
00350 {
00351   TimeoutHandler *handler;
00352 
00353   handler = data;
00354 
00355   dbus_timeout_handle (handler->timeout);
00356   
00357   return TRUE;
00358 }
00359 
00360 static void
00361 connection_setup_add_timeout (ConnectionSetup *cs,
00362                               DBusTimeout     *timeout)
00363 {
00364   TimeoutHandler *handler;
00365   
00366   if (!dbus_timeout_get_enabled (timeout))
00367     return;
00368   
00369   g_assert (dbus_timeout_get_data (timeout) == NULL);
00370 
00371   handler = g_new0 (TimeoutHandler, 1);
00372   handler->cs = cs;
00373   handler->timeout = timeout;
00374 
00375   handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
00376   g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
00377                          timeout_handler_source_finalized);
00378   g_source_attach (handler->source, handler->cs->context);
00379 
00380   cs->timeouts = g_slist_prepend (cs->timeouts, handler);
00381 
00382   dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
00383 }
00384 
00385 static void
00386 connection_setup_remove_timeout (ConnectionSetup *cs,
00387                                  DBusTimeout       *timeout)
00388 {
00389   TimeoutHandler *handler;
00390   
00391   handler = dbus_timeout_get_data (timeout);
00392 
00393   if (handler == NULL)
00394     return;
00395   
00396   timeout_handler_destroy_source (handler);
00397 }
00398 
00399 static void
00400 connection_setup_free (ConnectionSetup *cs)
00401 {
00402   while (cs->ios)
00403     io_handler_destroy_source (cs->ios->data);
00404 
00405   while (cs->timeouts)
00406     timeout_handler_destroy_source (cs->timeouts->data);
00407 
00408   if (cs->message_queue_source)
00409     {
00410       GSource *source;
00411 
00412       source = cs->message_queue_source;
00413       cs->message_queue_source = NULL;
00414 
00415       g_source_destroy (source);
00416       g_source_unref (source);
00417     }
00418   
00419   g_main_context_unref (cs->context);
00420   g_free (cs);
00421 }
00422 
00423 static dbus_bool_t
00424 add_watch (DBusWatch *watch,
00425            gpointer   data)
00426 {
00427   ConnectionSetup *cs;
00428 
00429   cs = data;
00430 
00431   connection_setup_add_watch (cs, watch);
00432   
00433   return TRUE;
00434 }
00435 
00436 static void
00437 remove_watch (DBusWatch *watch,
00438               gpointer   data)
00439 {
00440   ConnectionSetup *cs;
00441 
00442   cs = data;
00443 
00444   connection_setup_remove_watch (cs, watch);
00445 }
00446 
00447 static void
00448 watch_toggled (DBusWatch *watch,
00449                void      *data)
00450 {
00451   /* Because we just exit on OOM, enable/disable is
00452    * no different from add/remove
00453    */
00454   if (dbus_watch_get_enabled (watch))
00455     add_watch (watch, data);
00456   else
00457     remove_watch (watch, data);
00458 }
00459 
00460 static dbus_bool_t
00461 add_timeout (DBusTimeout *timeout,
00462              void        *data)
00463 {
00464   ConnectionSetup *cs;
00465 
00466   cs = data;
00467   
00468   if (!dbus_timeout_get_enabled (timeout))
00469     return TRUE;
00470 
00471   connection_setup_add_timeout (cs, timeout);
00472 
00473   return TRUE;
00474 }
00475 
00476 static void
00477 remove_timeout (DBusTimeout *timeout,
00478                 void        *data)
00479 {
00480   ConnectionSetup *cs;
00481 
00482   cs = data;
00483 
00484   connection_setup_remove_timeout (cs, timeout);
00485 }
00486 
00487 static void
00488 timeout_toggled (DBusTimeout *timeout,
00489                  void        *data)
00490 {
00491   /* Because we just exit on OOM, enable/disable is
00492    * no different from add/remove
00493    */
00494   if (dbus_timeout_get_enabled (timeout))
00495     add_timeout (timeout, data);
00496   else
00497     remove_timeout (timeout, data);
00498 }
00499 
00500 static void
00501 wakeup_main (void *data)
00502 {
00503   ConnectionSetup *cs = data;
00504 
00505   g_main_context_wakeup (cs->context);
00506 }
00507 
00508 
00509 /* Move to a new context */
00510 static ConnectionSetup*
00511 connection_setup_new_from_old (GMainContext    *context,
00512                                ConnectionSetup *old)
00513 {
00514   GSList *tmp;
00515   ConnectionSetup *cs;
00516 
00517   g_assert (old->context != context);
00518   
00519   cs = connection_setup_new (context, old->connection);
00520   
00521   tmp = old->ios;
00522   while (tmp != NULL)
00523     {
00524       IOHandler *handler = tmp->data;
00525 
00526       connection_setup_add_watch (cs, handler->watch);
00527       
00528       tmp = tmp->next;
00529     }
00530 
00531   tmp = old->timeouts;
00532   while (tmp != NULL)
00533     {
00534       TimeoutHandler *handler = tmp->data;
00535 
00536       connection_setup_add_timeout (cs, handler->timeout);
00537       
00538       tmp = tmp->next;
00539     }
00540 
00541   return cs;
00542 }
00543  /* End of GLib bindings internals */
00545 
00564 void
00565 dbus_connection_setup_with_g_main (DBusConnection *connection,
00566                                    GMainContext   *context)
00567 {
00568   ConnectionSetup *old_setup;
00569   ConnectionSetup *cs;
00570   
00571   /* FIXME we never free the slot, so its refcount just keeps growing,
00572    * which is kind of broken.
00573    */
00574   dbus_connection_allocate_data_slot (&connection_slot);
00575   if (connection_slot < 0)
00576     goto nomem;
00577 
00578   if (context == NULL)
00579     context = g_main_context_default ();
00580 
00581   cs = NULL;
00582   
00583   old_setup = dbus_connection_get_data (connection, connection_slot);
00584   if (old_setup != NULL)
00585     {
00586       if (old_setup->context == context)
00587         return; /* nothing to do */
00588 
00589       cs = connection_setup_new_from_old (context, old_setup);
00590       
00591       /* Nuke the old setup */
00592       dbus_connection_set_data (connection, connection_slot, NULL, NULL);
00593       old_setup = NULL;
00594     }
00595 
00596   if (cs == NULL)
00597     cs = connection_setup_new (context, connection);
00598 
00599   if (!dbus_connection_set_data (connection, connection_slot, cs,
00600                                  (DBusFreeFunction)connection_setup_free))
00601     goto nomem;
00602   
00603   if (!dbus_connection_set_watch_functions (connection,
00604                                             add_watch,
00605                                             remove_watch,
00606                                             watch_toggled,
00607                                             cs, NULL))
00608     goto nomem;
00609 
00610   if (!dbus_connection_set_timeout_functions (connection,
00611                                               add_timeout,
00612                                               remove_timeout,
00613                                               timeout_toggled,
00614                                               cs, NULL))
00615     goto nomem;
00616     
00617   dbus_connection_set_wakeup_main_function (connection,
00618                                             wakeup_main,
00619                                             cs, NULL);
00620       
00621   return;
00622 
00623  nomem:
00624   g_error ("Not enough memory to set up DBusConnection for use with GLib");
00625 }
00626 
00640 void
00641 dbus_server_setup_with_g_main (DBusServer   *server,
00642                                GMainContext *context)
00643 {
00644   ConnectionSetup *old_setup;
00645   ConnectionSetup *cs;
00646   
00647   /* FIXME we never free the slot, so its refcount just keeps growing,
00648    * which is kind of broken.
00649    */
00650   dbus_server_allocate_data_slot (&server_slot);
00651   if (server_slot < 0)
00652     goto nomem;
00653 
00654   if (context == NULL)
00655     context = g_main_context_default ();
00656 
00657   cs = NULL;
00658   
00659   old_setup = dbus_server_get_data (server, server_slot);
00660   if (old_setup != NULL)
00661     {
00662       if (old_setup->context == context)
00663         return; /* nothing to do */
00664 
00665       cs = connection_setup_new_from_old (context, old_setup);
00666       
00667       /* Nuke the old setup */
00668       dbus_server_set_data (server, server_slot, NULL, NULL);
00669       old_setup = NULL;
00670     }
00671 
00672   if (cs == NULL)
00673     cs = connection_setup_new (context, NULL);
00674 
00675   if (!dbus_server_set_data (server, server_slot, cs,
00676                              (DBusFreeFunction)connection_setup_free))
00677     goto nomem;
00678   
00679   if (!dbus_server_set_watch_functions (server,
00680                                         add_watch,
00681                                         remove_watch,
00682                                         watch_toggled,
00683                                         cs, NULL))
00684     goto nomem;
00685 
00686   if (!dbus_server_set_timeout_functions (server,
00687                                           add_timeout,
00688                                           remove_timeout,
00689                                           timeout_toggled,
00690                                           cs, NULL))
00691     goto nomem;
00692       
00693   return;
00694 
00695  nomem:
00696   g_error ("Not enough memory to set up DBusServer for use with GLib");
00697 }
00698 
00710 DBusGConnection*
00711 dbus_g_bus_get (DBusBusType     type,
00712                 GError        **error)
00713 {
00714   DBusConnection *connection;
00715   DBusError derror;
00716 
00717   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00718 
00719   _dbus_g_value_types_init ();
00720   
00721   dbus_error_init (&derror);
00722 
00723   connection = dbus_bus_get (type, &derror);
00724   if (connection == NULL)
00725     {
00726       dbus_set_g_error (error, &derror);
00727       dbus_error_free (&derror);
00728       return NULL;
00729     }
00730 
00731   /* does nothing if it's already been done */
00732   dbus_connection_setup_with_g_main (connection, NULL);
00733 
00734   return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00735 }
00736  /* end of public API */
00738 
00739 #ifdef DBUS_BUILD_TESTS
00740 
00746 gboolean
00747 _dbus_gmain_test (const char *test_data_dir)
00748 {
00749   GType type;
00750   GType rectype;
00751 
00752   g_type_init ();
00753   _dbus_g_value_types_init ();
00754 
00755   rectype = dbus_g_type_get_collection ("GArray", G_TYPE_UINT);
00756   g_assert (rectype != G_TYPE_INVALID);
00757   g_assert (!strcmp (g_type_name (rectype), "GArray+guint"));
00758 
00759   type = _dbus_gtype_from_signature ("au", TRUE);
00760   g_assert (type == rectype);
00761 
00762   rectype = dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING);
00763   g_assert (rectype != G_TYPE_INVALID);
00764   g_assert (!strcmp (g_type_name (rectype), "GHashTable+gchararray+gchararray"));
00765 
00766   type = _dbus_gtype_from_signature ("a{ss}", TRUE);
00767   g_assert (type == rectype);
00768 
00769   type = _dbus_gtype_from_signature ("o", FALSE);
00770   g_assert (type == DBUS_TYPE_G_OBJECT_PATH);
00771   type = _dbus_gtype_from_signature ("o", TRUE);
00772   g_assert (type == DBUS_TYPE_G_OBJECT_PATH);
00773   
00774   return TRUE;
00775 }
00776 
00777 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Jul 7 15:13:58 2009 for D-BUS by  doxygen 1.4.6