Branch data Line data Source code
1 : : #include <gio/gio.h>
2 : : #include <stdlib.h>
3 : :
4 : : #ifdef G_OS_UNIX
5 : : #include <gio/gunixfdlist.h>
6 : : /* For STDOUT_FILENO */
7 : : #include <unistd.h>
8 : : #endif
9 : :
10 : : /* ---------------------------------------------------------------------------------------------------- */
11 : :
12 : : static GDBusNodeInfo *introspection_data = NULL;
13 : :
14 : : /* Introspection data for the service we are exporting */
15 : : static const gchar introspection_xml[] =
16 : : "<node>"
17 : : " <interface name='org.gtk.GDBus.TestInterface'>"
18 : : " <annotation name='org.gtk.GDBus.Annotation' value='OnInterface'/>"
19 : : " <annotation name='org.gtk.GDBus.Annotation' value='AlsoOnInterface'/>"
20 : : " <method name='HelloWorld'>"
21 : : " <annotation name='org.gtk.GDBus.Annotation' value='OnMethod'/>"
22 : : " <arg type='s' name='greeting' direction='in'/>"
23 : : " <arg type='s' name='response' direction='out'/>"
24 : : " </method>"
25 : : " <method name='EmitSignal'>"
26 : : " <arg type='d' name='speed_in_mph' direction='in'>"
27 : : " <annotation name='org.gtk.GDBus.Annotation' value='OnArg'/>"
28 : : " </arg>"
29 : : " </method>"
30 : : " <method name='GimmeStdout'/>"
31 : : " <signal name='VelocityChanged'>"
32 : : " <annotation name='org.gtk.GDBus.Annotation' value='Onsignal'/>"
33 : : " <arg type='d' name='speed_in_mph'/>"
34 : : " <arg type='s' name='speed_as_string'>"
35 : : " <annotation name='org.gtk.GDBus.Annotation' value='OnArg_NonFirst'/>"
36 : : " </arg>"
37 : : " </signal>"
38 : : " <property type='s' name='FluxCapicitorName' access='read'>"
39 : : " <annotation name='org.gtk.GDBus.Annotation' value='OnProperty'>"
40 : : " <annotation name='org.gtk.GDBus.Annotation' value='OnAnnotation_YesThisIsCrazy'/>"
41 : : " </annotation>"
42 : : " </property>"
43 : : " <property type='s' name='Title' access='readwrite'/>"
44 : : " <property type='s' name='ReadingAlwaysThrowsError' access='read'/>"
45 : : " <property type='s' name='WritingAlwaysThrowsError' access='readwrite'/>"
46 : : " <property type='s' name='OnlyWritable' access='write'/>"
47 : : " <property type='s' name='Foo' access='read'/>"
48 : : " <property type='s' name='Bar' access='read'/>"
49 : : " </interface>"
50 : : "</node>";
51 : :
52 : : /* ---------------------------------------------------------------------------------------------------- */
53 : :
54 : : static void
55 : 0 : handle_method_call (GDBusConnection *connection,
56 : : const gchar *sender,
57 : : const gchar *object_path,
58 : : const gchar *interface_name,
59 : : const gchar *method_name,
60 : : GVariant *parameters,
61 : : GDBusMethodInvocation *invocation,
62 : : gpointer user_data)
63 : : {
64 [ # # ]: 0 : if (g_strcmp0 (method_name, "HelloWorld") == 0)
65 : : {
66 : : const gchar *greeting;
67 : :
68 : 0 : g_variant_get (parameters, "(&s)", &greeting);
69 : :
70 [ # # ]: 0 : if (g_strcmp0 (greeting, "Return Unregistered") == 0)
71 : : {
72 : 0 : g_dbus_method_invocation_return_error (invocation,
73 : : G_IO_ERROR,
74 : : G_IO_ERROR_FAILED_HANDLED,
75 : : "As requested, here's a GError not registered (G_IO_ERROR_FAILED_HANDLED)");
76 : : }
77 [ # # ]: 0 : else if (g_strcmp0 (greeting, "Return Registered") == 0)
78 : : {
79 : 0 : g_dbus_method_invocation_return_error (invocation,
80 : : G_DBUS_ERROR,
81 : : G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
82 : : "As requested, here's a GError that is registered (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
83 : : }
84 [ # # ]: 0 : else if (g_strcmp0 (greeting, "Return Raw") == 0)
85 : : {
86 : 0 : g_dbus_method_invocation_return_dbus_error (invocation,
87 : : "org.gtk.GDBus.SomeErrorName",
88 : : "As requested, here's a raw D-Bus error");
89 : : }
90 : : else
91 : : {
92 : : gchar *response;
93 : 0 : response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
94 : 0 : g_dbus_method_invocation_return_value (invocation,
95 : : g_variant_new ("(s)", response));
96 : 0 : g_free (response);
97 : : }
98 : : }
99 [ # # ]: 0 : else if (g_strcmp0 (method_name, "EmitSignal") == 0)
100 : : {
101 : : GError *local_error;
102 : : gdouble speed_in_mph;
103 : : gchar *speed_as_string;
104 : :
105 : 0 : g_variant_get (parameters, "(d)", &speed_in_mph);
106 : 0 : speed_as_string = g_strdup_printf ("%g mph!", speed_in_mph);
107 : :
108 : 0 : local_error = NULL;
109 : 0 : g_dbus_connection_emit_signal (connection,
110 : : NULL,
111 : : object_path,
112 : : interface_name,
113 : : "VelocityChanged",
114 : : g_variant_new ("(ds)",
115 : : speed_in_mph,
116 : : speed_as_string),
117 : : &local_error);
118 : 0 : g_assert_no_error (local_error);
119 : 0 : g_free (speed_as_string);
120 : :
121 : 0 : g_dbus_method_invocation_return_value (invocation, NULL);
122 : : }
123 [ # # ]: 0 : else if (g_strcmp0 (method_name, "GimmeStdout") == 0)
124 : : {
125 : : #ifdef G_OS_UNIX
126 [ # # ]: 0 : if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
127 : : {
128 : : GDBusMessage *reply;
129 : : GUnixFDList *fd_list;
130 : : GError *error;
131 : :
132 : 0 : fd_list = g_unix_fd_list_new ();
133 : 0 : error = NULL;
134 : 0 : g_unix_fd_list_append (fd_list, STDOUT_FILENO, &error);
135 : 0 : g_assert_no_error (error);
136 : :
137 : 0 : reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
138 : 0 : g_dbus_message_set_unix_fd_list (reply, fd_list);
139 : :
140 : 0 : error = NULL;
141 : 0 : g_dbus_connection_send_message (connection,
142 : : reply,
143 : : G_DBUS_SEND_MESSAGE_FLAGS_NONE,
144 : : NULL, /* out_serial */
145 : : &error);
146 : 0 : g_assert_no_error (error);
147 : :
148 : 0 : g_object_unref (invocation);
149 : 0 : g_object_unref (fd_list);
150 : 0 : g_object_unref (reply);
151 : : }
152 : : else
153 : : {
154 : 0 : g_dbus_method_invocation_return_dbus_error (invocation,
155 : : "org.gtk.GDBus.Failed",
156 : : "Your message bus daemon does not support file descriptor passing (need D-Bus >= 1.3.0)");
157 : : }
158 : : #else
159 : : g_dbus_method_invocation_return_dbus_error (invocation,
160 : : "org.gtk.GDBus.NotOnUnix",
161 : : "Your OS does not support file descriptor passing");
162 : : #endif
163 : : }
164 : 0 : }
165 : :
166 : : static gchar *_global_title = NULL;
167 : :
168 : : static gboolean swap_a_and_b = FALSE;
169 : :
170 : : static GVariant *
171 : 0 : 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 : :
181 : 0 : ret = NULL;
182 [ # # ]: 0 : if (g_strcmp0 (property_name, "FluxCapicitorName") == 0)
183 : : {
184 : 0 : ret = g_variant_new_string ("DeLorean");
185 : : }
186 [ # # ]: 0 : else if (g_strcmp0 (property_name, "Title") == 0)
187 : : {
188 [ # # ]: 0 : if (_global_title == NULL)
189 : 0 : _global_title = g_strdup ("Back To C!");
190 : 0 : ret = g_variant_new_string (_global_title);
191 : : }
192 [ # # ]: 0 : else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
193 : : {
194 : 0 : g_set_error (error,
195 : : G_IO_ERROR,
196 : : G_IO_ERROR_FAILED,
197 : : "Hello %s. I thought I said reading this property "
198 : : "always results in an error. kthxbye",
199 : : sender);
200 : : }
201 [ # # ]: 0 : else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
202 : : {
203 : 0 : ret = g_variant_new_string ("There's no home like home");
204 : : }
205 [ # # ]: 0 : else if (g_strcmp0 (property_name, "Foo") == 0)
206 : : {
207 [ # # ]: 0 : ret = g_variant_new_string (swap_a_and_b ? "Tock" : "Tick");
208 : : }
209 [ # # ]: 0 : else if (g_strcmp0 (property_name, "Bar") == 0)
210 : : {
211 [ # # ]: 0 : ret = g_variant_new_string (swap_a_and_b ? "Tick" : "Tock");
212 : : }
213 : :
214 : 0 : return ret;
215 : : }
216 : :
217 : : static gboolean
218 : 0 : handle_set_property (GDBusConnection *connection,
219 : : const gchar *sender,
220 : : const gchar *object_path,
221 : : const gchar *interface_name,
222 : : const gchar *property_name,
223 : : GVariant *value,
224 : : GError **error,
225 : : gpointer user_data)
226 : : {
227 [ # # ]: 0 : if (g_strcmp0 (property_name, "Title") == 0)
228 : : {
229 [ # # ]: 0 : if (g_strcmp0 (_global_title, g_variant_get_string (value, NULL)) != 0)
230 : : {
231 : : GVariantBuilder *builder;
232 : : GError *local_error;
233 : :
234 : 0 : g_free (_global_title);
235 : 0 : _global_title = g_variant_dup_string (value, NULL);
236 : :
237 : 0 : local_error = NULL;
238 : 0 : builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
239 : 0 : g_variant_builder_add (builder,
240 : : "{sv}",
241 : : "Title",
242 : : g_variant_new_string (_global_title));
243 : 0 : g_dbus_connection_emit_signal (connection,
244 : : NULL,
245 : : object_path,
246 : : "org.freedesktop.DBus.Properties",
247 : : "PropertiesChanged",
248 : : g_variant_new ("(sa{sv}as)",
249 : : interface_name,
250 : : builder,
251 : : NULL),
252 : : &local_error);
253 : 0 : g_assert_no_error (local_error);
254 : : }
255 : : }
256 [ # # ]: 0 : else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
257 : : {
258 : : /* do nothing - they can't read it after all! */
259 : : }
260 [ # # ]: 0 : else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
261 : : {
262 : 0 : g_set_error (error,
263 : : G_IO_ERROR,
264 : : G_IO_ERROR_FAILED,
265 : : "Hello AGAIN %s. I thought I said writing this property "
266 : : "always results in an error. kthxbye",
267 : : sender);
268 : : }
269 : :
270 : 0 : return *error == NULL;
271 : : }
272 : :
273 : :
274 : : /* for now */
275 : : static const GDBusInterfaceVTable interface_vtable =
276 : : {
277 : : handle_method_call,
278 : : handle_get_property,
279 : : handle_set_property,
280 : : { 0 }
281 : : };
282 : :
283 : : /* ---------------------------------------------------------------------------------------------------- */
284 : :
285 : : static gboolean
286 : 0 : on_timeout_cb (gpointer user_data)
287 : : {
288 : 0 : GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
289 : : GVariantBuilder *builder;
290 : : GVariantBuilder *invalidated_builder;
291 : : GError *error;
292 : :
293 : 0 : swap_a_and_b = !swap_a_and_b;
294 : :
295 : 0 : error = NULL;
296 : 0 : builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
297 : 0 : invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
298 : 0 : g_variant_builder_add (builder,
299 : : "{sv}",
300 : : "Foo",
301 [ # # ]: 0 : g_variant_new_string (swap_a_and_b ? "Tock" : "Tick"));
302 : 0 : g_variant_builder_add (builder,
303 : : "{sv}",
304 : : "Bar",
305 [ # # ]: 0 : g_variant_new_string (swap_a_and_b ? "Tick" : "Tock"));
306 : 0 : g_dbus_connection_emit_signal (connection,
307 : : NULL,
308 : : "/org/gtk/GDBus/TestObject",
309 : : "org.freedesktop.DBus.Properties",
310 : : "PropertiesChanged",
311 : : g_variant_new ("(sa{sv}as)",
312 : : "org.gtk.GDBus.TestInterface",
313 : : builder,
314 : : invalidated_builder),
315 : : &error);
316 : 0 : g_assert_no_error (error);
317 : :
318 : :
319 : 0 : return G_SOURCE_CONTINUE;
320 : : }
321 : :
322 : : /* ---------------------------------------------------------------------------------------------------- */
323 : :
324 : : static void
325 : 0 : on_bus_acquired (GDBusConnection *connection,
326 : : const gchar *name,
327 : : gpointer user_data)
328 : : {
329 : : guint registration_id;
330 : :
331 : 0 : registration_id = g_dbus_connection_register_object (connection,
332 : : "/org/gtk/GDBus/TestObject",
333 : 0 : introspection_data->interfaces[0],
334 : : &interface_vtable,
335 : : NULL, /* user_data */
336 : : NULL, /* user_data_free_func */
337 : : NULL); /* GError** */
338 : 0 : g_assert (registration_id > 0);
339 : :
340 : : /* swap value of properties Foo and Bar every two seconds */
341 : 0 : g_timeout_add_seconds (2,
342 : : on_timeout_cb,
343 : : connection);
344 : 0 : }
345 : :
346 : : static void
347 : 0 : on_name_acquired (GDBusConnection *connection,
348 : : const gchar *name,
349 : : gpointer user_data)
350 : : {
351 : 0 : }
352 : :
353 : : static void
354 : 0 : on_name_lost (GDBusConnection *connection,
355 : : const gchar *name,
356 : : gpointer user_data)
357 : : {
358 : 0 : exit (1);
359 : : }
360 : :
361 : : int
362 : 0 : main (int argc, char *argv[])
363 : : {
364 : : guint owner_id;
365 : : GMainLoop *loop;
366 : :
367 : : /* We are lazy here - we don't want to manually provide
368 : : * the introspection data structures - so we just build
369 : : * them from XML.
370 : : */
371 : 0 : introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
372 : 0 : g_assert (introspection_data != NULL);
373 : :
374 : 0 : owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
375 : : "org.gtk.GDBus.TestServer",
376 : : G_BUS_NAME_OWNER_FLAGS_NONE,
377 : : on_bus_acquired,
378 : : on_name_acquired,
379 : : on_name_lost,
380 : : NULL,
381 : : NULL);
382 : :
383 : 0 : loop = g_main_loop_new (NULL, FALSE);
384 : 0 : g_main_loop_run (loop);
385 : :
386 : 0 : g_bus_unown_name (owner_id);
387 : :
388 : 0 : g_dbus_node_info_unref (introspection_data);
389 : :
390 : 0 : return 0;
391 : : }
|