summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2005-01-29 19:52:19 +0000
committerHavoc Pennington <hp@redhat.com>2005-01-29 19:52:19 +0000
commitfd3e49f249fb4ab5ac7da4fe9fc14cc67958d84a (patch)
treedbc9e553ccf466707acffb0f6f1e1f59177f1841
parent602c4b05c4d1c7c83a459b7d0164cc14eebdfcb4 (diff)
2005-01-29 Havoc Pennington <hp@redhat.com>
* glib/Makefile.am: rename dbus-glib-tool to dbus-binding-tool; though it uses glib, it could be extended for any binding in principle * glib/dbus-gobject.c (gobject_message_function): change to the new way properties work * dbus/dbus-protocol.h: add the new interfaces * doc/dbus-specification.xml: document the introspection format, Introspectable interface, and add an org.freedesktop.Properties interface. * glib/dbus-gparser.c: add support for a <property> element * glib/dbus-gidl.c: add PropertyInfo * glib/dbus-gobject.c (handle_introspect): put the outermost <node> outside the signal and property descriptions. (introspect_properties): export properties as <property> rather than as method calls
-rw-r--r--ChangeLog24
-rw-r--r--dbus/dbus-protocol.h4
-rw-r--r--doc/TODO2
-rw-r--r--doc/dbus-specification.xml188
-rw-r--r--glib/.cvsignore2
-rw-r--r--glib/Makefile.am6
-rw-r--r--glib/dbus-gidl.c100
-rw-r--r--glib/dbus-gidl.h112
-rw-r--r--glib/dbus-glib-tool.c31
-rw-r--r--glib/dbus-gobject.c104
-rw-r--r--glib/dbus-gparser.c190
11 files changed, 641 insertions, 122 deletions
diff --git a/ChangeLog b/ChangeLog
index 23d1f426..e5367edc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2005-01-29 Havoc Pennington <hp@redhat.com>
+
+ * glib/Makefile.am: rename dbus-glib-tool to dbus-binding-tool;
+ though it uses glib, it could be extended for any binding in
+ principle
+
+ * glib/dbus-gobject.c (gobject_message_function): change to the
+ new way properties work
+
+ * dbus/dbus-protocol.h: add the new interfaces
+
+ * doc/dbus-specification.xml: document the introspection format,
+ Introspectable interface, and add an org.freedesktop.Properties
+ interface.
+
+ * glib/dbus-gparser.c: add support for a <property> element
+
+ * glib/dbus-gidl.c: add PropertyInfo
+
+ * glib/dbus-gobject.c (handle_introspect): put the outermost
+ <node> outside the signal and property descriptions.
+ (introspect_properties): export properties as <property> rather
+ than as method calls
+
2005-01-28 Havoc Pennington <hp@redhat.com>
* doc/TODO, doc/dbus-specification.xml: spec and TODO tweaks
diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
index 81912622..f72efb60 100644
--- a/dbus/dbus-protocol.h
+++ b/dbus/dbus-protocol.h
@@ -212,8 +212,10 @@ extern "C" {
/* Interfaces, these #define don't do much other than
* catch typos at compile time
*/
-#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus"
+#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS "org.freedesktop.DBus"
#define DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE "org.freedesktop.Introspectable"
+#define DBUS_INTERFACE_ORG_FREEDESKTOP_PROPERTIES "org.freedesktop.Properties"
+#define DBUS_INTERFACE_ORG_FREEDESKTOP_PEER "org.freedesktop.Peer"
/* This is a special interface whose methods can only be invoked
* by the local implementation (messages from remote apps aren't
diff --git a/doc/TODO b/doc/TODO
index d4ca427a..49b00779 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -43,6 +43,8 @@ Important for 1.0
support escaping in the addresses, be sure multiple addresses
in one env variable work, etc.
+ - Ping isn't handled
+
Important for 1.0 GLib Bindings
===
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index 6e34be27..973f390b 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -1119,12 +1119,22 @@
exceptions.
</para>
<para>
+ In converting from native APIs to D-BUS, it is perhaps nice to
+ map D-BUS naming conventions ("FooBar") to native conventions
+ such as "fooBar" or "foo_bar" automatically. This is OK
+ as long as you can say that the native API is one that
+ was specifically written for D-BUS. It makes the most sense
+ when writing object implementations that will be exported
+ over the bus. Object proxies used to invoke remote D-BUS
+ objects probably need the ability to call any D-BUS method,
+ and thus a magic name mapping like this could be a problem.
+ </para>
+ <para>
This specification doesn't require anything of native API bindings;
the preceding is only a suggested convention for consistency
among bindings.
</para>
</sect4>
-
</sect3>
<sect3 id="message-protocol-types-signal">
@@ -2053,26 +2063,184 @@
</para>
</sect1>
- <sect1 id="standard-messages">
- <title>Standard One-to-One Messages</title>
+ <sect1 id="naming-conventions">
+ <title>Naming Conventions</title>
+
+ <para>
+ D-BUS namespaces are all lowercase and correspond to reversed domain
+ names, as with Java. e.g. "org.freedesktop"
+ </para>
+ <para>
+ Interface, signal, method, and property names are "WindowsStyleCaps", note
+ that the first letter is capitalized, unlike Java.
+ </para>
+ <para>
+ Object paths are normally all lowercase with underscores used rather than
+ hyphens.
+ </para>
+ </sect1>
+
+ <sect1 id="standard-interfaces">
+ <title>Standard Interfaces</title>
<para>
See <xref linkend="message-protocol-types-notation"/> for details on
- the notation used in this section.
+ the notation used in this section. There are some standard interfaces
+ that may be useful across various D-BUS applications.
</para>
- <sect2 id="standard-messages-ping">
- <title><literal>org.freedesktop.Peer.Ping</literal></title>
- <para>
+ <sect2 id="standard-interfaces-peer">
+ <title><literal>org.freedesktop.Peer</literal></title>
+ <para>
+ The <literal>org.freedesktop.Peer</literal> interface
+ has one method:
<programlisting>
org.freedesktop.Peer.Ping ()
</programlisting>
</para>
<para>
- On receipt of the <literal>METHOD_CALL</literal>
- message <literal>org.freedesktop.Peer.Ping</literal>, an application
- should do nothing other than reply with a <literal>METHOD_RETURN</literal> as usual.
+ On receipt of the <literal>METHOD_CALL</literal> message
+ <literal>org.freedesktop.Peer.Ping</literal>, an application should do
+ nothing other than reply with a <literal>METHOD_RETURN</literal> as
+ usual. It does not matter which object path a ping is sent to. The
+ reference implementation should simply handle this method on behalf of
+ all objects, though it doesn't yet. (The point is, you're really pinging
+ the peer process, not a specific object.)
</para>
</sect2>
+ <sect2 id="standard-interfaces-introspectable">
+ <title><literal>org.freedesktop.Introspectable</literal></title>
+ <para>
+ This interface has one method:
+ <programlisting>
+ org.freedesktop.Introspectable.Introspect (out STRING xml_data)
+ </programlisting>
+ </para>
+ <para>
+ Objects instances may implement
+ <literal>Introspect</literal> which returns an XML description of
+ the object, including its interfaces (with signals and methods), objects
+ below it in the object path tree, and its properties.
+ </para>
+ <para>
+ <xref linkend="introspection-format"/> describes the format of this XML string.
+ </para>
+ </sect2>
+ <sect2 id="standard-interfaces-properties">
+ <title><literal>org.freedesktop.Properties</literal></title>
+ <para>
+ Many native APIs will have a concept of object <firstterm>properties</firstterm>
+ or <firstterm>attributes</firstterm>. These can be exposed via the
+ <literal>org.freedesktop.Properties</literal> interface.
+ </para>
+ <para>
+ <programlisting>
+ org.freedesktop.Properties.Get (in STRING interface_name,
+ in STRING property_name,
+ out VARIANT value);
+ org.freedesktop.Properties.Set (in STRING interface_name,
+ in STRING property_name,
+ in VARIANT value);
+ </programlisting>
+ </para>
+ <para>
+ The available properties and whether they are writable can be determined
+ by calling <literal>org.freedesktop.Introspectable.Introspect</literal>,
+ see <xref linkend="standard-interfaces-introspectable"/>.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="introspection-format">
+ <title>Introspection Data Format</title>
+ <para>
+ As described in <xref linkend="standard-interfaces-introspectable"/>,
+ objects may be introspected at runtime, returning an XML string
+ that describes the object. The same XML format may be used in
+ other contexts as well, for example as an "IDL" for generating
+ static language bindings.
+ </para>
+ <para>
+ Here is an example of introspection data:
+ <programlisting>
+ &lt;!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"&gt;
+ &lt;node name="/org/freedesktop/sample_object"&gt;
+ &lt;interface name="org.freedesktop.SampleInterface"&gt;
+ &lt;method name="Frobate"&gt;
+ &lt;arg name="foo" type="int32" direction="in"/&gt;
+ &lt;arg name="bar" type="string" direction="out"/&gt;
+ &lt;/method&gt;
+ &lt;signal name="Changed"&gt;
+ &lt;arg name="new_value" type="boolean"/&gt;
+ &lt;/signal&gt;
+ &lt;property name="Bar" type="byte" access="readwrite"/&gt;
+ &lt;/interface&gt;
+ &lt;node name="child_of_sample_object"/&gt;
+ &lt;node name="another_child_of_sample_object"/&gt;
+ &lt;/node&gt;
+ </programlisting>
+ </para>
+ <para>
+ A more formal DTD and spec needs writing, but here are some quick notes.
+ <itemizedlist>
+ <listitem>
+ <para>
+ Only the root &lt;node&gt; element can omit the node name, as it's
+ known to be the object that was introspected. If the root
+ &lt;node&gt; does have a name attribute, it should be an absolute
+ object path. If child &lt;node&gt; have object paths, they should be
+ relative.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a child &lt;node&gt; has any sub-elements, then they
+ must represent a complete introspection of the child.
+ If a child &lt;node&gt; is empty, then it may or may
+ not have sub-elements; the child must be introspected
+ in order to find out. The intent is that if an object
+ knows that its children are "fast" to introspect
+ it can go ahead and return their information, but
+ otherwise it can omit it.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The direction element on &lt;arg&gt; may be omitted,
+ in which case it defaults to "in" for method calls
+ and "out" for signals. Signals only allow "out"
+ so while direction may be specified, it's pointless.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The possible directions are "in" and "out",
+ unlike CORBA there is no "inout"
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The possible property access flags are
+ "readwrite", "read", and "write"
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The current type="uint32" stuff is totally broken,
+ instead we have to do full signatures.
+ However, then this format will suck for human readability.
+ So, some thinking to do here.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Multiple interfaces can of course be listed for
+ one &lt;node&gt;.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
</sect1>
<sect1 id="message-bus">
diff --git a/glib/.cvsignore b/glib/.cvsignore
index 881b4887..4e197a9f 100644
--- a/glib/.cvsignore
+++ b/glib/.cvsignore
@@ -5,7 +5,7 @@ Makefile.in
*.lo
*.la
dbus-glib-test
-dbus-glib-tool
+dbus-binding-tool
*.bb
*.bbg
*.da
diff --git a/glib/Makefile.am b/glib/Makefile.am
index e0362b42..4db47de4 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -34,12 +34,12 @@ libdbus_gtool_la_SOURCES = \
libdbus_gtool_la_LIBADD = libdbus-glib-1.la
-bin_PROGRAMS=dbus-glib-tool
+bin_PROGRAMS=dbus-binding-tool
-dbus_glib_tool_SOURCES = \
+dbus_binding_tool_SOURCES = \
dbus-glib-tool.c
-dbus_glib_tool_LDADD= -lexpat libdbus-gtool.la
+dbus_binding_tool_LDADD= -lexpat libdbus-gtool.la
if DBUS_BUILD_TESTS
diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c
index 6fa83916..cabc406b 100644
--- a/glib/dbus-gidl.c
+++ b/glib/dbus-gidl.c
@@ -2,7 +2,7 @@
/* dbus-gidl.c data structure describing an interface, to be generated from IDL
* or something
*
- * Copyright (C) 2003 Red Hat, Inc.
+ * Copyright (C) 2003, 2005 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
@@ -46,6 +46,7 @@ struct InterfaceInfo
/* Since we have BaseInfo now these could be one list */
GSList *methods;
GSList *signals;
+ GSList *properties;
};
struct MethodInfo
@@ -60,6 +61,13 @@ struct SignalInfo
GSList *args;
};
+struct PropertyInfo
+{
+ BaseInfo base;
+ int type;
+ PropertyAccessFlags access;
+};
+
struct ArgInfo
{
BaseInfo base;
@@ -111,6 +119,9 @@ base_info_unref (BaseInfo *info)
case INFO_TYPE_METHOD:
method_info_unref ((MethodInfo*) info);
break;
+ case INFO_TYPE_PROPERTY:
+ property_info_unref ((PropertyInfo*) info);
+ break;
case INFO_TYPE_ARG:
arg_info_unref ((ArgInfo*) info);
break;
@@ -209,6 +220,20 @@ free_signal_list (GSList **signals_p)
*signals_p = NULL;
}
+static void
+free_property_list (GSList **props_p)
+{
+ GSList *tmp;
+ tmp = *props_p;
+ while (tmp != NULL)
+ {
+ property_info_unref (tmp->data);
+ tmp = tmp->next;
+ }
+ g_slist_free (*props_p);
+ *props_p = NULL;
+}
+
NodeInfo*
node_info_new (const char *name)
{
@@ -307,6 +332,7 @@ interface_info_unref (InterfaceInfo *info)
{
free_method_list (&info->methods);
free_signal_list (&info->signals);
+ free_property_list (&info->properties);
base_info_free (info);
}
}
@@ -329,6 +355,12 @@ interface_info_get_signals (InterfaceInfo *info)
return info->signals;
}
+GSList*
+interface_info_get_properties (InterfaceInfo *info)
+{
+ return info->properties;
+}
+
void
interface_info_add_method (InterfaceInfo *info,
MethodInfo *method)
@@ -345,6 +377,14 @@ interface_info_add_signal (InterfaceInfo *info,
info->signals = g_slist_append (info->signals, signal);
}
+void
+interface_info_add_property (InterfaceInfo *info,
+ PropertyInfo *property)
+{
+ property_info_ref (property);
+ info->properties = g_slist_append (info->properties, property);
+}
+
static void
free_arg_list (GSList **args_p)
{
@@ -352,6 +392,8 @@ free_arg_list (GSList **args_p)
tmp = *args_p;
while (tmp != NULL)
{
+ ArgInfo *ai = tmp->data;
+ g_assert (ai->base.type == INFO_TYPE_ARG);
arg_info_unref (tmp->data);
tmp = tmp->next;
}
@@ -484,10 +526,64 @@ signal_info_add_arg (SignalInfo *info,
arg_info_ref (arg);
info->args = g_slist_append (info->args, arg);
-
+
/* signal args don't need sorting since only "out" is allowed */
}
+PropertyInfo*
+property_info_new (const char *name,
+ int type,
+ PropertyAccessFlags access)
+{
+ PropertyInfo *info;
+
+ info = g_new0 (PropertyInfo, 1);
+ info->base.refcount = 1;
+ info->base.name = g_strdup (name);
+ info->base.type = INFO_TYPE_PROPERTY;
+
+ info->type = type;
+ info->access = access;
+
+ return info;
+}
+
+PropertyInfo*
+property_info_ref (PropertyInfo *info)
+{
+ info->base.refcount += 1;
+
+ return info;
+}
+
+void
+property_info_unref (PropertyInfo *info)
+{
+ info->base.refcount -= 1;
+ if (info->base.refcount == 0)
+ {
+ base_info_free (info);
+ }
+}
+
+const char*
+property_info_get_name (PropertyInfo *info)
+{
+ return info->base.name;
+}
+
+int
+property_info_get_type (PropertyInfo *info)
+{
+ return info->type;
+}
+
+PropertyAccessFlags
+property_info_get_access (PropertyInfo *info)
+{
+ return info->access;
+}
+
ArgInfo*
arg_info_new (const char *name,
ArgDirection direction,
diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h
index 47b4f093..fffbddfc 100644
--- a/glib/dbus-gidl.h
+++ b/glib/dbus-gidl.h
@@ -36,21 +36,30 @@ typedef struct NodeInfo NodeInfo;
typedef struct InterfaceInfo InterfaceInfo;
typedef struct MethodInfo MethodInfo;
typedef struct SignalInfo SignalInfo;
+typedef struct PropertyInfo PropertyInfo;
typedef struct ArgInfo ArgInfo;
typedef enum
{
+ ARG_INVALID = -1,
ARG_IN,
ARG_OUT
} ArgDirection;
typedef enum
{
+ PROPERTY_READ = 1 << 0,
+ PROPERTY_WRITE = 1 << 1
+} PropertyAccessFlags;
+
+typedef enum
+{
INFO_TYPE_NODE,
INFO_TYPE_INTERFACE,
INFO_TYPE_METHOD,
INFO_TYPE_SIGNAL,
- INFO_TYPE_ARG
+ INFO_TYPE_ARG,
+ INFO_TYPE_PROPERTY
} InfoType;
@@ -64,54 +73,59 @@ GType base_info_get_gtype (void);
#define BASE_INFO_TYPE (base_info_get_gtype ())
-NodeInfo* node_info_new (const char *name);
-NodeInfo* node_info_ref (NodeInfo *info);
-void node_info_unref (NodeInfo *info);
-const char* node_info_get_name (NodeInfo *info);
-GSList* node_info_get_interfaces (NodeInfo *info);
-GSList* node_info_get_nodes (NodeInfo *info);
-void node_info_add_interface (NodeInfo *info,
- InterfaceInfo *interface);
-void node_info_add_node (NodeInfo *info,
- NodeInfo *child);
-
-InterfaceInfo* interface_info_new (const char *name);
-InterfaceInfo* interface_info_ref (InterfaceInfo *info);
-void interface_info_unref (InterfaceInfo *info);
-const char* interface_info_get_name (InterfaceInfo *info);
-GSList* interface_info_get_methods (InterfaceInfo *info);
-GSList* interface_info_get_signals (InterfaceInfo *info);
-void interface_info_add_method (InterfaceInfo *info,
- MethodInfo *method);
-void interface_info_add_signal (InterfaceInfo *info,
- SignalInfo *signal);
-
-MethodInfo* method_info_new (const char *name);
-MethodInfo* method_info_ref (MethodInfo *info);
-void method_info_unref (MethodInfo *info);
-
-const char* method_info_get_name (MethodInfo *info);
-GSList* method_info_get_args (MethodInfo *info);
-void method_info_add_arg (MethodInfo *info,
- ArgInfo *arg);
-
-SignalInfo* signal_info_new (const char *name);
-SignalInfo* signal_info_ref (SignalInfo *info);
-void signal_info_unref (SignalInfo *info);
-
-const char* signal_info_get_name (SignalInfo *info);
-GSList* signal_info_get_args (SignalInfo *info);
-void signal_info_add_arg (SignalInfo *info,
- ArgInfo *arg);
-
-ArgInfo* arg_info_new (const char *name,
- ArgDirection direction,
- int type);
-ArgInfo* arg_info_ref (ArgInfo *info);
-void arg_info_unref (ArgInfo *info);
-const char* arg_info_get_name (ArgInfo *info);
-int arg_info_get_type (ArgInfo *info);
-ArgDirection arg_info_get_direction (ArgInfo *info);
+NodeInfo* node_info_new (const char *name);
+NodeInfo* node_info_ref (NodeInfo *info);
+void node_info_unref (NodeInfo *info);
+const char* node_info_get_name (NodeInfo *info);
+GSList* node_info_get_interfaces (NodeInfo *info);
+GSList* node_info_get_nodes (NodeInfo *info);
+void node_info_add_interface (NodeInfo *info,
+ InterfaceInfo *interface);
+void node_info_add_node (NodeInfo *info,
+ NodeInfo *child);
+InterfaceInfo* interface_info_new (const char *name);
+InterfaceInfo* interface_info_ref (InterfaceInfo *info);
+void interface_info_unref (InterfaceInfo *info);
+const char* interface_info_get_name (InterfaceInfo *info);
+GSList* interface_info_get_methods (InterfaceInfo *info);
+GSList* interface_info_get_signals (InterfaceInfo *info);
+GSList* interface_info_get_properties (InterfaceInfo *info);
+void interface_info_add_method (InterfaceInfo *info,
+ MethodInfo *method);
+void interface_info_add_signal (InterfaceInfo *info,
+ SignalInfo *signal);
+void interface_info_add_property (InterfaceInfo *info,
+ PropertyInfo *property);
+MethodInfo* method_info_new (const char *name);
+MethodInfo* method_info_ref (MethodInfo *info);
+void method_info_unref (MethodInfo *info);
+const char* method_info_get_name (MethodInfo *info);
+GSList* method_info_get_args (MethodInfo *info);
+void method_info_add_arg (MethodInfo *info,
+ ArgInfo *arg);
+SignalInfo* signal_info_new (const char *name);
+SignalInfo* signal_info_ref (SignalInfo *info);
+void signal_info_unref (SignalInfo *info);
+const char* signal_info_get_name (SignalInfo *info);
+GSList* signal_info_get_args (SignalInfo *info);
+void signal_info_add_arg (SignalInfo *info,
+ ArgInfo *arg);
+PropertyInfo* property_info_new (const char *name,
+ int type,
+ PropertyAccessFlags access);
+PropertyInfo* property_info_ref (PropertyInfo *info);
+void property_info_unref (PropertyInfo *info);
+const char* property_info_get_name (PropertyInfo *info);
+int property_info_get_type (PropertyInfo *info);
+PropertyAccessFlags property_info_get_access (PropertyInfo *info);
+ArgInfo* arg_info_new (const char *name,
+ ArgDirection direction,
+ int type);
+ArgInfo* arg_info_ref (ArgInfo *info);
+void arg_info_unref (ArgInfo *info);
+const char* arg_info_get_name (ArgInfo *info);
+int arg_info_get_type (ArgInfo *info);
+ArgDirection arg_info_get_direction (ArgInfo *info);
G_END_DECLS
diff --git a/glib/dbus-glib-tool.c b/glib/dbus-glib-tool.c
index c460a352..c8273afa 100644
--- a/glib/dbus-glib-tool.c
+++ b/glib/dbus-glib-tool.c
@@ -57,7 +57,7 @@ pretty_print_list (GSList *list,
int depth)
{
GSList *tmp;
-
+
tmp = list;
while (tmp != NULL)
{
@@ -106,6 +106,7 @@ pretty_print (BaseInfo *base,
pretty_print_list (interface_info_get_methods (i), depth + 1);
pretty_print_list (interface_info_get_signals (i), depth + 1);
+ pretty_print_list (interface_info_get_properties (i), depth + 1);
indent (depth);
printf ("}\n");
@@ -139,6 +140,22 @@ pretty_print (BaseInfo *base,
printf (")\n");
}
break;
+ case INFO_TYPE_PROPERTY:
+ {
+ PropertyInfo *a = (PropertyInfo*) base;
+ int pt = property_info_get_type (a);
+ PropertyAccessFlags acc = property_info_get_access (a);
+
+ printf ("%s%s %s",
+ acc & PROPERTY_READ ? "read" : "",
+ acc & PROPERTY_WRITE ? "write" : "",
+ _dbus_gutils_type_to_string (pt));
+ if (name)
+ printf (" %s\n", name);
+ else
+ printf ("\n");
+ }
+ break;
case INFO_TYPE_ARG:
{
ArgInfo *a = (ArgInfo*) base;
@@ -160,16 +177,16 @@ pretty_print (BaseInfo *base,
static void
usage (int ecode)
{
- fprintf (stderr, "dbus-glib-tool [--version] [--help]\n");
+ fprintf (stderr, "dbus-binding-tool [--version] [--help] [--pretty-print]\n");
exit (ecode);
}
static void
version (void)
{
- printf ("D-BUS GLib Tool %s\n"
- "Copyright (C) 2003, 2004 Red Hat, Inc.\n"
- "This is free software; see the source for copying conditions.\n"
+ printf ("D-BUS Binding Tool %s\n"
+ "Copyright (C) 2003-2005 Red Hat, Inc.\n"
+ "This is free software; xsee the source for copying conditions.\n"
"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
VERSION);
exit (0);
@@ -313,11 +330,11 @@ run_all_tests (const char *test_data_dir)
else
printf ("No test data!\n");
- printf ("%s: running gtool tests\n", "dbus-glib-tool");
+ printf ("%s: running binding tests\n", "dbus-binding-tool");
if (!_dbus_gtool_test (test_data_dir))
test_die ("gtool");
- printf ("%s: completed successfully\n", "dbus-glib-tool");
+ printf ("%s: completed successfully\n", "dbus-binding-tool");
}
#endif /* DBUS_BUILD_TESTS */
diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c
index 18361035..5aab4a68 100644
--- a/glib/dbus-gobject.c
+++ b/glib/dbus-gobject.c
@@ -198,28 +198,27 @@ introspect_properties (GObject *object, GString *xml)
s = uscore_to_wincaps (spec->name);
- if (can_set)
+ if (can_set || can_get)
{
- g_string_append (xml, " <method name=\"set_");
+ g_string_append (xml, " <property name=\"");
g_string_append (xml, s);
- g_string_append (xml, "\">\n");
-
- g_string_append (xml, " <arg type=\"");
+ g_string_append (xml, "\" type=\"");
g_string_append (xml, _dbus_gutils_type_to_string (dbus_type));
- g_string_append (xml, "\"/>\n");
- }
+ g_string_append (xml, "\" access=\"\n");
- if (can_get)
- {
- g_string_append (xml, " <method name=\"get_");
- g_string_append (xml, s);
- g_string_append (xml, "\">\n");
+ if (can_set && can_get)
+ g_string_append (xml, "readwrite");
+ else if (can_get)
+ g_string_append (xml, "read");
+ else
+ {
+ g_assert (can_set);
+ g_string_append (xml, "write");
+ }
- g_string_append (xml, " <arg type=\"");
- g_string_append (xml, _dbus_gutils_type_to_string (dbus_type));
- g_string_append (xml, "\" direction=\"out\"/>\n");
+ g_string_append (xml, "\">\n");
}
-
+
g_free (s);
}
@@ -290,10 +289,10 @@ handle_introspect (DBusConnection *connection,
xml = g_string_new (NULL);
+ g_string_append (xml, "<node>\n");
+
introspect_signals (G_OBJECT_TYPE (object), xml);
introspect_properties (object, xml);
-
- g_string_append (xml, "<node>\n");
/* Append child nodes */
for (i = 0; children[i]; i++)
@@ -322,23 +321,24 @@ handle_introspect (DBusConnection *connection,
}
static DBusMessage*
-set_object_property (DBusConnection *connection,
- DBusMessage *message,
- GObject *object,
- GParamSpec *pspec)
+set_object_property (DBusConnection *connection,
+ DBusMessage *message,
+ DBusMessageIter *iter,
+ GObject *object,
+ GParamSpec *pspec)
{
GValue value = { 0, };
DBusMessage *ret;
- DBusMessageIter iter;
-
- dbus_message_iter_init (message, &iter);
+ DBusMessageIter sub;
+ dbus_message_iter_recurse (iter, &sub);
+
/* The g_object_set_property() will transform some types, e.g. it
* will let you use a uchar to set an int property etc. Note that
* any error in value range or value conversion will just
* g_warning(). These GObject skels are not for secure applications.
*/
- if (dbus_gvalue_demarshal (&iter, &value))
+ if (dbus_gvalue_demarshal (&sub, &value))
{
g_object_set_property (object,
pspec->name,
@@ -405,10 +405,12 @@ gobject_message_function (DBusConnection *connection,
const DBusGObjectInfo *info;
GParamSpec *pspec;
GObject *object;
- const char *member;
gboolean setter;
gboolean getter;
char *s;
+ const char *wincaps_propname;
+ const char *wincaps_propiface;
+ DBusMessageIter iter;
object = G_OBJECT (user_data);
@@ -417,8 +419,6 @@ gobject_message_function (DBusConnection *connection,
"Introspect"))
return handle_introspect (connection, message, object);
- member = dbus_message_get_member (message);
-
/* Try the metainfo, which lets us invoke methods */
g_static_mutex_lock (&info_hash_mutex);
@@ -439,13 +439,39 @@ gobject_message_function (DBusConnection *connection,
/* If no metainfo, we can still do properties and signals
* via standard GLib introspection
*/
- setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
- getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
+ getter = FALSE;
+ setter = FALSE;
+ if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_PROPERTIES,
+ "Get"))
+ getter = TRUE;
+ else if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_PROPERTIES,
+ "Set"))
+ setter = TRUE;
if (!(setter || getter))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- s = wincaps_to_uscore (&member[4]);
+ dbus_message_iter_init (message, &iter);
+
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ {
+ g_warning ("Property get or set does not have an interface string as first arg\n");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_message_iter_get_basic (&iter, &wincaps_propiface);
+ dbus_message_iter_next (&iter);
+
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
+ {
+ g_warning ("Property get or set does not have a property name string as second arg\n");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_message_iter_get_basic (&iter, &wincaps_propname);
+ dbus_message_iter_next (&iter);
+
+ s = wincaps_to_uscore (wincaps_propname);
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
s);
@@ -458,11 +484,18 @@ gobject_message_function (DBusConnection *connection,
if (setter)
{
- ret = set_object_property (connection, message,
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT)
+ {
+ g_warning ("Property set does not have a variant value as third arg\n");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ ret = set_object_property (connection, message, &iter,
object, pspec);
+ dbus_message_iter_next (&iter);
}
else if (getter)
- {
+ {
ret = get_object_property (connection, message,
object, pspec);
}
@@ -474,6 +507,9 @@ gobject_message_function (DBusConnection *connection,
g_assert (ret != NULL);
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
+ g_warning ("Property get or set had too many arguments\n");
+
dbus_connection_send (connection, ret, NULL);
dbus_message_unref (ret);
return DBUS_HANDLER_RESULT_HANDLED;
diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c
index 478dcdf3..83922af4 100644
--- a/glib/dbus-gparser.c
+++ b/glib/dbus-gparser.c
@@ -1,7 +1,7 @@
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-gparser.c parse DBus description files
*
- * Copyright (C) 2003 Red Hat, Inc.
+ * Copyright (C) 2003, 2005 Red Hat, Inc.
*
* Licensed under the Academic Free License version 2.1
*
@@ -169,6 +169,7 @@ struct Parser
InterfaceInfo *interface;
MethodInfo *method;
SignalInfo *signal;
+ PropertyInfo *property;
ArgInfo *arg;
};
@@ -238,11 +239,12 @@ parse_node (Parser *parser,
if (parser->interface ||
parser->method ||
parser->signal ||
+ parser->property ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
- _("Can't put a <%s> element here"),
+ _("Can't put <%s> element here"),
element_name);
return FALSE;
}
@@ -264,6 +266,25 @@ parse_node (Parser *parser,
return FALSE;
}
+ /* Root element name must be absolute */
+ if (parser->node_stack == NULL && name && *name != '/')
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute on <%s> element must be an absolute object path, \"%s\" not OK"),
+ "name", element_name, name);
+ return FALSE;
+ }
+
+ /* Other element names must not be absolute */
+ if (parser->node_stack != NULL && name && *name == '/')
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute on <%s> element must not be an absolute object path, \"%s\" starts with /"),
+ "name", element_name, name);
+ return FALSE;
+ }
node = node_info_new (name);
@@ -293,12 +314,13 @@ parse_interface (Parser *parser,
if (parser->interface ||
parser->method ||
parser->signal ||
+ parser->property ||
parser->arg ||
(parser->node_stack == NULL))
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
- _("Can't put a <%s> element here"),
+ _("Can't put <%s> element here"),
element_name);
return FALSE;
}
@@ -345,11 +367,12 @@ parse_method (Parser *parser,
parser->node_stack == NULL ||
parser->method ||
parser->signal ||
+ parser->property ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
- _("Can't put a <%s> element here"),
+ _("Can't put <%s> element here"),
element_name);
return FALSE;
}
@@ -395,12 +418,13 @@ parse_signal (Parser *parser,
if (parser->interface == NULL ||
parser->node_stack == NULL ||
parser->signal ||
- parser->signal ||
+ parser->method ||
+ parser->property ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
- _("Can't put a <%s> element here"),
+ _("Can't put <%s> element here"),
element_name);
return FALSE;
}
@@ -463,10 +487,122 @@ basic_type_from_string (const char *str)
return DBUS_TYPE_INVALID;
}
+/* FIXME we have to allow type signatures, not just basic types
+ */
static int
-type_from_string (const char *str)
+type_from_string (const char *str,
+ const char *element_name,
+ GError **error)
+{
+ int t;
+
+ t = basic_type_from_string (str);
+
+ if (t == DBUS_TYPE_INVALID)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Type \"%s\" not understood on <%s> element "),
+ str, element_name);
+ }
+
+ return t;
+}
+
+static gboolean
+parse_property (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
{
- return basic_type_from_string (str);
+ const char *name;
+ const char *access;
+ const char *type;
+ PropertyInfo *property;
+ NodeInfo *top;
+ PropertyAccessFlags access_flags;
+ int t;
+
+ if (parser->interface == NULL ||
+ parser->node_stack == NULL ||
+ parser->signal ||
+ parser->method ||
+ parser->property ||
+ parser->arg)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Can't put <%s> element here"),
+ element_name);
+ return FALSE;
+ }
+
+ name = NULL;
+ if (!locate_attributes (element_name, attribute_names,
+ attribute_values, error,
+ "name", &name,
+ "access", &access,
+ "type", &type,
+ NULL))
+ return FALSE;
+
+ if (name == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "name", element_name);
+ return FALSE;
+ }
+
+ if (access == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "access", element_name);
+ return FALSE;
+ }
+
+ if (type == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "type", element_name);
+ return FALSE;
+ }
+
+ t = type_from_string (type, element_name, error);
+ if (t == DBUS_TYPE_INVALID)
+ return FALSE;
+
+ access_flags = 0;
+ if (strcmp (access, "readwrite") == 0)
+ access_flags = PROPERTY_READ | PROPERTY_WRITE;
+ else if (strcmp (access, "read") == 0)
+ access_flags = PROPERTY_READ;
+ else if (strcmp (access, "write") == 0)
+ access_flags = PROPERTY_WRITE;
+ else
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("access=\"%s\" must have value readwrite, read, or write on %s\n"),
+ access, element_name);
+ return FALSE;
+ }
+
+ top = parser->node_stack->data;
+
+ property = property_info_new (name, t, access_flags);
+ interface_info_add_property (parser->interface, property);
+ property_info_unref (property);
+
+ parser->property = property;
+
+ return TRUE;
}
static gboolean
@@ -485,11 +621,12 @@ parse_arg (Parser *parser,
if (!(parser->method || parser->signal) ||
parser->node_stack == NULL ||
+ parser->property ||
parser->arg)
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_PARSE,
- _("Can't put a <%s> element here"),
+ _("Can't put <%s> element here"),
element_name);
return FALSE;
}
@@ -525,20 +662,31 @@ parse_arg (Parser *parser,
g_assert_not_reached ();
}
+ dir = ARG_INVALID;
+
if (strcmp (direction, "in") == 0)
dir = ARG_IN;
else if (strcmp (direction, "out") == 0)
dir = ARG_OUT;
- else
+
+ if (dir == ARG_INVALID ||
+ (parser->signal && dir == ARG_IN))
{
- g_set_error (error, G_MARKUP_ERROR,
- G_MARKUP_ERROR_PARSE,
- _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
- "direction", element_name);
+ if (parser->signal)
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Signals must have direction=\"out\" (just omit the direction attribute)"));
+ else
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
+ "direction", element_name);
return FALSE;
}
- t = type_from_string (type);
+ t = type_from_string (type, element_name, error);
+ if (t == DBUS_TYPE_INVALID)
+ return FALSE;
arg = arg_info_new (name, dir, t);
if (parser->method)
@@ -588,6 +736,12 @@ parser_start_element (Parser *parser,
attribute_values, error))
return FALSE;
}
+ else if (ELEMENT_IS ("property"))
+ {
+ if (!parse_property (parser, element_name, attribute_names,
+ attribute_values, error))
+ return FALSE;
+ }
else if (ELEMENT_IS ("arg"))
{
if (!parse_arg (parser, element_name, attribute_names,
@@ -624,6 +778,10 @@ parser_end_element (Parser *parser,
{
parser->signal = NULL;
}
+ else if (ELEMENT_IS ("property"))
+ {
+ parser->property = NULL;
+ }
else if (ELEMENT_IS ("arg"))
{
parser->arg = NULL;
@@ -655,6 +813,8 @@ parser_content (Parser *parser,
{
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* FIXME check that it's all whitespace */
+
return TRUE;
}