Add an example of exporting a GObject
[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 static GDBusNodeInfo *introspection_data = NULL;
133
134 /* Introspection data for the service we are exporting */
135 static const gchar introspection_xml[] =
136   "<node>"
137   "  <interface name='org.myorg.MyObject'>"
138   "    <method name='ChangeCount'>"
139   "      <arg type='i' name='change' direction='in'/>"
140   "    </method>"
141   "    <property type='i' name='Count' access='read'/>"
142   "    <property type='s' name='Name' access='readwrite'/>"
143   "  </interface>"
144   "</node>";
145
146
147 static void
148 handle_method_call (GDBusConnection       *connection,
149                     const gchar           *sender,
150                     const gchar           *object_path,
151                     const gchar           *interface_name,
152                     const gchar           *method_name,
153                     GVariant              *parameters,
154                     GDBusMethodInvocation *invocation,
155                     gpointer               user_data)
156 {
157   MyObject *myobj = user_data;
158
159   if (g_strcmp0 (method_name, "ChangeCount") == 0)
160     {
161       gint change;
162       g_variant_get (parameters, "(i)", &change);
163
164       my_object_change_count (myobj, change);
165
166       g_dbus_method_invocation_return_value (invocation, NULL);
167     }
168 }
169
170 static GVariant *
171 handle_get_property (GDBusConnection  *connection,
172                      const gchar      *sender,
173                      const gchar      *object_path,
174                      const gchar      *interface_name,
175                      const gchar      *property_name,
176                      GError          **error,
177                      gpointer          user_data)
178 {
179   GVariant *ret;
180   MyObject *myobj = user_data;
181
182   ret = NULL;
183   if (g_strcmp0 (property_name, "Count") == 0)
184     {
185       ret = g_variant_new_int32 (myobj->count);
186     }
187   else if (g_strcmp0 (property_name, "Name") == 0)
188     {
189       ret = g_variant_new_string (myobj->name ? myobj->name : "");
190     }
191
192   return ret;
193 }
194
195 static gboolean
196 handle_set_property (GDBusConnection  *connection,
197                      const gchar      *sender,
198                      const gchar      *object_path,
199                      const gchar      *interface_name,
200                      const gchar      *property_name,
201                      GVariant         *value,
202                      GError          **error,
203                      gpointer          user_data)
204 {
205   MyObject *myobj = user_data;
206
207   if (g_strcmp0 (property_name, "Count") == 0)
208     {
209       g_object_set (myobj, "count", g_variant_get_int32 (value), NULL);
210     }
211   else if (g_strcmp0 (property_name, "Name") == 0)
212     {
213       g_object_set (myobj, "name", g_variant_get_string (value, NULL), NULL);
214     }
215
216   return TRUE;
217 }
218
219
220 /* for now */
221 static const GDBusInterfaceVTable interface_vtable =
222 {
223   handle_method_call,
224   handle_get_property,
225   handle_set_property
226 };
227
228 static void
229 send_property_change (GObject         *obj,
230                       GParamSpec      *pspec,
231                       GDBusConnection *connection)
232 {
233   GVariantBuilder *builder;
234   MyObject *myobj = (MyObject *)obj;
235
236   builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
237
238   if (g_strcmp0 (pspec->name, "count") == 0)
239     g_variant_builder_add (builder,
240                            "{sv}",
241                            "Count", g_variant_new_int32 (myobj->count));
242   else if (g_strcmp0 (pspec->name, "name") == 0)
243     g_variant_builder_add (builder,
244                            "{sv}",
245                            "Name", g_variant_new_string (myobj->name ? myobj->name : ""));
246
247   g_dbus_connection_emit_signal (connection,
248                                  NULL,
249                                  "/org/myorg/MyObject",
250                                  "org.myorg.MyObject",
251                                  "PropertiesChanged",
252                                  g_variant_new ("(sa{sv})",
253                                                 "org.myorg.MyObject",
254                                                 builder),
255                                  NULL);
256 }
257
258 static void
259 on_bus_acquired (GDBusConnection *connection,
260                  const gchar     *name,
261                  gpointer         user_data)
262 {
263   MyObject *myobj = user_data;
264   guint registration_id;
265
266   g_signal_connect (myobj, "notify",
267                     G_CALLBACK (send_property_change), connection);
268   registration_id = g_dbus_connection_register_object (connection,
269                                                        "/org/myorg/MyObject",
270                                                        "org.myorg.MyObject",
271                                                        introspection_data->interfaces[0],
272                                                        &interface_vtable,
273                                                        myobj,
274                                                        NULL,  /* user_data_free_func */
275                                                        NULL); /* GError** */
276   g_assert (registration_id > 0);
277 }
278
279 static void
280 on_name_acquired (GDBusConnection *connection,
281                   const gchar     *name,
282                   gpointer         user_data)
283 {
284 }
285
286 static void
287 on_name_lost (GDBusConnection *connection,
288               const gchar     *name,
289               gpointer         user_data)
290 {
291   exit (1);
292 }
293
294 int
295 main (int argc, char *argv[])
296 {
297   guint owner_id;
298   GMainLoop *loop;
299   MyObject *myobj;
300
301   g_type_init ();
302
303   /* We are lazy here - we don't want to manually provide
304    * the introspection data structures - so we just build
305    * them from XML.
306    */
307   introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
308   g_assert (introspection_data != NULL);
309
310   myobj = g_object_new (my_object_get_type (), NULL);
311
312   owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
313                              "org.myorg.MyObject",
314                              G_BUS_NAME_OWNER_FLAGS_NONE,
315                              on_bus_acquired,
316                              on_name_acquired,
317                              on_name_lost,
318                              myobj,
319                              NULL);
320
321   loop = g_main_loop_new (NULL, FALSE);
322   g_main_loop_run (loop);
323
324   g_bus_unown_name (owner_id);
325
326   g_dbus_node_info_unref (introspection_data);
327
328   g_object_unref (myobj);
329
330   return 0;
331 }