--- /dev/null
+#include "dbus-gmarshal.h"
+
+#include <glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v) g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v) g_value_get_int (v)
+#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
+#define g_marshal_value_peek_long(v) g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
+#define g_marshal_value_peek_float(v) g_value_get_float (v)
+#define g_marshal_value_peek_double(v) g_value_get_double (v)
+#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v) g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v) g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ * Do not access GValues directly in your code. Instead, use the
+ * g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
+#define g_marshal_value_peek_char(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v) (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v) (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v) (v)->data[0].v_float
+#define g_marshal_value_peek_double(v) (v)->data[0].v_double
+#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* NONE:STRING,STRING,STRING (dbus-gmarshal.list:1) */
+void
+_dbus_g_marshal_VOID__STRING_STRING_STRING (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING) (gpointer data1,
+ gpointer arg_1,
+ gpointer arg_2,
+ gpointer arg_3,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_STRING_STRING callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 4);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_STRING_STRING) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_marshal_value_peek_string (param_values + 1),
+ g_marshal_value_peek_string (param_values + 2),
+ g_marshal_value_peek_string (param_values + 3),
+ data2);
+}
+
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "dbus-gutils.h"
+#include "dbus-gmarshal.h"
+#include "dbus-gvalue.h"
#include <string.h>
/**
char *name; /**< Name messages go to or NULL */
char *path; /**< Path messages go to or NULL */
char *interface; /**< Interface messages go to or NULL */
+
+ GData *signal_signatures; /**< D-BUS signatures for each signal */
};
/**
GObjectClass parent_class; /**< Parent class */
};
-static void dbus_g_proxy_init (DBusGProxy *proxy);
-static void dbus_g_proxy_class_init (DBusGProxyClass *klass);
-static void dbus_g_proxy_finalize (GObject *object);
-static void dbus_g_proxy_dispose (GObject *object);
-static void dbus_g_proxy_destroy (DBusGProxy *proxy);
-static void dbus_g_proxy_emit_received (DBusGProxy *proxy,
- DBusMessage *message);
-
+static void dbus_g_proxy_init (DBusGProxy *proxy);
+static void dbus_g_proxy_class_init (DBusGProxyClass *klass);
+static void dbus_g_proxy_finalize (GObject *object);
+static void dbus_g_proxy_dispose (GObject *object);
+static void dbus_g_proxy_destroy (DBusGProxy *proxy);
+static void dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
+ DBusMessage *message);
/**
* A list of proxies with a given name+path+interface, used to
proxy = DBUS_G_PROXY (tmp->data);
UNLOCK_MANAGER (manager);
- dbus_g_proxy_emit_received (proxy, message);
+ dbus_g_proxy_emit_remote_signal (proxy, message);
g_object_unref (G_OBJECT (proxy));
LOCK_MANAGER (manager);
enum
{
DESTROY,
- RECEIVED,
LAST_SIGNAL
};
static void
dbus_g_proxy_init (DBusGProxy *proxy)
{
- /* Nothing */
+ g_datalist_init (&proxy->signal_signatures);
}
static void
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
-
- signals[RECEIVED] =
- g_signal_new ("received",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__BOXED,
- G_TYPE_NONE, 1,
- DBUS_TYPE_MESSAGE);
}
proxy = DBUS_G_PROXY (object);
+ g_datalist_clear (&proxy->signal_signatures);
+
g_signal_emit (object, signals[DESTROY], 0);
G_OBJECT_CLASS (parent_class)->dispose (object);
g_object_run_dispose (G_OBJECT (proxy));
}
+/* this is to avoid people using g_signal_connect() directly,
+ * to avoid confusion with local signal names, and because
+ * of the horribly broken current setup (signals are added
+ * globally to all proxies)
+ */
static char*
-create_signal_detail (const char *interface,
- const char *signal)
+create_signal_name (const char *interface,
+ const char *signal)
{
GString *str;
+ char *p;
str = g_string_new (interface);
- g_string_append (str, ".");
-
+ g_string_append (str, "-");
+
g_string_append (str, signal);
+ /* GLib will silently barf on '.' in signal names */
+ p = str->str;
+ while (*p)
+ {
+ if (*p == '.')
+ *p = '-';
+ ++p;
+ }
+
return g_string_free (str, FALSE);
}
static void
-dbus_g_proxy_emit_received (DBusGProxy *proxy,
- DBusMessage *message)
+emit_remote_internal (DBusGProxy *proxy,
+ DBusMessage *message,
+ guint signal_id,
+ gboolean marshal_args)
+{
+#define MAX_SIGNATURE_ARGS 20
+ GValue values[MAX_SIGNATURE_ARGS];
+ int arg;
+ int i;
+
+ memset (&values[0], 0, sizeof (values));
+
+ arg = 0;
+
+ g_value_init (&values[arg], G_TYPE_FROM_INSTANCE (proxy));
+ g_value_set_instance (&values[arg], proxy);
+ ++arg;
+
+ if (marshal_args)
+ {
+ DBusMessageIter iter;
+ int dtype;
+
+ dbus_message_iter_init (message, &iter);
+
+ while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+ {
+ if (arg == MAX_SIGNATURE_ARGS)
+ {
+ g_warning ("Don't support more than %d signal args\n", MAX_SIGNATURE_ARGS);
+ goto out;
+ }
+
+ if (!dbus_gvalue_demarshal (&iter, &values[arg]))
+ {
+ g_warning ("Unable to convert arg type %d to GValue to emit DBusGProxy signal", dtype);
+ goto out;
+ }
+
+ ++arg;
+ dbus_message_iter_next (&iter);
+ }
+ }
+
+ g_signal_emitv (&values[0],
+ signal_id,
+ 0,
+ NULL);
+
+ out:
+ i = 0;
+ while (i < arg)
+ {
+ g_value_unset (&values[i]);
+ ++i;
+ }
+}
+
+static void
+dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
+ DBusMessage *message)
{
const char *interface;
const char *signal;
- char *detail;
+ char *name;
GQuark q;
interface = dbus_message_get_interface (message);
g_assert (interface != NULL);
g_assert (signal != NULL);
- detail = create_signal_detail (interface, signal);
+ name = create_signal_name (interface, signal);
/* If the quark isn't preexisting, there's no way there
* are any handlers connected. We don't want to create
* extra quarks for every possible signal.
*/
- q = g_quark_try_string (detail);
+ q = g_quark_try_string (name);
if (q != 0)
- g_signal_emit (G_OBJECT (proxy),
- signals[RECEIVED],
- q,
- message);
+ {
+ const char *signature;
- g_free (detail);
+ signature = g_datalist_id_get_data (&proxy->signal_signatures, q);
+ if (signature == NULL)
+ {
+ g_warning ("Signal '%s' has not been added to this proxy object\n",
+ name);
+ }
+ else if (!dbus_message_has_signature (message, signature))
+ {
+ g_warning ("Signature '%s' expected for signal '%s', actual signature '%s'\n",
+ signature,
+ name,
+ dbus_message_get_signature (message));
+ }
+ else
+ {
+ guint signal_id;
+
+ signal_id = g_signal_lookup (name, G_OBJECT_TYPE (proxy));
+ g_assert (signal_id != 0); /* because we have the signature */
+
+ emit_remote_internal (proxy, message, signal_id, signature != NULL);
+ }
+ }
+
+ g_free (name);
}
/** @} End of DBusGLibInternals */
* @param client_serial return location for message's serial, or #NULL */
void
dbus_g_proxy_send (DBusGProxy *proxy,
- DBusMessage *message,
- dbus_uint32_t *client_serial)
+ DBusMessage *message,
+ dbus_uint32_t *client_serial)
{
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_error ("Out of memory\n");
}
+static gboolean
+siginfo_from_signature (const char *signature,
+ GSignalCMarshaller *c_marshaller,
+ GType *return_type,
+ guint *n_params,
+ GType **param_types)
+{
+ /* FIXME (which marshalers should we include?
+ * probably need public API to add your own
+ */
+
+ if (strcmp (signature, "sss") == 0)
+ {
+ *c_marshaller = _dbus_g_marshal_NONE__STRING_STRING_STRING;
+ *return_type = G_TYPE_NONE;
+ *n_params = 3;
+ *param_types = g_new0 (GType, *n_params);
+ (*param_types)[0] = G_TYPE_STRING;
+ (*param_types)[1] = G_TYPE_STRING;
+ (*param_types)[2] = G_TYPE_STRING;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Specifies the signature of a signal, such that it's possible to
+ * connect to the signal on this proxy.
+ *
+ * @param proxy the proxy for a remote interface
+ * @param signal_name the name of the signal
+ * @param signature D-BUS signature of the signal
+ */
+void
+dbus_g_proxy_add_signal (DBusGProxy *proxy,
+ const char *signal_name,
+ const char *signature)
+{
+ GSignalCMarshaller c_marshaller;
+ GType return_type;
+ int n_params;
+ GType *params;
+
+ g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+ g_return_if_fail (signal_name != NULL);
+ g_return_if_fail (signature != NULL);
+
+ if (siginfo_from_signature (signature,
+ &c_marshaller,
+ &return_type,
+ &n_params,
+ ¶ms))
+ {
+ GQuark q;
+ char *name;
+
+ name = create_signal_name (proxy->interface, signal_name);
+
+ q = g_quark_from_string (name);
+
+ g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
+
+ g_datalist_id_set_data_full (&proxy->signal_signatures,
+ q, g_strdup (signature),
+ g_free);
+
+ /* hackaround global nature of g_signal_newv()... this whole thing needs unhosing */
+
+ if (g_signal_lookup (name,
+ G_OBJECT_TYPE (proxy)) == 0)
+ {
+ g_signal_newv (name,
+ G_OBJECT_TYPE (proxy),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ c_marshaller,
+ return_type, n_params, params);
+ }
+
+ g_free (params);
+ g_free (name);
+ }
+ else
+ {
+ g_warning ("DBusGProxy doesn't know how to create a signal with signature '%s'\n",
+ signature);
+ }
+}
+
/**
* Connect a signal handler to a proxy for a remote interface. When
* the remote interface emits the specified signal, the proxy will
* emit a corresponding GLib signal.
*
- * @todo Right now there's no way to specify the signature to use
- * for invoking the GCallback. Need to either rely on introspection,
- * or require signature here.
- *
* @param proxy a proxy for a remote interface
* @param signal_name the DBus signal name to listen for
* @param handler the handler to connect
*/
void
dbus_g_proxy_connect_signal (DBusGProxy *proxy,
- const char *signal_name,
- GCallback handler,
- void *data,
- GClosureNotify free_data_func)
+ const char *signal_name,
+ GCallback handler,
+ void *data,
+ GClosureNotify free_data_func)
{
- GClosure *closure;
- char *detail;
+ char *name;
+ guint signal_id;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (signal_name != NULL);
g_return_if_fail (handler != NULL);
- detail = create_signal_detail (proxy->interface, signal_name);
-
- closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
- g_signal_connect_closure_by_id (G_OBJECT (proxy),
- signals[RECEIVED],
- g_quark_from_string (detail),
- closure, FALSE);
+ name = create_signal_name (proxy->interface, signal_name);
- g_free (detail);
+ g_printerr ("Looking up signal '%s'\n", name);
+ signal_id = g_signal_lookup (name,
+ G_OBJECT_TYPE (proxy));
+ if (signal_id != 0)
+ {
+ GClosure *closure;
+
+ closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
+ g_signal_connect_closure_by_id (G_OBJECT (proxy),
+ signal_id,
+ 0,
+ closure, FALSE);
+ }
+ else
+ {
+ g_warning ("You have to add signal '%s' with dbus_g_proxy_add_signal() before you can connect to it\n",
+ name);
+ }
+
+ g_free (name);
}
/**
*/
void
dbus_g_proxy_disconnect_signal (DBusGProxy *proxy,
- const char *signal_name,
- GCallback handler,
- void *data)
+ const char *signal_name,
+ GCallback handler,
+ void *data)
{
- char *detail;
- GQuark q;
+ char *name;
+ guint signal_id;
g_return_if_fail (DBUS_IS_G_PROXY (proxy));
g_return_if_fail (signal_name != NULL);
g_return_if_fail (handler != NULL);
- detail = create_signal_detail (proxy->interface, signal_name);
- q = g_quark_try_string (detail);
- g_free (detail);
+ name = create_signal_name (proxy->interface, signal_name);
-#ifndef G_DISABLE_CHECKS
- if (q == 0)
+ signal_id = g_signal_lookup (name, G_OBJECT_TYPE (proxy));
+ if (signal_id != 0)
{
- g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
- G_GNUC_FUNCTION, signal_name);
- return;
+ g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
+ G_SIGNAL_MATCH_DETAIL |
+ G_SIGNAL_MATCH_FUNC |
+ G_SIGNAL_MATCH_DATA,
+ signal_id,
+ 0,
+ NULL,
+ G_CALLBACK (handler), data);
+ }
+ else
+ {
+ g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
+ name);
}
-#endif
- g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
- G_SIGNAL_MATCH_DETAIL |
- G_SIGNAL_MATCH_FUNC |
- G_SIGNAL_MATCH_DATA,
- signals[RECEIVED],
- q,
- NULL,
- G_CALLBACK (handler), data);
+ g_free (name);
}
/** @} End of DBusGLib public */
*/
#include "dbus-names-model.h"
#include <glib/gi18n.h>
+#include <string.h>
enum
{
g_strfreev (names);
}
+static gboolean
+names_model_find_name (NamesModel *names_model,
+ const char *name,
+ GtkTreeIter *iter_p)
+{
+ GtkTreeIter iter;
+
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (names_model),
+ &iter))
+ return FALSE;
+
+ do
+ {
+ char *s;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (names_model),
+ &iter,
+ MODEL_COLUMN_NAME, &s,
+ -1);
+ if (s && strcmp (s, name) == 0)
+ {
+ *iter_p = iter;
+ g_free (s);
+ return TRUE;
+ }
+
+ g_free (s);
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (names_model),
+ &iter));
+
+ return FALSE;
+}
+
+static void
+name_owner_changed (DBusGProxy *driver_proxy,
+ const char *name,
+ const char *old_owner,
+ const char *new_owner,
+ void *data)
+{
+ NamesModel *names_model = NAMES_MODEL (data);
+
+#if 0
+ g_printerr ("Name '%s' changed owner '%s' -> '%s'\n",
+ name, old_owner, new_owner);
+#endif
+
+ if (*new_owner == '\0')
+ {
+ /* this name has vanished */
+ GtkTreeIter iter;
+
+ if (names_model_find_name (names_model, name, &iter))
+ gtk_tree_store_remove (GTK_TREE_STORE (names_model),
+ &iter);
+ }
+ else if (*old_owner == '\0')
+ {
+ /* this name has been added */
+ GtkTreeIter iter;
+
+ if (!names_model_find_name (names_model, name, &iter))
+ {
+ gtk_tree_store_append (GTK_TREE_STORE (names_model),
+ &iter, NULL);
+
+ gtk_tree_store_set (GTK_TREE_STORE (names_model),
+ &iter,
+ MODEL_COLUMN_NAME, name,
+ -1);
+ }
+ }
+}
+
static void
names_model_reload (NamesModel *names_model)
{
names_model_set_connection (NamesModel *names_model,
DBusGConnection *connection)
{
- const char *match_rule = "type='signal',member='NameOwnerChanged'";
-
g_return_if_fail (IS_NAMES_MODEL (names_model));
if (connection == names_model->connection)
if (names_model->connection)
{
- dbus_g_proxy_call_no_reply (names_model->driver_proxy,
- "RemoveMatch",
- DBUS_TYPE_STRING, &match_rule,
- DBUS_TYPE_INVALID);
+ dbus_g_proxy_disconnect_signal (names_model->driver_proxy,
+ "NameOwnerChanged",
+ G_CALLBACK (name_owner_changed),
+ names_model);
+
g_object_unref (names_model->driver_proxy);
names_model->driver_proxy = NULL;
dbus_g_connection_unref (names_model->connection);
DBUS_PATH_ORG_FREEDESKTOP_DBUS,
DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS);
g_assert (names_model->driver_proxy);
+
+ dbus_g_proxy_add_signal (names_model->driver_proxy,
+ "NameOwnerChanged",
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING);
+
+ dbus_g_proxy_connect_signal (names_model->driver_proxy,
+ "NameOwnerChanged",
+ G_CALLBACK (name_owner_changed),
+ names_model,
+ NULL);
}
names_model_reload (names_model);