diff options
Diffstat (limited to 'glib')
| -rw-r--r-- | glib/dbus-glib.h | 2 | ||||
| -rw-r--r-- | glib/dbus-gproxy.c | 258 | 
2 files changed, 242 insertions, 18 deletions
| diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 79c1e116..46f4555d 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -123,7 +123,7 @@ void             dbus_gproxy_connect_signal        (DBusGProxy               *pr                                                      const char               *signal_name,                                                      DBusGProxySignalHandler   handler,                                                      void                     *data, -                                                    GFreeFunc                 free_data_func); +                                                    GClosureNotify            free_data_func);  void             dbus_gproxy_disconnect_signal     (DBusGProxy               *proxy,                                                      const char               *signal_name,                                                      DBusGProxySignalHandler   handler, diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index ebcbb5d4..99900e4c 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -44,6 +44,9 @@ struct DBusGProxy    char *interface;            /**< Interface messages go to or NULL */  }; +/** + * Class struct for DBusGProxy + */  struct DBusGProxyClass  {    GObjectClass parent_class;   @@ -52,6 +55,8 @@ struct DBusGProxyClass  static void dbus_gproxy_init          (DBusGProxy      *proxy);  static void dbus_gproxy_class_init    (DBusGProxyClass *klass);  static void dbus_gproxy_finalize      (GObject         *object); +static void dbus_gproxy_dispose       (GObject         *object); +static void dbus_gproxy_destroy       (DBusGProxy      *proxy);  static void dbus_gproxy_emit_received (DBusGProxy      *proxy,                                         DBusMessage     *message); @@ -174,6 +179,11 @@ dbus_gproxy_manager_unref (DBusGProxyManager *manager)        if (manager->proxy_lists)          { +          /* can't have any proxies left since they hold +           * a reference to the proxy manager. +           */ +          g_assert (g_hash_table_size (manager->proxy_lists) == 0); +                      g_hash_table_destroy (manager->proxy_lists);            manager->proxy_lists = NULL;          } @@ -447,11 +457,13 @@ dbus_gproxy_manager_unregister (DBusGProxyManager *manager,    LOCK_MANAGER (manager); +#ifndef G_DISABLE_CHECKS    if (manager->proxy_lists == NULL)      {        g_warning ("Trying to disconnect a signal on a proxy but none are connected\n");        return;      } +#endif    tri = tristring_from_proxy (proxy); @@ -459,21 +471,70 @@ dbus_gproxy_manager_unregister (DBusGProxyManager *manager,    g_free (tri); +#ifndef G_DISABLE_CHECKS    if (list == NULL)      {        g_warning ("Trying to disconnect a signal on a proxy but none are connected\n");        return;      } +#endif    g_assert (g_slist_find (list->proxies, proxy) != NULL);    list->proxies = g_slist_remove (list->proxies, proxy);    g_assert (g_slist_find (list->proxies, proxy) == NULL); + +  if (g_hash_table_size (manager->proxy_lists) == 0) +    { +      g_hash_table_destroy (manager->proxy_lists); +      manager->proxy_lists = NULL; +    }    UNLOCK_MANAGER (manager);  } +static void +list_proxies_foreach (gpointer key, +                      gpointer value, +                      gpointer user_data) +{ +  DBusGProxyList *list; +  GSList **ret; +  GSList *tmp; +   +  list = value; +  ret = user_data; + +  tmp = list->proxies; +  while (tmp != NULL) +    { +      DBusGProxy *proxy = DBUS_GPROXY (tmp->data); + +      g_object_ref (proxy); +      *ret = g_slist_prepend (*ret, proxy); +       +      tmp = tmp->next; +    } +} + +static GSList* +dbus_gproxy_manager_list_all (DBusGProxyManager *manager) +{ +  GSList *ret; + +  ret = NULL; + +  if (manager->proxy_lists) +    { +      g_hash_table_foreach (manager->proxy_lists, +                            list_proxies_foreach, +                            &ret); +    } + +  return ret; +} +  static DBusHandlerResult  dbus_gproxy_manager_filter (DBusConnection    *connection,                              DBusMessage       *message, @@ -481,18 +542,48 @@ dbus_gproxy_manager_filter (DBusConnection    *connection,  {    DBusGProxyManager *manager; -  manager = user_data; -    if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +  manager = user_data; + +  dbus_gproxy_manager_ref (manager); +   +  LOCK_MANAGER (manager); +      if (dbus_message_is_signal (message,                                DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,                                "Disconnected"))      { -      /* FIXME g_object_run_dispose() all the proxies; should proxies have -       * a "destroy" signal? +      /* Destroy all the proxies, quite possibly resulting in unreferencing +       * the proxy manager and the connection as well.         */ +      GSList *all; +      GSList *tmp; + +      all = dbus_gproxy_manager_list_all (manager); + +      tmp = all; +      while (tmp != NULL) +        { +          DBusGProxy *proxy; + +          proxy = DBUS_GPROXY (tmp->data); + +          UNLOCK_MANAGER (manager); +          dbus_gproxy_destroy (proxy); +          g_object_unref (G_OBJECT (proxy)); +          LOCK_MANAGER (manager); +           +          tmp = tmp->next; +        } + +      g_slist_free (all); + +#ifndef G_DISABLE_CHECKS +      if (manager->proxy_lists != NULL) +        g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak."); +#endif      }    else      { @@ -507,14 +598,38 @@ dbus_gproxy_manager_filter (DBusConnection    *connection,          list = NULL;        g_free (tri); + +      /* Emit the signal */        if (list != NULL)          { -          /* FIXME Emit the signal on each proxy in the list */ -           +          GSList *tmp; +          GSList *copy; +          copy = g_slist_copy (list->proxies); +          g_slist_foreach (copy, (GFunc) g_object_ref, NULL); +           +          tmp = copy; +          while (tmp != NULL) +            { +              DBusGProxy *proxy; + +              proxy = DBUS_GPROXY (tmp->data); + +              UNLOCK_MANAGER (manager); +              dbus_gproxy_emit_received (proxy, message); +              g_object_unref (G_OBJECT (proxy)); +              LOCK_MANAGER (manager); +               +              tmp = tmp->next; +            } + +          g_slist_free (copy);          }      } + +  UNLOCK_MANAGER (manager); +  dbus_gproxy_manager_unref (manager);    /* "Handling" signals doesn't make sense, they are for everyone     * who cares @@ -530,6 +645,7 @@ dbus_gproxy_manager_filter (DBusConnection    *connection,  enum  { +  DESTROY,    RECEIVED,    LAST_SIGNAL  }; @@ -551,7 +667,17 @@ dbus_gproxy_class_init (DBusGProxyClass *klass)    parent_class = g_type_class_peek_parent (klass);    object_class->finalize = dbus_gproxy_finalize; - +  object_class->dispose = dbus_gproxy_dispose; +   +  signals[DESTROY] = +    g_signal_new ("destroy", +		  G_OBJECT_CLASS_TYPE (object_class), +                  G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, +                  0, +		  NULL, NULL, +                  g_cclosure_marshal_VOID__VOID, +		  G_TYPE_NONE, 0); +      signals[RECEIVED] =      g_signal_new ("received",  		  G_OBJECT_CLASS_TYPE (object_class), @@ -563,6 +689,19 @@ dbus_gproxy_class_init (DBusGProxyClass *klass)                    DBUS_TYPE_MESSAGE);  } + +static void +dbus_gproxy_dispose (GObject *object) +{ +  DBusGProxy *proxy; + +  proxy = DBUS_GPROXY (object); + +  g_signal_emit (object, signals[DESTROY], 0); +   +  G_OBJECT_CLASS (parent_class)->dispose (object); +} +  static void  dbus_gproxy_finalize (GObject *object)  { @@ -583,6 +722,15 @@ dbus_gproxy_finalize (GObject *object)    G_OBJECT_CLASS (parent_class)->finalize (object);  } +static void +dbus_gproxy_destroy (DBusGProxy *proxy) +{ +  /* FIXME do we need the GTK_IN_DESTRUCTION style flag +   * from GtkObject? +   */ +  g_object_run_dispose (G_OBJECT (proxy)); +} +  static char*  create_signal_detail (const char *interface,                        const char *signal) @@ -697,18 +845,22 @@ dbus_gproxy_new (DBusConnection *connection,  }  /** - * Creates a new proxy for a remote interface. Method calls and signal - * connections over this proxy will go to the service owner; the - * service owner is expected to support the given interface name. THE - * SERVICE OWNER MAY CHANGE OVER TIME, for example between two - * different method calls. If you need a fixed owner, you need to - * request the current owner and bind a proxy to that rather than to - * the generic service name; see dbus_gproxy_new_for_service_owner(). + * Creates a new proxy for a remote interface exported by a service on + * a message bus. Method calls and signal connections over this proxy + * will go to the service owner; the service owner is expected to + * support the given interface name. THE SERVICE OWNER MAY CHANGE OVER + * TIME, for example between two different method calls. If you need a + * fixed owner, you need to request the current owner and bind a proxy + * to that rather than to the generic service name; see + * dbus_gproxy_new_for_service_owner().   *   * A service-associated proxy only makes sense with a message bus,   * not for app-to-app direct dbus connections.   * - * @param connection the connection to the remote bus or app + * This proxy will only emit the "destroy" signal if the #DBusConnection + * is disconnected or the proxy is has no remaining references. + * + * @param connection the connection to the remote bus   * @param service_name name of the service on the message bus   * @param path_name name of the object inside the service to call methods on   * @param interface_name name of the interface to call methods on @@ -734,6 +886,75 @@ dbus_gproxy_new_for_service (DBusConnection *connection,  }  /** + * Similar to dbus_gproxy_new_for_service(), but makes a round-trip + * request to the message bus to get the current service owner, then + * binds the proxy specifically to the current owner. As a result, the + * service owner will not change over time, and the proxy will emit + * the "destroy" signal when the owner disappears from the message + * bus. + * + * An example of the difference between dbus_gproxy_new_for_service() + * and dbus_gproxy_new_for_service_owner(): if you pass the service name + * "org.freedesktop.Database" dbus_gproxy_new_for_service() remains bound + * to that name as it changes owner. dbus_gproxy_new_for_service_owner() + * will fail if the service has no owner. If the service has an owner, + * dbus_gproxy_new_for_service_owner() will bind to the unique name + * of that owner rather than the generic service name. + *  + * @param connection the connection to the remote bus + * @param service_name name of the service on the message bus + * @param path_name name of the object inside the service to call methods on + * @param interface_name name of the interface to call methods on + * @param error return location for an error + * @returns new proxy object, or #NULL on error + */ +DBusGProxy* +dbus_gproxy_new_for_service_owner (DBusConnection           *connection, +                                   const char               *service_name, +                                   const char               *path_name, +                                   const char               *interface_name, +                                   GError                  **error) +{ +  g_return_val_if_fail (connection != NULL, NULL); +  g_return_val_if_fail (service_name != NULL, NULL); +  g_return_val_if_fail (path_name != NULL, NULL); +  g_return_val_if_fail (interface_name != NULL, NULL); + + +} + +/** + * Creates a proxy for an object in peer application (one + * we're directly connected to). That is, this function is + * intended for use when there's no message bus involved, + * we're doing a simple 1-to-1 communication between two + * applications. + * + * + * @param connection the connection to the peer + * @param path_name name of the object inside the peer to call methods on + * @param interface_name name of the interface to call methods on + * @returns new proxy object + *  + */ +DBusGProxy* +dbus_gproxy_new_for_peer (DBusConnection           *connection, +                          const char               *path_name, +                          const char               *interface_name) +{ +  DBusGProxy *proxy; +   +  g_return_val_if_fail (connection != NULL, NULL); +  g_return_val_if_fail (path_name != NULL, NULL); +  g_return_val_if_fail (interface_name != NULL, NULL); + +  proxy = dbus_gproxy_new (connection, NULL, +                           path_name, interface_name); + +  return proxy; +} + +/**   * Invokes a method on a remote interface. This function does not   * block; instead it returns an opaque #DBusPendingCall object that   * tracks the pending call.  The method call will not be sent over the @@ -952,7 +1173,7 @@ dbus_gproxy_connect_signal (DBusGProxy             *proxy,                              const char             *signal_name,                              DBusGProxySignalHandler handler,                              void                   *data, -                            GFreeFunc               free_data_func) +                            GClosureNotify          free_data_func)  {    GClosure *closure;    char *detail; @@ -989,12 +1210,14 @@ dbus_gproxy_disconnect_signal (DBusGProxy             *proxy,    q = g_quark_try_string (detail);    g_free (detail); +#ifndef G_DISABLE_CHECKS    if (q == 0)      {        g_warning ("%s: No signal handlers for %s found on this DBusGProxy",                   G_GNUC_FUNCTION, signal_name);        return;      } +#endif    g_signal_handlers_disconnect_matched (G_OBJECT (proxy),                                          G_SIGNAL_MATCH_DETAIL | @@ -1018,7 +1241,8 @@ dbus_gproxy_disconnect_signal (DBusGProxy             *proxy,  dbus_bool_t  _dbus_gproxy_test (void)  { - +   +      return TRUE;  } | 
