Main Page   Modules   Data Structures   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  *
00006  * Licensed under the Academic Free License version 2.0
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-glib.h"
00026 #include "dbus-gtest.h"
00027 
00028 #include <libintl.h>
00029 #define _(x) dgettext (GETTEXT_PACKAGE, x)
00030 #define N_(x) x
00031 
00054 typedef struct DBusGSource DBusGSource;
00055 
00059 struct DBusGSource
00060 {
00061   GSource source; 
00063   GList *watch_fds;      
00065   GMainContext *context; 
00067   void *connection_or_server; 
00068 };
00069 
00074 typedef struct
00075 {
00076   int refcount;     
00078   GPollFD poll_fd;  
00079   DBusWatch *watch; 
00081   unsigned int removed : 1; 
00082 } WatchFD;
00083 
00084 static WatchFD *
00085 watch_fd_new (void)
00086 {
00087   WatchFD *watch_fd;
00088 
00089   watch_fd = g_new0 (WatchFD, 1);
00090   watch_fd->refcount = 1;
00091 
00092   return watch_fd;
00093 }
00094 
00095 static WatchFD * 
00096 watch_fd_ref (WatchFD *watch_fd)
00097 {
00098   watch_fd->refcount += 1;
00099 
00100   return watch_fd;
00101 }
00102 
00103 static void
00104 watch_fd_unref (WatchFD *watch_fd)
00105 {
00106   watch_fd->refcount -= 1;
00107 
00108   if (watch_fd->refcount == 0)
00109     {
00110       g_assert (watch_fd->removed);
00111   
00112       g_free (watch_fd);
00113     }
00114 }
00115 
00116 static dbus_int32_t connection_slot = -1;
00117 static dbus_int32_t server_slot = -1;
00118 
00119 static gboolean gsource_connection_prepare  (GSource     *source,
00120                                              gint        *timeout);
00121 static gboolean gsource_connection_check    (GSource     *source);
00122 static gboolean gsource_connection_dispatch (GSource     *source,
00123                                              GSourceFunc  callback,
00124                                              gpointer     user_data);
00125 static gboolean gsource_server_prepare      (GSource     *source,
00126                                              gint        *timeout);
00127 static gboolean gsource_server_check        (GSource     *source);
00128 static gboolean gsource_server_dispatch     (GSource     *source,
00129                                              GSourceFunc  callback,
00130                                              gpointer     user_data);
00131 
00132 static GSourceFuncs dbus_connection_funcs = {
00133   gsource_connection_prepare,
00134   gsource_connection_check,
00135   gsource_connection_dispatch,
00136   NULL
00137 };
00138 
00139 static GSourceFuncs dbus_server_funcs = {
00140   gsource_server_prepare,
00141   gsource_server_check,
00142   gsource_server_dispatch,
00143   NULL
00144 };
00145 
00146 static gboolean
00147 gsource_connection_prepare (GSource *source,
00148                             gint    *timeout)
00149 {
00150   DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
00151   
00152   *timeout = -1;
00153 
00154   return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
00155 }
00156 
00157 static gboolean
00158 gsource_server_prepare (GSource *source,
00159                         gint    *timeout)
00160 {
00161   *timeout = -1;
00162 
00163   return FALSE;
00164 }
00165 
00166 static gboolean
00167 dbus_gsource_check (GSource *source)
00168 {
00169   DBusGSource *dbus_source = (DBusGSource *)source;
00170   GList *list;
00171 
00172   list = dbus_source->watch_fds;
00173 
00174   while (list)
00175     {
00176       WatchFD *watch_fd = list->data;
00177 
00178       if (watch_fd->poll_fd.revents != 0)
00179         return TRUE;
00180 
00181       list = list->next;
00182     }
00183 
00184   return FALSE;  
00185 }
00186 
00187 static gboolean
00188 gsource_connection_check (GSource *source)
00189 {
00190   return dbus_gsource_check (source);
00191 }
00192 
00193 static gboolean
00194 gsource_server_check (GSource *source)
00195 {
00196   return dbus_gsource_check (source);
00197 }
00198 
00199 static gboolean
00200 dbus_gsource_dispatch (GSource     *source,
00201                        GSourceFunc  callback,
00202                        gpointer     user_data,
00203                        dbus_bool_t  is_server)
00204 {
00205    DBusGSource *dbus_source = (DBusGSource *)source;
00206    GList *copy, *list;
00207 
00208    /* Make a copy of the list and ref all WatchFDs */
00209    copy = g_list_copy (dbus_source->watch_fds);
00210    g_list_foreach (copy, (GFunc)watch_fd_ref, NULL);
00211    
00212    list = copy;
00213    while (list)
00214      {
00215        WatchFD *watch_fd = list->data;
00216 
00217        if (!watch_fd->removed && watch_fd->poll_fd.revents != 0)
00218          {
00219            guint condition = 0;
00220            
00221            if (watch_fd->poll_fd.revents & G_IO_IN)
00222              condition |= DBUS_WATCH_READABLE;
00223            if (watch_fd->poll_fd.revents & G_IO_OUT)
00224              condition |= DBUS_WATCH_WRITABLE;
00225            if (watch_fd->poll_fd.revents & G_IO_ERR)
00226              condition |= DBUS_WATCH_ERROR;
00227            if (watch_fd->poll_fd.revents & G_IO_HUP)
00228              condition |= DBUS_WATCH_HANGUP;
00229 
00230            dbus_watch_handle (watch_fd->watch, condition);
00231          }
00232 
00233        list = list->next;
00234      }
00235 
00236    g_list_foreach (copy, (GFunc)watch_fd_unref, NULL);   
00237    g_list_free (copy);   
00238 
00239    return TRUE;
00240 }
00241 
00242 static gboolean
00243 gsource_connection_dispatch (GSource     *source,
00244                              GSourceFunc  callback,
00245                              gpointer     user_data)
00246 {
00247   DBusGSource *dbus_source = (DBusGSource *)source;
00248   DBusConnection *connection = dbus_source->connection_or_server;
00249 
00250   dbus_connection_ref (connection);
00251 
00252   dbus_gsource_dispatch (source, callback, user_data,
00253                          FALSE);
00254   
00255   /* Dispatch messages */
00256   while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS)
00257     ;
00258 
00259    dbus_connection_unref (connection);
00260    
00261    return TRUE;
00262 }
00263 
00264 static gboolean
00265 gsource_server_dispatch (GSource     *source,
00266                          GSourceFunc  callback,
00267                          gpointer     user_data)
00268 {
00269   DBusGSource *dbus_source = (DBusGSource *)source;
00270   DBusServer *server = dbus_source->connection_or_server;
00271 
00272   dbus_server_ref (server);
00273 
00274   dbus_gsource_dispatch (source, callback, user_data,
00275                          TRUE);
00276 
00277   dbus_server_unref (server);
00278    
00279   return TRUE;
00280 }
00281      
00282 static dbus_bool_t
00283 add_watch (DBusWatch *watch,
00284            gpointer   data)
00285 {
00286   WatchFD *watch_fd;
00287   DBusGSource *dbus_source;
00288   guint flags;
00289 
00290   if (!dbus_watch_get_enabled (watch))
00291     return TRUE;
00292   
00293   dbus_source = data;
00294 
00295   watch_fd = watch_fd_new ();
00296   watch_fd->poll_fd.fd = dbus_watch_get_fd (watch);
00297   watch_fd->poll_fd.events = 0;
00298   flags = dbus_watch_get_flags (watch);
00299   dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref);
00300 
00301   if (flags & DBUS_WATCH_READABLE)
00302     watch_fd->poll_fd.events |= G_IO_IN;
00303   if (flags & DBUS_WATCH_WRITABLE)
00304     watch_fd->poll_fd.events |= G_IO_OUT;
00305   watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP;
00306 
00307   watch_fd->watch = watch;
00308   
00309   g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00310 
00311   dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd);
00312 
00313   return TRUE;
00314 }
00315 
00316 static void
00317 remove_watch (DBusWatch *watch,
00318               gpointer   data)
00319 {
00320   DBusGSource *dbus_source = data;
00321   WatchFD *watch_fd;
00322   
00323   watch_fd = dbus_watch_get_data (watch);
00324   if (watch_fd == NULL)
00325     return; /* probably a not-enabled watch that was added */
00326 
00327   watch_fd->removed = TRUE;
00328   watch_fd->watch = NULL;  
00329   
00330   dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd);
00331 
00332   g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00333 
00334   dbus_watch_set_data (watch, NULL, NULL); /* needed due to watch_toggled
00335                                             * breaking add/remove symmetry
00336                                             */
00337 }
00338 
00339 static void
00340 watch_toggled (DBusWatch *watch,
00341                void      *data)
00342 {
00343   /* Because we just exit on OOM, enable/disable is
00344    * no different from add/remove
00345    */
00346   if (dbus_watch_get_enabled (watch))
00347     add_watch (watch, data);
00348   else
00349     remove_watch (watch, data);
00350 }
00351 
00352 static gboolean
00353 timeout_handler (gpointer data)
00354 {
00355   DBusTimeout *timeout = data;
00356 
00357   dbus_timeout_handle (timeout);
00358 
00359   return TRUE;
00360 }
00361 
00362 static dbus_bool_t
00363 add_timeout (DBusTimeout *timeout,
00364              void        *data)
00365 {
00366   DBusGSource *dbus_source = data;
00367   GSource *source;
00368 
00369   if (!dbus_timeout_get_enabled (timeout))
00370     return TRUE;
00371   
00372   source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
00373   g_source_set_callback (source, timeout_handler, timeout, NULL);
00374   g_source_attach (source, dbus_source->context);
00375   
00376   dbus_timeout_set_data (timeout, GUINT_TO_POINTER (g_source_get_id (source)),
00377                          NULL);
00378 
00379   return TRUE;
00380 }
00381 
00382 static void
00383 remove_timeout (DBusTimeout *timeout,
00384                 void        *data)
00385 {
00386   guint timeout_tag;
00387   
00388   timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
00389 
00390   if (timeout_tag != 0) /* if 0, probably timeout was disabled */
00391     g_source_remove (timeout_tag);
00392 }
00393 
00394 static void
00395 timeout_toggled (DBusTimeout *timeout,
00396                  void        *data)
00397 {
00398   /* Because we just exit on OOM, enable/disable is
00399    * no different from add/remove
00400    */
00401   if (dbus_timeout_get_enabled (timeout))
00402     add_timeout (timeout, data);
00403   else
00404     remove_timeout (timeout, data);
00405 }
00406 
00407 
00408 static void
00409 free_source (GSource *source)
00410 {
00411   g_source_destroy (source);
00412 }
00413 
00414 static void
00415 wakeup_main (void *data)
00416 {
00417   DBusGSource *dbus_source = data;
00418 
00419   g_main_context_wakeup (dbus_source->context);
00420 }
00421 
00422  /* End of GLib bindings internals */
00424 
00429 static GSource*
00430 create_source (void         *connection_or_server,
00431                GSourceFuncs *funcs,
00432                GMainContext *context)
00433 {
00434   GSource *source;
00435   DBusGSource *dbus_source;
00436 
00437   source = g_source_new (funcs, sizeof (DBusGSource));
00438   
00439   dbus_source = (DBusGSource *)source;  
00440   dbus_source->connection_or_server = connection_or_server;
00441   dbus_source->context = context;
00442 
00443   return source;
00444 }
00445 
00460 void
00461 dbus_connection_setup_with_g_main (DBusConnection *connection,
00462                                    GMainContext   *context)
00463 {
00464   GSource *source;
00465   
00466   /* FIXME we never free the slot, so its refcount just keeps growing,
00467    * which is kind of broken.
00468    */
00469   dbus_connection_allocate_data_slot (&connection_slot);
00470   if (connection_slot < 0)
00471     goto nomem;
00472 
00473   /* So we can test for equality below */
00474   if (context == NULL)
00475     context = g_main_context_default ();
00476   
00477   source = dbus_connection_get_data (connection, connection_slot);
00478   if (source != NULL)
00479     {
00480       if (source->context == context)
00481         return; /* nothing to do */
00482 
00483       /* Remove the previous source and move to a new context */
00484       dbus_connection_set_data (connection, connection_slot, NULL, NULL);
00485       source = NULL;
00486     }
00487   
00488   source = create_source (connection, &dbus_connection_funcs, context);
00489 
00490   if (!dbus_connection_set_watch_functions (connection,
00491                                             add_watch,
00492                                             remove_watch,
00493                                             watch_toggled,
00494                                             source, NULL))
00495     goto nomem;
00496 
00497   if (!dbus_connection_set_timeout_functions (connection,
00498                                               add_timeout,
00499                                               remove_timeout,
00500                                               timeout_toggled,
00501                                               source, NULL))
00502     goto nomem;
00503     
00504   dbus_connection_set_wakeup_main_function (connection,
00505                                             wakeup_main,
00506                                             source, NULL);
00507       
00508   g_source_attach (source, context);
00509 
00510   if (!dbus_connection_set_data (connection, connection_slot, source,
00511                                  (DBusFreeFunction)free_source))
00512     goto nomem;
00513 
00514   return;
00515 
00516  nomem:
00517   g_error ("Not enough memory to set up DBusConnection for use with GLib");
00518 }
00519 
00533 void
00534 dbus_server_setup_with_g_main (DBusServer   *server,
00535                                GMainContext *context)
00536 {
00537   GSource *source;
00538 
00539   dbus_server_allocate_data_slot (&server_slot);
00540   if (server_slot < 0)
00541     goto nomem;
00542 
00543   /* So we can test for equality below */
00544   if (context == NULL)
00545     context = g_main_context_default ();
00546   
00547   source = dbus_server_get_data (server, server_slot);
00548   if (source != NULL)
00549     {
00550       if (source->context == context)
00551         return; /* nothing to do */
00552 
00553       /* Remove the previous source and move to a new context */
00554       dbus_server_set_data (server, server_slot, NULL, NULL);
00555       source = NULL;
00556     }
00557   
00558   source = create_source (server, &dbus_server_funcs, context);
00559 
00560   dbus_server_set_watch_functions (server,
00561                                    add_watch,
00562                                    remove_watch,
00563                                    watch_toggled,
00564                                    source, NULL);
00565 
00566   dbus_server_set_timeout_functions (server,
00567                                      add_timeout,
00568                                      remove_timeout,
00569                                      timeout_toggled,
00570                                      NULL, NULL);
00571   
00572   g_source_attach (source, context);
00573 
00574   if (!dbus_server_set_data (server, server_slot, source,
00575                              (DBusFreeFunction)free_source))
00576     goto nomem;
00577 
00578   return;
00579 
00580  nomem:
00581   g_error ("Not enough memory to set up DBusServer for use with GLib");
00582 }
00583 
00592 DBusConnection*
00593 dbus_bus_get_with_g_main (DBusBusType     type,
00594                           GError        **error)
00595 {
00596   DBusConnection *connection;
00597   DBusError derror;
00598 
00599   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00600   
00601   dbus_error_init (&derror);
00602 
00603   connection = dbus_bus_get (type, &derror);
00604   if (connection == NULL)
00605     {
00606       dbus_set_g_error (error, &derror);
00607       dbus_error_free (&derror);
00608     }
00609   else
00610     {
00611       /* does nothing if it's already been done */
00612       dbus_connection_setup_with_g_main (connection, NULL);
00613     }
00614 
00615   return connection;
00616 }
00617 
00624 GQuark
00625 dbus_g_error_quark (void)
00626 {
00627   static GQuark quark = 0;
00628   if (quark == 0)
00629     quark = g_quark_from_static_string ("g-exec-error-quark");
00630   return quark;
00631 }
00632 
00633 
00642 void
00643 dbus_set_g_error (GError   **gerror,
00644                   DBusError *derror)
00645 {
00646   g_return_if_fail (derror != NULL);
00647   g_return_if_fail (dbus_error_is_set (derror));
00648   
00649   g_set_error (gerror, DBUS_GERROR,
00650                DBUS_GERROR_FAILED,
00651                _("D-BUS error %s: %s"),
00652                derror->name, derror->message);  
00653 }
00654 
00660 GType
00661 dbus_connection_get_g_type (void)
00662 {
00663   static GType our_type = 0;
00664   
00665   if (our_type == 0)
00666     our_type = g_boxed_type_register_static ("DBusConnection",
00667                                              (GBoxedCopyFunc) dbus_connection_ref,
00668                                              (GBoxedFreeFunc) dbus_connection_unref);
00669 
00670   return our_type;
00671 }
00672 
00678 GType
00679 dbus_message_get_g_type (void)
00680 {
00681   static GType our_type = 0;
00682   
00683   if (our_type == 0)
00684     our_type = g_boxed_type_register_static ("DBusMessage",
00685                                              (GBoxedCopyFunc) dbus_message_ref,
00686                                              (GBoxedFreeFunc) dbus_message_unref);
00687 
00688   return our_type;
00689 }
00690 
00691  /* end of public API */
00693 
00694 #ifdef DBUS_BUILD_TESTS
00695 
00701 dbus_bool_t
00702 _dbus_gmain_test (const char *test_data_dir)
00703 {
00704   
00705   return TRUE;
00706 }
00707 
00708 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Jun 9 05:01:25 2004 for D-BUS by doxygen1.2.15