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 "dbus-glib.h"
00025 #include <glib.h>
00026 
00049 typedef struct DBusGSource DBusGSource;
00050 
00051 struct DBusGSource
00052 {
00053   GSource source; 
00055   GList *watch_fds;      
00057   GMainContext *context; 
00059   void *connection_or_server; 
00060 };
00061 
00062 typedef struct
00063 {
00064   int refcount;
00065 
00066   GPollFD poll_fd;
00067   DBusWatch *watch;
00068   
00069   unsigned int removed : 1;
00070 } WatchFD;
00071 
00072 static WatchFD *
00073 watch_fd_new (void)
00074 {
00075   WatchFD *watch_fd;
00076 
00077   watch_fd = g_new0 (WatchFD, 1);
00078   watch_fd->refcount = 1;
00079 
00080   return watch_fd;
00081 }
00082 
00083 static void
00084 watch_fd_ref (WatchFD *watch_fd)
00085 {
00086   watch_fd->refcount += 1;
00087 }
00088 
00089 static void
00090 watch_fd_unref (WatchFD *watch_fd)
00091 {
00092   watch_fd->refcount -= 1;
00093 
00094   if (watch_fd->refcount == 0)
00095     {
00096       g_assert (watch_fd->removed);
00097   
00098       g_free (watch_fd);
00099     }
00100 }
00101 
00102 static dbus_int32_t connection_slot = -1;
00103 static dbus_int32_t server_slot = -1;
00104 
00105 static gboolean gsource_connection_prepare  (GSource     *source,
00106                                              gint        *timeout);
00107 static gboolean gsource_connection_check    (GSource     *source);
00108 static gboolean gsource_connection_dispatch (GSource     *source,
00109                                              GSourceFunc  callback,
00110                                              gpointer     user_data);
00111 static gboolean gsource_server_prepare      (GSource     *source,
00112                                              gint        *timeout);
00113 static gboolean gsource_server_check        (GSource     *source);
00114 static gboolean gsource_server_dispatch     (GSource     *source,
00115                                              GSourceFunc  callback,
00116                                              gpointer     user_data);
00117 
00118 static GSourceFuncs dbus_connection_funcs = {
00119   gsource_connection_prepare,
00120   gsource_connection_check,
00121   gsource_connection_dispatch,
00122   NULL
00123 };
00124 
00125 static GSourceFuncs dbus_server_funcs = {
00126   gsource_server_prepare,
00127   gsource_server_check,
00128   gsource_server_dispatch,
00129   NULL
00130 };
00131 
00132 static gboolean
00133 gsource_connection_prepare (GSource *source,
00134                             gint    *timeout)
00135 {
00136   DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
00137   
00138   *timeout = -1;
00139 
00140   return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
00141 }
00142 
00143 static gboolean
00144 gsource_server_prepare (GSource *source,
00145                         gint    *timeout)
00146 {
00147   *timeout = -1;
00148 
00149   return FALSE;
00150 }
00151 
00152 static gboolean
00153 dbus_gsource_check (GSource *source)
00154 {
00155   DBusGSource *dbus_source = (DBusGSource *)source;
00156   GList *list;
00157 
00158   list = dbus_source->watch_fds;
00159 
00160   while (list)
00161     {
00162       WatchFD *watch_fd = list->data;
00163 
00164       if (watch_fd->poll_fd.revents != 0)
00165         return TRUE;
00166 
00167       list = list->next;
00168     }
00169 
00170   return FALSE;  
00171 }
00172 
00173 static gboolean
00174 gsource_connection_check (GSource *source)
00175 {
00176   return dbus_gsource_check (source);
00177 }
00178 
00179 static gboolean
00180 gsource_server_check (GSource *source)
00181 {
00182   return dbus_gsource_check (source);
00183 }
00184 
00185 static gboolean
00186 dbus_gsource_dispatch (GSource     *source,
00187                        GSourceFunc  callback,
00188                        gpointer     user_data,
00189                        dbus_bool_t  is_server)
00190 {
00191    DBusGSource *dbus_source = (DBusGSource *)source;
00192    GList *copy, *list;
00193 
00194    /* Make a copy of the list and ref all WatchFDs */
00195    copy = g_list_copy (dbus_source->watch_fds);
00196    g_list_foreach (copy, (GFunc)watch_fd_ref, NULL);
00197    
00198    list = copy;
00199    while (list)
00200      {
00201        WatchFD *watch_fd = list->data;
00202 
00203        if (!watch_fd->removed && watch_fd->poll_fd.revents != 0)
00204          {
00205            guint condition = 0;
00206            
00207            if (watch_fd->poll_fd.revents & G_IO_IN)
00208              condition |= DBUS_WATCH_READABLE;
00209            if (watch_fd->poll_fd.revents & G_IO_OUT)
00210              condition |= DBUS_WATCH_WRITABLE;
00211            if (watch_fd->poll_fd.revents & G_IO_ERR)
00212              condition |= DBUS_WATCH_ERROR;
00213            if (watch_fd->poll_fd.revents & G_IO_HUP)
00214              condition |= DBUS_WATCH_HANGUP;
00215 
00216            dbus_watch_handle (watch_fd->watch, condition);
00217          }
00218 
00219        list = list->next;
00220      }
00221 
00222    g_list_foreach (copy, (GFunc)watch_fd_unref, NULL);   
00223    g_list_free (copy);   
00224 
00225    return TRUE;
00226 }
00227 
00228 static gboolean
00229 gsource_connection_dispatch (GSource     *source,
00230                              GSourceFunc  callback,
00231                              gpointer     user_data)
00232 {
00233   DBusGSource *dbus_source = (DBusGSource *)source;
00234   DBusConnection *connection = dbus_source->connection_or_server;
00235 
00236   dbus_connection_ref (connection);
00237 
00238   dbus_gsource_dispatch (source, callback, user_data,
00239                          FALSE);
00240   
00241   /* Dispatch messages */
00242   while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS)
00243     ;
00244 
00245    dbus_connection_unref (connection);
00246    
00247    return TRUE;
00248 }
00249 
00250 static gboolean
00251 gsource_server_dispatch (GSource     *source,
00252                          GSourceFunc  callback,
00253                          gpointer     user_data)
00254 {
00255   DBusGSource *dbus_source = (DBusGSource *)source;
00256   DBusServer *server = dbus_source->connection_or_server;
00257 
00258   dbus_server_ref (server);
00259 
00260   dbus_gsource_dispatch (source, callback, user_data,
00261                          TRUE);
00262 
00263   dbus_server_unref (server);
00264    
00265   return TRUE;
00266 }
00267      
00268 static dbus_bool_t
00269 add_watch (DBusWatch *watch,
00270            gpointer   data)
00271 {
00272   WatchFD *watch_fd;
00273   DBusGSource *dbus_source;
00274   guint flags;
00275 
00276   if (!dbus_watch_get_enabled (watch))
00277     return TRUE;
00278   
00279   dbus_source = data;
00280 
00281   watch_fd = watch_fd_new ();
00282   watch_fd->poll_fd.fd = dbus_watch_get_fd (watch);
00283   watch_fd->poll_fd.events = 0;
00284   flags = dbus_watch_get_flags (watch);
00285   dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref);
00286 
00287   if (flags & DBUS_WATCH_READABLE)
00288     watch_fd->poll_fd.events |= G_IO_IN;
00289   if (flags & DBUS_WATCH_WRITABLE)
00290     watch_fd->poll_fd.events |= G_IO_OUT;
00291   watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP;
00292 
00293   watch_fd->watch = watch;
00294   
00295   g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00296 
00297   dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd);
00298 
00299   return TRUE;
00300 }
00301 
00302 static void
00303 remove_watch (DBusWatch *watch,
00304               gpointer   data)
00305 {
00306   DBusGSource *dbus_source = data;
00307   WatchFD *watch_fd;
00308   
00309   watch_fd = dbus_watch_get_data (watch);
00310   if (watch_fd == NULL)
00311     return; /* probably a not-enabled watch that was added */
00312 
00313   watch_fd->removed = TRUE;
00314   watch_fd->watch = NULL;  
00315   
00316   dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd);
00317 
00318   g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00319 
00320   dbus_watch_set_data (watch, NULL, NULL); /* needed due to watch_toggled
00321                                             * breaking add/remove symmetry
00322                                             */
00323 }
00324 
00325 static void
00326 watch_toggled (DBusWatch *watch,
00327                void      *data)
00328 {
00329   /* Because we just exit on OOM, enable/disable is
00330    * no different from add/remove
00331    */
00332   if (dbus_watch_get_enabled (watch))
00333     add_watch (watch, data);
00334   else
00335     remove_watch (watch, data);
00336 }
00337 
00338 static gboolean
00339 timeout_handler (gpointer data)
00340 {
00341   DBusTimeout *timeout = data;
00342 
00343   dbus_timeout_handle (timeout);
00344 
00345   return TRUE;
00346 }
00347 
00348 static dbus_bool_t
00349 add_timeout (DBusTimeout *timeout,
00350              void        *data)
00351 {
00352   DBusGSource *dbus_source = data;
00353   GSource *source;
00354 
00355   if (!dbus_timeout_get_enabled (timeout))
00356     return TRUE;
00357   
00358   source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
00359   g_source_set_callback (source, timeout_handler, timeout, NULL);
00360   g_source_attach (source, dbus_source->context);
00361   
00362   dbus_timeout_set_data (timeout, GUINT_TO_POINTER (g_source_get_id (source)),
00363                          NULL);
00364 
00365   return TRUE;
00366 }
00367 
00368 static void
00369 remove_timeout (DBusTimeout *timeout,
00370                 void        *data)
00371 {
00372   guint timeout_tag;
00373   
00374   timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
00375 
00376   if (timeout_tag != 0) /* if 0, probably timeout was disabled */
00377     g_source_remove (timeout_tag);
00378 }
00379 
00380 static void
00381 timeout_toggled (DBusTimeout *timeout,
00382                  void        *data)
00383 {
00384   /* Because we just exit on OOM, enable/disable is
00385    * no different from add/remove
00386    */
00387   if (dbus_timeout_get_enabled (timeout))
00388     add_timeout (timeout, data);
00389   else
00390     remove_timeout (timeout, data);
00391 }
00392 
00393 
00394 static void
00395 free_source (GSource *source)
00396 {
00397   g_source_destroy (source);
00398 }
00399 
00400 static void
00401 wakeup_main (void *data)
00402 {
00403   DBusGSource *dbus_source = data;
00404 
00405   g_main_context_wakeup (dbus_source->context);
00406 }
00407 
00408  /* End of GLib bindings internals */
00410 
00415 static GSource*
00416 create_source (void         *connection_or_server,
00417                GSourceFuncs *funcs,
00418                GMainContext *context)
00419 {
00420   GSource *source;
00421   DBusGSource *dbus_source;
00422 
00423   source = g_source_new (funcs, sizeof (DBusGSource));
00424   
00425   dbus_source = (DBusGSource *)source;  
00426   dbus_source->connection_or_server = connection_or_server;
00427   dbus_source->context = context;
00428 
00429   return source;
00430 }
00431 
00441 void
00442 dbus_connection_setup_with_g_main (DBusConnection *connection,
00443                                    GMainContext   *context)
00444 {
00445   GSource *source;
00446 
00447   source = create_source (connection, &dbus_connection_funcs, context);
00448 
00449   if (!dbus_connection_set_watch_functions (connection,
00450                                             add_watch,
00451                                             remove_watch,
00452                                             watch_toggled,
00453                                             source, NULL))
00454     goto nomem;
00455 
00456   if (!dbus_connection_set_timeout_functions (connection,
00457                                               add_timeout,
00458                                               remove_timeout,
00459                                               timeout_toggled,
00460                                               NULL, NULL))
00461     goto nomem;
00462     
00463   dbus_connection_set_wakeup_main_function (connection,
00464                                             wakeup_main,
00465                                             source, NULL);
00466       
00467   g_source_attach (source, context);
00468 
00469   /* FIXME we never free the slot, so its refcount just keeps growing,
00470    * which is kind of broken.
00471    */
00472   dbus_connection_allocate_data_slot (&connection_slot);
00473   if (connection_slot < 0)
00474     goto nomem;
00475 
00476   if (!dbus_connection_set_data (connection, connection_slot, source,
00477                                  (DBusFreeFunction)free_source))
00478     goto nomem;
00479 
00480   return;
00481 
00482  nomem:
00483   g_error ("Not enough memory to set up DBusConnection for use with GLib");
00484 }
00485 
00494 void
00495 dbus_server_setup_with_g_main (DBusServer   *server,
00496                                GMainContext *context)
00497 {
00498   GSource *source;
00499 
00500   source = create_source (server, &dbus_server_funcs, context);
00501 
00502   dbus_server_set_watch_functions (server,
00503                                    add_watch,
00504                                    remove_watch,
00505                                    watch_toggled,
00506                                    source, NULL);
00507 
00508   dbus_server_set_timeout_functions (server,
00509                                      add_timeout,
00510                                      remove_timeout,
00511                                      timeout_toggled,
00512                                      NULL, NULL);
00513   
00514   g_source_attach (source, context);
00515 
00516   /* FIXME we never free the slot, so its refcount just keeps growing,
00517    * which is kind of broken.
00518    */
00519   dbus_server_allocate_data_slot (&server_slot);
00520   if (server_slot < 0)
00521     goto nomem;
00522 
00523   if (!dbus_server_set_data (server, server_slot, source,
00524                              (DBusFreeFunction)free_source))
00525     goto nomem;
00526 
00527   return;
00528 
00529  nomem:
00530   g_error ("Not enough memory to set up DBusServer for use with GLib");
00531 }
00532  /* end of public API */

Generated on Wed Oct 22 14:05:01 2003 for D-BUS by doxygen1.3-rc3