[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / tests / gdbus-example-export.c
1 #include <gio/gio.h>
2 #include <stdlib.h>
3
4 /* ---------------------------------------------------------------------------------------------------- */
5
6 /* The object we want to export */
7 typedef struct _MyObjectClass MyObjectClass;
8 typedef struct _MyObject MyObject;
9
10 struct _MyObjectClass
11 {
12   GObjectClass parent_class;
13 };
14
15 struct _MyObject
16 {
17   GObject parent_instance;
18
19   gint count;
20   gchar *name;
21 };
22
23 enum
24 {
25   PROP_0,
26   PROP_COUNT,
27   PROP_NAME
28 };
29
30 static GType my_object_get_type (void);
31 G_DEFINE_TYPE (MyObject, my_object, G_TYPE_OBJECT);
32
33 static void
34 my_object_finalize (GObject *object)
35 {
36   MyObject *myobj = (MyObject*)object;
37
38   g_free (myobj->name);
39
40   G_OBJECT_CLASS (my_object_parent_class)->finalize (object);
41 }
42
43 static void
44 my_object_init (MyObject *object)
45 {
46   object->count = 0;
47   object->name = NULL;
48 }
49
50 static void
51 my_object_get_property (GObject    *object,
52                         guint       prop_id,
53                         GValue     *value,
54                         GParamSpec *pspec)
55 {
56   MyObject *myobj = (MyObject*)object;
57
58   switch (prop_id)
59     {
60     case PROP_COUNT:
61       g_value_set_int (value, myobj->count);
62       break;
63
64     case PROP_NAME:
65       g_value_set_string (value, myobj->name);
66       break;
67
68     default:
69       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
70     }
71 }
72
73 static void
74 my_object_set_property (GObject      *object,
75                         guint         prop_id,
76                         const GValue *value,
77                         GParamSpec   *pspec)
78 {
79   MyObject *myobj = (MyObject*)object;
80
81   switch (prop_id)
82     {
83     case PROP_COUNT:
84       myobj->count = g_value_get_int (value);
85       break;
86
87     case PROP_NAME:
88       g_free (myobj->name);
89       myobj->name = g_value_dup_string (value);
90       break;
91
92     default:
93       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
94     }
95 }
96
97 static void
98 my_object_class_init (MyObjectClass *class)
99 {
100   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
101
102   gobject_class->finalize = my_object_finalize;
103   gobject_class->set_property = my_object_set_property;
104   gobject_class->get_property = my_object_get_property;
105
106   g_object_class_install_property (gobject_class,
107                                    PROP_COUNT,
108                                    g_param_spec_int ("count",
109                                                      "Count",
110                                                      "Count",
111                                                      0, 99999, 0,
112                                                      G_PARAM_READWRITE));
113
114   g_object_class_install_property (gobject_class,
115                                    PROP_NAME,
116                                    g_param_spec_string ("name",
117                                                         "Name",
118                                                         "Name",
119                                                         NULL,
120                                                         G_PARAM_READWRITE));
121 }
122
123 /* A method that we want to export */
124 static void
125 my_object_change_count (MyObject *myobj,
126                         gint      change)
127 {
128   myobj->count = 2 * myobj->count + change;
129
130   g_object_notify (G_OBJECT (myobj), "count");
131 }
132
133 /* ---------------------------------------------------------------------------------------------------- */
134
135 static GDBusNodeInfo *introspection_data = NULL;
136
137 /* Introspection data for the service we are exporting */
138 static const gchar introspection_xml[] =
139   "<node>"
140   "  <interface name='org.myorg.MyObject'>"
141   "    <method name='ChangeCount'>"
142   "      <arg type='i' name='change' direction='in'/>"
143   "    </method>"
144   "    <property type='i' name='Count' access='read'/>"
145   "    <property type='s' name='Name' access='readwrite'/>"
146   "  </interface>"
147   "</node>";
148
149
150 static void
151 handle_method_call (GDBusConnection       *connection,
152                     const gchar           *sender,
153                     const gchar           *object_path,
154                     const gchar           *interface_name,
155                     const gchar           *method_name,
156                     GVariant              *parameters,
157                     GDBusMethodInvocation *invocation,
158                     gpointer               user_data)
159 {
160   MyObject *myobj = user_data;
161
162   if (g_strcmp0 (method_name, "ChangeCount") == 0)
163     {
164       gint change;
165       g_variant_get (parameters, "(i)", &change);
166
167       my_object_change_count (myobj, change);
168
169       g_dbus_method_invocation_return_value (invocation, NULL);
170     }
171 }
172
173 static GVariant *
174 handle_get_property (GDBusConnection  *connection,
175                      const gchar      *sender,
176                      const gchar      *object_path,
177                      const gchar      *interface_name,
178                      const gchar      *property_name,
179                      GError          **error,
180                      gpointer          user_data)
181 {
182   GVariant *ret;
183   MyObject *myobj = user_data;
184
185   ret = NULL;
186   if (g_strcmp0 (property_name, "Count") == 0)
187     {
188       ret = g_variant_new_int32 (myobj->count);
189     }
190   else if (g_strcmp0 (property_name, "Name") == 0)
191     {
192       ret = g_variant_new_string (myobj->name ? myobj->name : "");
193     }
194
195   return ret;
196 }
197
198 static gboolean
199 handle_set_property (GDBusConnection  *connection,
200                      const gchar      *sender,
201                      const gchar      *object_path,
202                      const gchar      *interface_name,
203                      const gchar      *property_name,
204                      GVariant         *value,
205                      GError          **error,
206                      gpointer          user_data)
207 {
208   MyObject *myobj = user_data;
209
210   if (g_strcmp0 (property_name, "Count") == 0)
211     {
212       g_object_set (myobj, "count", g_variant_get_int32 (value), NULL);
213     }
214   else if (g_strcmp0 (property_name, "Name") == 0)
215     {
216       g_object_set (myobj, "name", g_variant_get_string (value, NULL), NULL);
217     }
218
219   return TRUE;
220 }
221
222
223 /* for now */
224 static const GDBusInterfaceVTable interface_vtable =
225 {
226   handle_method_call,
227   handle_get_property,
228   handle_set_property
229 };
230
231 static void
232 send_property_change (GObject         *obj,
233                       GParamSpec      *pspec,
234                       GDBusConnection *connection)
235 {
236   GVariantBuilder *builder;
237   GVariantBuilder *invalidated_builder;
238   MyObject *myobj = (MyObject *)obj;
239
240   builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
241   invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
242
243   if (g_strcmp0 (pspec->name, "count") == 0)
244     g_variant_builder_add (builder,
245                            "{sv}",
246                            "Count", g_variant_new_int32 (myobj->count));
247   else if (g_strcmp0 (pspec->name, "name") == 0)
248     g_variant_builder_add (builder,
249                            "{sv}",
250                            "Name", g_variant_new_string (myobj->name ? myobj->name : ""));
251
252   g_dbus_connection_emit_signal (connection,
253                                  NULL,
254                                  "/org/myorg/MyObject",
255                                  "org.freedesktop.DBus.Properties",
256                                  "PropertiesChanged",
257                                  g_variant_new ("(sa{sv}as)",
258                                                 "org.myorg.MyObject",
259                                                 builder,
260                                                 invalidated_builder),
261                                  NULL);
262 }
263
264 static void
265 on_bus_acquired (GDBusConnection *connection,
266                  const gchar     *name,
267                  gpointer         user_data)
268 {
269   MyObject *myobj = user_data;
270   guint registration_id;
271
272   g_signal_connect (myobj, "notify",
273                     G_CALLBACK (send_property_change), connection);
274   registration_id = g_dbus_connection_register_object (connection,
275                                                        "/org/myorg/MyObject",
276                                                        introspection_data->interfaces[0],
277                                                        &interface_vtable,
278                                                        myobj,
279                                                        NULL,  /* user_data_free_func */
280                                                        NULL); /* GError** */
281   g_assert (registration_id > 0);
282 }
283
284 static void
285 on_name_acquired (GDBusConnection *connection,
286                   const gchar     *name,
287                   gpointer         user_data)
288 {
289 }
290
291 static void
292 on_name_lost (GDBusConnection *connection,
293               const gchar     *name,
294               gpointer         user_data)
295 {
296   exit (1);
297 }
298
299 int
300 main (int argc, char *argv[])
301 {
302   guint owner_id;
303   GMainLoop *loop;
304   MyObject *myobj;
305
306   /* We are lazy here - we don't want to manually provide
307    * the introspection data structures - so we just build
308    * them from XML.
309    */
310   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
311   g_assert (introspection_data != NULL);
312
313   myobj = g_object_new (my_object_get_type (), NULL);
314
315   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
316                              "org.myorg.MyObject",
317                              G_BUS_NAME_OWNER_FLAGS_NONE,
318                              on_bus_acquired,
319                              on_name_acquired,
320                              on_name_lost,
321                              myobj,
322                              NULL);
323
324   loop = g_main_loop_new (NULL, FALSE);
325   g_main_loop_run (loop);
326
327   g_bus_unown_name (owner_id);
328
329   g_dbus_node_info_unref (introspection_data);
330
331   g_object_unref (myobj);
332
333   return 0;
334 }