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