gkdbus: Fix underflow and unreachable code bug
[platform/upstream/glib.git] / gio / tests / gdbus-example-proxy-subclass.c
1
2 #include <gio/gio.h>
3
4 /* ---------------------------------------------------------------------------------------------------- */
5 /* The D-Bus interface definition we want to create a GDBusProxy-derived type for: */
6 /* ---------------------------------------------------------------------------------------------------- */
7
8 static const gchar introspection_xml[] =
9   "<node>"
10   "  <interface name='org.freedesktop.Accounts.User'>"
11   "    <method name='Frobnicate'>"
12   "      <arg name='flux' type='s' direction='in'/>"
13   "      <arg name='baz' type='s' direction='in'/>"
14   "      <arg name='result' type='s' direction='out'/>"
15   "    </method>"
16   "    <signal name='Changed'/>"
17   "    <property name='AutomaticLogin' type='b' access='readwrite'/>"
18   "    <property name='RealName' type='s' access='read'/>"
19   "    <property name='UserName' type='s' access='read'/>"
20   "  </interface>"
21   "</node>";
22
23 /* ---------------------------------------------------------------------------------------------------- */
24 /* Definition of the AccountsUser type */
25 /* ---------------------------------------------------------------------------------------------------- */
26
27 #define ACCOUNTS_TYPE_USER         (accounts_user_get_type ())
28 #define ACCOUNTS_USER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), ACCOUNTS_TYPE_USER, AccountsUser))
29 #define ACCOUNTS_USER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), ACCOUNTS_TYPE_USER, AccountsUserClass))
30 #define ACCOUNTS_USER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), ACCOUNTS_TYPE_USER, AccountsUserClass))
31 #define ACCOUNTS_IS_USER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ACCOUNTS_TYPE_USER))
32 #define ACCOUNTS_IS_USER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), ACCOUNTS_TYPE_USER))
33
34 typedef struct _AccountsUser        AccountsUser;
35 typedef struct _AccountsUserClass   AccountsUserClass;
36 typedef struct _AccountsUserPrivate AccountsUserPrivate;
37
38 struct _AccountsUser
39 {
40   /*< private >*/
41   GDBusProxy parent_instance;
42   AccountsUserPrivate *priv;
43 };
44
45 struct _AccountsUserClass
46 {
47   /*< private >*/
48   GDBusProxyClass parent_class;
49   void (*changed) (AccountsUser *user);
50 };
51
52 GType        accounts_user_get_type            (void) G_GNUC_CONST;
53
54 const gchar *accounts_user_get_user_name       (AccountsUser        *user);
55 const gchar *accounts_user_get_real_name       (AccountsUser        *user);
56 gboolean     accounts_user_get_automatic_login (AccountsUser        *user);
57
58 void         accounts_user_frobnicate          (AccountsUser        *user,
59                                                 const gchar         *flux,
60                                                 gint                 baz,
61                                                 GCancellable        *cancellable,
62                                                 GAsyncReadyCallback  callback,
63                                                 gpointer             user_data);
64 gchar       *accounts_user_frobnicate_finish   (AccountsUser        *user,
65                                                 GAsyncResult        *res,
66                                                 GError             **error);
67 gchar       *accounts_user_frobnicate_sync     (AccountsUser        *user,
68                                                 const gchar         *flux,
69                                                 gint                 baz,
70                                                 GCancellable        *cancellable,
71                                                 GError             **error);
72
73 /* ---------------------------------------------------------------------------------------------------- */
74 /* Implementation of the AccountsUser type */
75 /* ---------------------------------------------------------------------------------------------------- */
76
77 /* A more efficient approach than parsing XML is to use const static
78  * GDBusInterfaceInfo, GDBusMethodInfo, ... structures
79  */
80 static GDBusInterfaceInfo *
81 accounts_user_get_interface_info (void)
82 {
83   static gsize has_info = 0;
84   static GDBusInterfaceInfo *info = NULL;
85   if (g_once_init_enter (&has_info))
86     {
87       GDBusNodeInfo *introspection_data;
88       introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
89       info = introspection_data->interfaces[0];
90       g_once_init_leave (&has_info, 1);
91     }
92   return info;
93 }
94
95 enum
96 {
97   PROP_0,
98   PROP_USER_NAME,
99   PROP_REAL_NAME,
100   PROP_AUTOMATIC_LOGIN,
101 };
102
103 enum
104 {
105   CHANGED_SIGNAL,
106   LAST_SIGNAL
107 };
108
109 static guint signals[LAST_SIGNAL] = {0};
110
111 G_DEFINE_TYPE (AccountsUser, accounts_user, G_TYPE_DBUS_PROXY)
112
113 static void
114 accounts_user_init (AccountsUser *user)
115 {
116   /* Sets the expected interface */
117   g_dbus_proxy_set_interface_info (G_DBUS_PROXY (user), accounts_user_get_interface_info ());
118 }
119
120 static void
121 accounts_user_get_property (GObject    *object,
122                             guint       prop_id,
123                             GValue     *value,
124                             GParamSpec *pspec)
125 {
126   AccountsUser *user = ACCOUNTS_USER (object);
127
128   switch (prop_id)
129     {
130     case PROP_USER_NAME:
131       g_value_set_string (value, accounts_user_get_user_name (user));
132       break;
133
134     case PROP_REAL_NAME:
135       g_value_set_string (value, accounts_user_get_real_name (user));
136       break;
137
138     case PROP_AUTOMATIC_LOGIN:
139       g_value_set_boolean (value, accounts_user_get_automatic_login (user));
140       break;
141
142     default:
143       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
144       break;
145     }
146 }
147
148 const gchar *
149 accounts_user_get_user_name (AccountsUser *user)
150 {
151   GVariant *value;
152   const gchar *ret;
153   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
154   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "UserName");
155   ret = g_variant_get_string (value, NULL);
156   g_variant_unref (value);
157   return ret;
158 }
159
160 const gchar *
161 accounts_user_get_real_name (AccountsUser *user)
162 {
163   GVariant *value;
164   const gchar *ret;
165   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
166   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "RealName");
167   ret = g_variant_get_string (value, NULL);
168   g_variant_unref (value);
169   return ret;
170 }
171
172 gboolean
173 accounts_user_get_automatic_login (AccountsUser *user)
174 {
175   GVariant *value;
176   gboolean ret;
177   g_return_val_if_fail (ACCOUNTS_IS_USER (user), FALSE);
178   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "AutomaticLogin");
179   ret = g_variant_get_boolean (value);
180   g_variant_unref (value);
181   return ret;
182 }
183
184 static void
185 accounts_user_g_signal (GDBusProxy   *proxy,
186                         const gchar  *sender_name,
187                         const gchar  *signal_name,
188                         GVariant     *parameters)
189 {
190   AccountsUser *user = ACCOUNTS_USER (proxy);
191   if (g_strcmp0 (signal_name, "Changed") == 0)
192     g_signal_emit (user, signals[CHANGED_SIGNAL], 0);
193 }
194
195 static void
196 accounts_user_g_properties_changed (GDBusProxy          *proxy,
197                                     GVariant            *changed_properties,
198                                     const gchar* const  *invalidated_properties)
199 {
200   AccountsUser *user = ACCOUNTS_USER (proxy);
201   GVariantIter *iter;
202   const gchar *key;
203
204   if (changed_properties != NULL)
205     {
206       g_variant_get (changed_properties, "a{sv}", &iter);
207       while (g_variant_iter_next (iter, "{&sv}", &key, NULL))
208         {
209           if (g_strcmp0 (key, "AutomaticLogin") == 0)
210             g_object_notify (G_OBJECT (user), "automatic-login");
211           else if (g_strcmp0 (key, "RealName") == 0)
212             g_object_notify (G_OBJECT (user), "real-name");
213           else if (g_strcmp0 (key, "UserName") == 0)
214             g_object_notify (G_OBJECT (user), "user-name");
215         }
216       g_variant_iter_free (iter);
217     }
218 }
219
220 static void
221 accounts_user_class_init (AccountsUserClass *klass)
222 {
223   GObjectClass *gobject_class;
224   GDBusProxyClass *proxy_class;
225
226   gobject_class = G_OBJECT_CLASS (klass);
227   gobject_class->get_property = accounts_user_get_property;
228
229   proxy_class = G_DBUS_PROXY_CLASS (klass);
230   proxy_class->g_signal             = accounts_user_g_signal;
231   proxy_class->g_properties_changed = accounts_user_g_properties_changed;
232
233   g_object_class_install_property (gobject_class,
234                                    PROP_USER_NAME,
235                                    g_param_spec_string ("user-name",
236                                                         "User Name",
237                                                         "The user name of the user",
238                                                         NULL,
239                                                         G_PARAM_READABLE |
240                                                         G_PARAM_STATIC_STRINGS));
241
242   g_object_class_install_property (gobject_class,
243                                    PROP_REAL_NAME,
244                                    g_param_spec_string ("real-name",
245                                                         "Real Name",
246                                                         "The real name of the user",
247                                                         NULL,
248                                                         G_PARAM_READABLE |
249                                                         G_PARAM_STATIC_STRINGS));
250
251   g_object_class_install_property (gobject_class,
252                                    PROP_AUTOMATIC_LOGIN,
253                                    g_param_spec_boolean ("automatic-login",
254                                                          "Automatic Login",
255                                                          "Whether the user is automatically logged in",
256                                                          FALSE,
257                                                          G_PARAM_READABLE |
258                                                          G_PARAM_STATIC_STRINGS));
259
260   signals[CHANGED_SIGNAL] = g_signal_new ("changed",
261                                           ACCOUNTS_TYPE_USER,
262                                           G_SIGNAL_RUN_LAST,
263                                           G_STRUCT_OFFSET (AccountsUserClass, changed),
264                                           NULL,
265                                           NULL,
266                                           g_cclosure_marshal_VOID__VOID,
267                                           G_TYPE_NONE,
268                                           0);
269 }
270
271 gchar *
272 accounts_user_frobnicate_sync (AccountsUser        *user,
273                                const gchar         *flux,
274                                gint                 baz,
275                                GCancellable        *cancellable,
276                                GError             **error)
277 {
278   gchar *ret;
279   GVariant *value;
280
281   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
282
283   ret = NULL;
284
285   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (user),
286                                   "Frobnicate",
287                                   g_variant_new ("(si)",
288                                                  flux,
289                                                  baz),
290                                   G_DBUS_CALL_FLAGS_NONE,
291                                   -1,
292                                   cancellable,
293                                   error);
294   if (value != NULL)
295     {
296       g_variant_get (value, "(s)", &ret);
297       g_variant_unref (value);
298     }
299   return ret;
300 }
301
302 void
303 accounts_user_frobnicate (AccountsUser        *user,
304                           const gchar         *flux,
305                           gint                 baz,
306                           GCancellable        *cancellable,
307                           GAsyncReadyCallback  callback,
308                           gpointer             user_data)
309 {
310   g_return_if_fail (ACCOUNTS_IS_USER (user));
311   g_dbus_proxy_call (G_DBUS_PROXY (user),
312                      "Frobnicate",
313                      g_variant_new ("(si)",
314                                     flux,
315                                     baz),
316                      G_DBUS_CALL_FLAGS_NONE,
317                      -1,
318                      cancellable,
319                      callback,
320                      user_data);
321 }
322
323
324 gchar *
325 accounts_user_frobnicate_finish (AccountsUser        *user,
326                                  GAsyncResult        *res,
327                                  GError             **error)
328 {
329   gchar *ret;
330   GVariant *value;
331
332   ret = NULL;
333   value = g_dbus_proxy_call_finish (G_DBUS_PROXY (user), res, error);
334   if (value != NULL)
335     {
336       g_variant_get (value, "(s)", &ret);
337       g_variant_unref (value);
338     }
339   return ret;
340 }
341
342 /* ---------------------------------------------------------------------------------------------------- */
343 /* Example usage of the AccountsUser type */
344 /* ---------------------------------------------------------------------------------------------------- */
345
346 static void
347 print_user (AccountsUser *user)
348 {
349   g_print ("  user-name       = `%s'\n", accounts_user_get_user_name (user));
350   g_print ("  real-name       = `%s'\n", accounts_user_get_real_name (user));
351   g_print ("  automatic-login = %s\n", accounts_user_get_automatic_login (user) ? "true" : "false");
352 }
353
354 static void
355 on_changed (AccountsUser *user,
356             gpointer      user_data)
357 {
358   g_print ("+++ Received the AccountsUser::changed signal\n");
359   print_user (user);
360 }
361
362 static void
363 on_notify (GObject    *object,
364            GParamSpec *pspec,
365            gpointer    user_data)
366 {
367   AccountsUser *user = ACCOUNTS_USER (object);
368   g_print ("+++ Received the GObject::notify signal for property `%s'\n",
369            pspec->name);
370   print_user (user);
371 }
372
373 static void
374 on_accounts_proxy_available (GObject      *object,
375                              GAsyncResult *result,
376                              gpointer      user_data)
377 {
378   GError *error = NULL;
379   GObject *user_object;
380   AccountsUser *user;
381
382   user_object = g_async_initable_new_finish (G_ASYNC_INITABLE (object),
383                                              result,
384                                              &error);
385   if (!user_object)
386     {
387       g_error ("Failed to create proxy: %s", error->message);
388       g_clear_error (&error);
389       return;
390     }
391   user = ACCOUNTS_USER (user_object);
392
393   g_print ("+++ Acquired proxy for user\n");
394   print_user (user);
395
396   g_signal_connect (user,
397                     "notify",
398                     G_CALLBACK (on_notify),
399                     NULL);
400   g_signal_connect (user,
401                     "changed",
402                     G_CALLBACK (on_changed),
403                     NULL);
404 }
405
406 static void
407 on_accounts_appeared (GDBusConnection *connection,
408                       const gchar     *name,
409                       const gchar     *name_owner,
410                       gpointer         user_data)
411 {
412   g_async_initable_new_async (ACCOUNTS_TYPE_USER, 0, NULL,
413                               on_accounts_proxy_available,
414                               "g-flags", 0,
415                               "g-interface-info", NULL,
416                               "g-unique-bus-name", name_owner,
417                               "g-connection", connection,
418                               "g-object-path", "/org/freedesktop/Accounts/User500",
419                               "g-interface-name", "org.freedesktop.Accounts.User");
420 }
421
422 static void
423 on_accounts_vanished (GDBusConnection *connection,
424                       const gchar     *name,
425                       gpointer         user_data)
426 {
427 }
428
429 /* ---------------------------------------------------------------------------------------------------- */
430
431 gint
432 main (gint argc, gchar *argv[])
433 {
434   guint watcher_id;
435   GMainLoop *loop;
436
437   watcher_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
438                                  "org.freedesktop.Accounts",
439                                  G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
440                                  on_accounts_appeared,
441                                  on_accounts_vanished,
442                                  NULL, NULL);
443
444   loop = g_main_loop_new (NULL, FALSE);
445   g_main_loop_run (loop);
446   g_main_loop_unref (loop);
447   g_bus_unwatch_name (watcher_id);
448
449   return 0;
450 }