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.1
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/dbus-glib.h>
00026 #include <dbus/dbus-glib-lowlevel.h>
00027 #include "dbus-gtest.h"
00028 #include "dbus-gutils.h"
00029 
00030 #include <libintl.h>
00031 #define _(x) dgettext (GETTEXT_PACKAGE, x)
00032 #define N_(x) x
00033 
00056 typedef struct DBusGSource DBusGSource;
00057 
00061 struct DBusGSource
00062 {
00063   GSource source; 
00065   GList *watch_fds;      
00067   GMainContext *context; 
00069   void *connection_or_server; 
00070 };
00071 
00076 typedef struct
00077 {
00078   int refcount;     
00080   GPollFD poll_fd;  
00081   DBusWatch *watch; 
00083   unsigned int removed : 1; 
00084 } WatchFD;
00085 
00086 static WatchFD *
00087 watch_fd_new (void)
00088 {
00089   WatchFD *watch_fd;
00090 
00091   watch_fd = g_new0 (WatchFD, 1);
00092   watch_fd->refcount = 1;
00093 
00094   return watch_fd;
00095 }
00096 
00097 static WatchFD * 
00098 watch_fd_ref (WatchFD *watch_fd)
00099 {
00100   watch_fd->refcount += 1;
00101 
00102   return watch_fd;
00103 }
00104 
00105 static void
00106 watch_fd_unref (WatchFD *watch_fd)
00107 {
00108   watch_fd->refcount -= 1;
00109 
00110   if (watch_fd->refcount == 0)
00111     {
00112       g_assert (watch_fd->removed);
00113   
00114       g_free (watch_fd);
00115     }
00116 }
00117 
00118 static dbus_int32_t connection_slot = -1;
00119 static dbus_int32_t server_slot = -1;
00120 
00121 static gboolean gsource_connection_prepare  (GSource     *source,
00122                                              gint        *timeout);
00123 static gboolean gsource_connection_check    (GSource     *source);
00124 static gboolean gsource_connection_dispatch (GSource     *source,
00125                                              GSourceFunc  callback,
00126                                              gpointer     user_data);
00127 static gboolean gsource_server_prepare      (GSource     *source,
00128                                              gint        *timeout);
00129 static gboolean gsource_server_check        (GSource     *source);
00130 static gboolean gsource_server_dispatch     (GSource     *source,
00131                                              GSourceFunc  callback,
00132                                              gpointer     user_data);
00133 
00134 static GSourceFuncs dbus_connection_funcs = {
00135   gsource_connection_prepare,
00136   gsource_connection_check,
00137   gsource_connection_dispatch,
00138   NULL
00139 };
00140 
00141 static GSourceFuncs dbus_server_funcs = {
00142   gsource_server_prepare,
00143   gsource_server_check,
00144   gsource_server_dispatch,
00145   NULL
00146 };
00147 
00148 static gboolean
00149 gsource_connection_prepare (GSource *source,
00150                             gint    *timeout)
00151 {
00152   DBusConnection *connection = ((DBusGSource *)source)->connection_or_server;
00153   
00154   *timeout = -1;
00155 
00156   return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);  
00157 }
00158 
00159 static gboolean
00160 gsource_server_prepare (GSource *source,
00161                         gint    *timeout)
00162 {
00163   *timeout = -1;
00164 
00165   return FALSE;
00166 }
00167 
00168 static gboolean
00169 dbus_gsource_check (GSource *source)
00170 {
00171   DBusGSource *dbus_source = (DBusGSource *)source;
00172   GList *list;
00173 
00174   list = dbus_source->watch_fds;
00175 
00176   while (list)
00177     {
00178       WatchFD *watch_fd = list->data;
00179 
00180       if (watch_fd->poll_fd.revents != 0)
00181         return TRUE;
00182 
00183       list = list->next;
00184     }
00185 
00186   return FALSE;  
00187 }
00188 
00189 static gboolean
00190 gsource_connection_check (GSource *source)
00191 {
00192   return dbus_gsource_check (source);
00193 }
00194 
00195 static gboolean
00196 gsource_server_check (GSource *source)
00197 {
00198   return dbus_gsource_check (source);
00199 }
00200 
00201 static gboolean
00202 dbus_gsource_dispatch (GSource     *source,
00203                        GSourceFunc  callback,
00204                        gpointer     user_data,
00205                        dbus_bool_t  is_server)
00206 {
00207    DBusGSource *dbus_source = (DBusGSource *)source;
00208    GList *copy, *list;
00209 
00210    /* Make a copy of the list and ref all WatchFDs */
00211    copy = g_list_copy (dbus_source->watch_fds);
00212    g_list_foreach (copy, (GFunc)watch_fd_ref, NULL);
00213    
00214    list = copy;
00215    while (list)
00216      {
00217        WatchFD *watch_fd = list->data;
00218 
00219        if (!watch_fd->removed && watch_fd->poll_fd.revents != 0)
00220          {
00221            guint condition = 0;
00222            
00223            if (watch_fd->poll_fd.revents & G_IO_IN)
00224              condition |= DBUS_WATCH_READABLE;
00225            if (watch_fd->poll_fd.revents & G_IO_OUT)
00226              condition |= DBUS_WATCH_WRITABLE;
00227            if (watch_fd->poll_fd.revents & G_IO_ERR)
00228              condition |= DBUS_WATCH_ERROR;
00229            if (watch_fd->poll_fd.revents & G_IO_HUP)
00230              condition |= DBUS_WATCH_HANGUP;
00231 
00232            dbus_watch_handle (watch_fd->watch, condition);
00233          }
00234 
00235        list = list->next;
00236      }
00237 
00238    g_list_foreach (copy, (GFunc)watch_fd_unref, NULL);   
00239    g_list_free (copy);   
00240 
00241    return TRUE;
00242 }
00243 
00244 static gboolean
00245 gsource_connection_dispatch (GSource     *source,
00246                              GSourceFunc  callback,
00247                              gpointer     user_data)
00248 {
00249   DBusGSource *dbus_source = (DBusGSource *)source;
00250   DBusConnection *connection = dbus_source->connection_or_server;
00251 
00252   dbus_connection_ref (connection);
00253 
00254   dbus_gsource_dispatch (source, callback, user_data,
00255                          FALSE);
00256   
00257   /* Dispatch messages */
00258   while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS)
00259     ;
00260 
00261    dbus_connection_unref (connection);
00262    
00263    return TRUE;
00264 }
00265 
00266 static gboolean
00267 gsource_server_dispatch (GSource     *source,
00268                          GSourceFunc  callback,
00269                          gpointer     user_data)
00270 {
00271   DBusGSource *dbus_source = (DBusGSource *)source;
00272   DBusServer *server = dbus_source->connection_or_server;
00273 
00274   dbus_server_ref (server);
00275 
00276   dbus_gsource_dispatch (source, callback, user_data,
00277                          TRUE);
00278 
00279   dbus_server_unref (server);
00280    
00281   return TRUE;
00282 }
00283      
00284 static dbus_bool_t
00285 add_watch (DBusWatch *watch,
00286            gpointer   data)
00287 {
00288   WatchFD *watch_fd;
00289   DBusGSource *dbus_source;
00290   guint flags;
00291 
00292   if (!dbus_watch_get_enabled (watch))
00293     return TRUE;
00294   
00295   dbus_source = data;
00296 
00297   watch_fd = watch_fd_new ();
00298   watch_fd->poll_fd.fd = dbus_watch_get_fd (watch);
00299   watch_fd->poll_fd.events = 0;
00300   flags = dbus_watch_get_flags (watch);
00301   dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref);
00302 
00303   if (flags & DBUS_WATCH_READABLE)
00304     watch_fd->poll_fd.events |= G_IO_IN;
00305   if (flags & DBUS_WATCH_WRITABLE)
00306     watch_fd->poll_fd.events |= G_IO_OUT;
00307   watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP;
00308 
00309   watch_fd->watch = watch;
00310   
00311   g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00312 
00313   dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd);
00314 
00315   return TRUE;
00316 }
00317 
00318 static void
00319 remove_watch (DBusWatch *watch,
00320               gpointer   data)
00321 {
00322   DBusGSource *dbus_source = data;
00323   WatchFD *watch_fd;
00324   
00325   watch_fd = dbus_watch_get_data (watch);
00326   if (watch_fd == NULL)
00327     return; /* probably a not-enabled watch that was added */
00328 
00329   watch_fd->removed = TRUE;
00330   watch_fd->watch = NULL;  
00331   
00332   dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd);
00333 
00334   g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd);
00335 
00336   dbus_watch_set_data (watch, NULL, NULL); /* needed due to watch_toggled
00337                                             * breaking add/remove symmetry
00338                                             */
00339 }
00340 
00341 static void
00342 watch_toggled (DBusWatch *watch,
00343                void      *data)
00344 {
00345   /* Because we just exit on OOM, enable/disable is
00346    * no different from add/remove
00347    */
00348   if (dbus_watch_get_enabled (watch))
00349     add_watch (watch, data);
00350   else
00351     remove_watch (watch, data);
00352 }
00353 
00354 static gboolean
00355 timeout_handler (gpointer data)
00356 {
00357   DBusTimeout *timeout = data;
00358 
00359   dbus_timeout_handle (timeout);
00360 
00361   return TRUE;
00362 }
00363 
00364 static dbus_bool_t
00365 add_timeout (DBusTimeout *timeout,
00366              void        *data)
00367 {
00368   DBusGSource *dbus_source = data;
00369   GSource *source;
00370 
00371   if (!dbus_timeout_get_enabled (timeout))
00372     return TRUE;
00373   
00374   source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
00375   g_source_set_callback (source, timeout_handler, timeout, NULL);
00376   g_source_attach (source, dbus_source->context);
00377   
00378   dbus_timeout_set_data (timeout, GUINT_TO_POINTER (g_source_get_id (source)),
00379                          NULL);
00380 
00381   return TRUE;
00382 }
00383 
00384 static void
00385 remove_timeout (DBusTimeout *timeout,
00386                 void        *data)
00387 {
00388   guint timeout_tag;
00389   
00390   timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
00391 
00392   if (timeout_tag != 0) /* if 0, probably timeout was disabled */
00393     g_source_remove (timeout_tag);
00394 }
00395 
00396 static void
00397 timeout_toggled (DBusTimeout *timeout,
00398                  void        *data)
00399 {
00400   /* Because we just exit on OOM, enable/disable is
00401    * no different from add/remove
00402    */
00403   if (dbus_timeout_get_enabled (timeout))
00404     add_timeout (timeout, data);
00405   else
00406     remove_timeout (timeout, data);
00407 }
00408 
00409 
00410 static void
00411 free_source (GSource *source)
00412 {
00413   g_source_destroy (source);
00414 }
00415 
00416 static void
00417 wakeup_main (void *data)
00418 {
00419   DBusGSource *dbus_source = data;
00420 
00421   g_main_context_wakeup (dbus_source->context);
00422 }
00423 
00424  /* End of GLib bindings internals */
00426 
00431 static GSource*
00432 create_source (void         *connection_or_server,
00433                GSourceFuncs *funcs,
00434                GMainContext *context)
00435 {
00436   GSource *source;
00437   DBusGSource *dbus_source;
00438 
00439   source = g_source_new (funcs, sizeof (DBusGSource));
00440   
00441   dbus_source = (DBusGSource *)source;  
00442   dbus_source->connection_or_server = connection_or_server;
00443   dbus_source->context = context;
00444 
00445   return source;
00446 }
00447 
00462 void
00463 dbus_connection_setup_with_g_main (DBusConnection *connection,
00464                                    GMainContext   *context)
00465 {
00466   GSource *source;
00467   
00468   /* FIXME we never free the slot, so its refcount just keeps growing,
00469    * which is kind of broken.
00470    */
00471   dbus_connection_allocate_data_slot (&connection_slot);
00472   if (connection_slot < 0)
00473     goto nomem;
00474 
00475   /* So we can test for equality below */
00476   if (context == NULL)
00477     context = g_main_context_default ();
00478   
00479   source = dbus_connection_get_data (connection, connection_slot);
00480   if (source != NULL)
00481     {
00482       if (source->context == context)
00483         return; /* nothing to do */
00484 
00485       /* Remove the previous source and move to a new context */
00486       dbus_connection_set_data (connection, connection_slot, NULL, NULL);
00487       source = NULL;
00488     }
00489   
00490   source = create_source (connection, &dbus_connection_funcs, context);
00491 
00492   if (!dbus_connection_set_watch_functions (connection,
00493                                             add_watch,
00494                                             remove_watch,
00495                                             watch_toggled,
00496                                             source, NULL))
00497     goto nomem;
00498 
00499   if (!dbus_connection_set_timeout_functions (connection,
00500                                               add_timeout,
00501                                               remove_timeout,
00502                                               timeout_toggled,
00503                                               source, NULL))
00504     goto nomem;
00505     
00506   dbus_connection_set_wakeup_main_function (connection,
00507                                             wakeup_main,
00508                                             source, NULL);
00509       
00510   g_source_attach (source, context);
00511 
00512   if (!dbus_connection_set_data (connection, connection_slot, source,
00513                                  (DBusFreeFunction)free_source))
00514     goto nomem;
00515 
00516   return;
00517 
00518  nomem:
00519   g_error ("Not enough memory to set up DBusConnection for use with GLib");
00520 }
00521 
00535 void
00536 dbus_server_setup_with_g_main (DBusServer   *server,
00537                                GMainContext *context)
00538 {
00539   GSource *source;
00540 
00541   dbus_server_allocate_data_slot (&server_slot);
00542   if (server_slot < 0)
00543     goto nomem;
00544 
00545   /* So we can test for equality below */
00546   if (context == NULL)
00547     context = g_main_context_default ();
00548   
00549   source = dbus_server_get_data (server, server_slot);
00550   if (source != NULL)
00551     {
00552       if (source->context == context)
00553         return; /* nothing to do */
00554 
00555       /* Remove the previous source and move to a new context */
00556       dbus_server_set_data (server, server_slot, NULL, NULL);
00557       source = NULL;
00558     }
00559   
00560   source = create_source (server, &dbus_server_funcs, context);
00561 
00562   dbus_server_set_watch_functions (server,
00563                                    add_watch,
00564                                    remove_watch,
00565                                    watch_toggled,
00566                                    source, NULL);
00567 
00568   dbus_server_set_timeout_functions (server,
00569                                      add_timeout,
00570                                      remove_timeout,
00571                                      timeout_toggled,
00572                                      NULL, NULL);
00573   
00574   g_source_attach (source, context);
00575 
00576   if (!dbus_server_set_data (server, server_slot, source,
00577                              (DBusFreeFunction)free_source))
00578     goto nomem;
00579 
00580   return;
00581 
00582  nomem:
00583   g_error ("Not enough memory to set up DBusServer for use with GLib");
00584 }
00585 
00597 DBusGConnection*
00598 dbus_g_bus_get (DBusBusType     type,
00599                 GError        **error)
00600 {
00601   DBusConnection *connection;
00602   DBusError derror;
00603 
00604   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
00605   
00606   dbus_error_init (&derror);
00607 
00608   connection = dbus_bus_get (type, &derror);
00609   if (connection == NULL)
00610     {
00611       dbus_set_g_error (error, &derror);
00612       dbus_error_free (&derror);
00613     }
00614   else
00615     {
00616       /* does nothing if it's already been done */
00617       dbus_connection_setup_with_g_main (connection, NULL);
00618     }
00619 
00620   return DBUS_G_CONNECTION_FROM_CONNECTION (connection);
00621 }
00622 
00629 GQuark
00630 dbus_g_error_quark (void)
00631 {
00632   static GQuark quark = 0;
00633   if (quark == 0)
00634     quark = g_quark_from_static_string ("g-exec-error-quark");
00635   return quark;
00636 }
00637 
00638 
00647 void
00648 dbus_set_g_error (GError   **gerror,
00649                   DBusError *derror)
00650 {
00651   g_return_if_fail (derror != NULL);
00652   g_return_if_fail (dbus_error_is_set (derror));
00653   
00654   g_set_error (gerror, DBUS_GERROR,
00655                DBUS_GERROR_FAILED,
00656                _("D-BUS error %s: %s"),
00657                derror->name, derror->message);  
00658 }
00659 
00665 GType
00666 dbus_connection_get_g_type (void)
00667 {
00668   static GType our_type = 0;
00669   
00670   if (our_type == 0)
00671     our_type = g_boxed_type_register_static ("DBusConnection",
00672                                              (GBoxedCopyFunc) dbus_connection_ref,
00673                                              (GBoxedFreeFunc) dbus_connection_unref);
00674 
00675   return our_type;
00676 }
00677 
00683 GType
00684 dbus_message_get_g_type (void)
00685 {
00686   static GType our_type = 0;
00687   
00688   if (our_type == 0)
00689     our_type = g_boxed_type_register_static ("DBusMessage",
00690                                              (GBoxedCopyFunc) dbus_message_ref,
00691                                              (GBoxedFreeFunc) dbus_message_unref);
00692 
00693   return our_type;
00694 }
00695 
00696 static DBusGConnection*
00697 dbus_g_connection_ref (DBusGConnection *gconnection)
00698 {
00699   DBusConnection *c;
00700 
00701   c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
00702   dbus_connection_ref (c);
00703   return gconnection;
00704 }
00705 
00706 static void
00707 dbus_g_connection_unref (DBusGConnection *gconnection)
00708 {
00709   DBusConnection *c;
00710 
00711   c = DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
00712   dbus_connection_unref (c);
00713 }
00714 
00715 
00716 static DBusGMessage*
00717 dbus_g_message_ref (DBusGMessage *gmessage)
00718 {
00719   DBusMessage *c;
00720 
00721   c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
00722   dbus_message_ref (c);
00723   return gmessage;
00724 }
00725 
00726 static void
00727 dbus_g_message_unref (DBusGMessage *gmessage)
00728 {
00729   DBusMessage *c;
00730 
00731   c = DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
00732   dbus_message_unref (c);
00733 }
00734 
00740 GType
00741 dbus_g_connection_get_g_type (void)
00742 {
00743   static GType our_type = 0;
00744   
00745   if (our_type == 0)
00746     our_type = g_boxed_type_register_static ("DBusGConnection",
00747                                              (GBoxedCopyFunc) dbus_g_connection_ref,
00748                                              (GBoxedFreeFunc) dbus_g_connection_unref);
00749 
00750   return our_type;
00751 }
00752 
00758 GType
00759 dbus_g_message_get_g_type (void)
00760 {
00761   static GType our_type = 0;
00762   
00763   if (our_type == 0)
00764     our_type = g_boxed_type_register_static ("DBusGMessage",
00765                                              (GBoxedCopyFunc) dbus_g_message_ref,
00766                                              (GBoxedFreeFunc) dbus_g_message_unref);
00767 
00768   return our_type;
00769 }
00770 
00777 DBusConnection*
00778 dbus_g_connection_get_connection (DBusGConnection *gconnection)
00779 {
00780   return DBUS_CONNECTION_FROM_G_CONNECTION (gconnection);
00781 }
00782 
00789 DBusMessage*
00790 dbus_g_message_get_message (DBusGMessage *gmessage)
00791 {
00792   return DBUS_MESSAGE_FROM_G_MESSAGE (gmessage);
00793 }
00794  /* end of public API */
00796 
00797 #ifdef DBUS_BUILD_TESTS
00798 
00804 gboolean
00805 _dbus_gmain_test (const char *test_data_dir)
00806 {
00807   
00808   return TRUE;
00809 }
00810 
00811 #endif /* DBUS_BUILD_TESTS */

Generated on Sat Sep 25 19:17:11 2004 for D-BUS by  doxygen 1.3.8-20040913