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

Generated on Tue Feb 10 18:14:02 2004 for D-BUS by doxygen 1.3.5