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

Generated on Sun Mar 21 03:52:04 2004 for D-BUS by doxygen 1.3.6-20040222