GDBus: Catch up with new PropertiesChanged signal
[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_finalize (GObject *object)
115 {
116   G_GNUC_UNUSED AccountsUser *user = ACCOUNTS_USER (object);
117
118   if (G_OBJECT_CLASS (accounts_user_parent_class)->finalize != NULL)
119     G_OBJECT_CLASS (accounts_user_parent_class)->finalize (object);
120 }
121
122 static void
123 accounts_user_init (AccountsUser *user)
124 {
125   /* Sets the expected interface */
126   g_dbus_proxy_set_interface_info (G_DBUS_PROXY (user), accounts_user_get_interface_info ());
127 }
128
129 static void
130 accounts_user_get_property (GObject    *object,
131                             guint       prop_id,
132                             GValue     *value,
133                             GParamSpec *pspec)
134 {
135   AccountsUser *user = ACCOUNTS_USER (object);
136
137   switch (prop_id)
138     {
139     case PROP_USER_NAME:
140       g_value_set_string (value, accounts_user_get_user_name (user));
141       break;
142
143     case PROP_REAL_NAME:
144       g_value_set_string (value, accounts_user_get_real_name (user));
145       break;
146
147     case PROP_AUTOMATIC_LOGIN:
148       g_value_set_boolean (value, accounts_user_get_automatic_login (user));
149       break;
150
151     default:
152       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
153       break;
154     }
155 }
156
157 const gchar *
158 accounts_user_get_user_name (AccountsUser *user)
159 {
160   GVariant *value;
161   const gchar *ret;
162   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
163   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "UserName");
164   ret = g_variant_get_string (value, NULL);
165   g_variant_unref (value);
166   return ret;
167 }
168
169 const gchar *
170 accounts_user_get_real_name (AccountsUser *user)
171 {
172   GVariant *value;
173   const gchar *ret;
174   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
175   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "RealName");
176   ret = g_variant_get_string (value, NULL);
177   g_variant_unref (value);
178   return ret;
179 }
180
181 gboolean
182 accounts_user_get_automatic_login (AccountsUser *user)
183 {
184   GVariant *value;
185   gboolean ret;
186   g_return_val_if_fail (ACCOUNTS_IS_USER (user), FALSE);
187   value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (user), "AutomaticLogin");
188   ret = g_variant_get_boolean (value);
189   g_variant_unref (value);
190   return ret;
191 }
192
193 static void
194 accounts_user_g_signal (GDBusProxy   *proxy,
195                         const gchar  *sender_name,
196                         const gchar  *signal_name,
197                         GVariant     *parameters)
198 {
199   AccountsUser *user = ACCOUNTS_USER (proxy);
200   if (g_strcmp0 (signal_name, "Changed") == 0)
201     g_signal_emit (user, signals[CHANGED_SIGNAL], 0);
202 }
203
204 static void
205 accounts_user_g_properties_changed (GDBusProxy          *proxy,
206                                     GVariant            *changed_properties,
207                                     const gchar* const  *invalidated_properties)
208 {
209   AccountsUser *user = ACCOUNTS_USER (proxy);
210   GVariantIter *iter;
211   GVariant *item;
212
213   if (changed_properties != NULL)
214     {
215       g_variant_get (changed_properties, "a{sv}", &iter);
216       while ((item = g_variant_iter_next_value (iter)) != NULL)
217         {
218           const gchar *key;
219           g_variant_get (item,
220                          "{sv}",
221                          &key,
222                          NULL);
223           if (g_strcmp0 (key, "AutomaticLogin") == 0)
224             g_object_notify (G_OBJECT (user), "automatic-login");
225           else if (g_strcmp0 (key, "RealName") == 0)
226             g_object_notify (G_OBJECT (user), "real-name");
227           else if (g_strcmp0 (key, "UserName") == 0)
228             g_object_notify (G_OBJECT (user), "user-name");
229         }
230     }
231 }
232
233 static void
234 accounts_user_class_init (AccountsUserClass *klass)
235 {
236   GObjectClass *gobject_class;
237   GDBusProxyClass *proxy_class;
238
239   gobject_class = G_OBJECT_CLASS (klass);
240   gobject_class->get_property = accounts_user_get_property;
241   gobject_class->finalize = accounts_user_finalize;
242
243   proxy_class = G_DBUS_PROXY_CLASS (klass);
244   proxy_class->g_signal             = accounts_user_g_signal;
245   proxy_class->g_properties_changed = accounts_user_g_properties_changed;
246
247   g_object_class_install_property (gobject_class,
248                                    PROP_USER_NAME,
249                                    g_param_spec_string ("user-name",
250                                                         "User Name",
251                                                         "The user name of the user",
252                                                         NULL,
253                                                         G_PARAM_READABLE |
254                                                         G_PARAM_STATIC_STRINGS));
255
256   g_object_class_install_property (gobject_class,
257                                    PROP_REAL_NAME,
258                                    g_param_spec_string ("real-name",
259                                                         "Real Name",
260                                                         "The real name of the user",
261                                                         NULL,
262                                                         G_PARAM_READABLE |
263                                                         G_PARAM_STATIC_STRINGS));
264
265   g_object_class_install_property (gobject_class,
266                                    PROP_AUTOMATIC_LOGIN,
267                                    g_param_spec_boolean ("automatic-login",
268                                                          "Automatic Login",
269                                                          "Whether the user is automatically logged in",
270                                                          FALSE,
271                                                          G_PARAM_READABLE |
272                                                          G_PARAM_STATIC_STRINGS));
273
274   signals[CHANGED_SIGNAL] = g_signal_new ("changed",
275                                           ACCOUNTS_TYPE_USER,
276                                           G_SIGNAL_RUN_LAST,
277                                           G_STRUCT_OFFSET (AccountsUserClass, changed),
278                                           NULL,
279                                           NULL,
280                                           g_cclosure_marshal_VOID__VOID,
281                                           G_TYPE_NONE,
282                                           0);
283 }
284
285 gchar *
286 accounts_user_frobnicate_sync (AccountsUser        *user,
287                                const gchar         *flux,
288                                gint                 baz,
289                                GCancellable        *cancellable,
290                                GError             **error)
291 {
292   gchar *ret;
293   GVariant *value;
294
295   g_return_val_if_fail (ACCOUNTS_IS_USER (user), NULL);
296
297   ret = NULL;
298
299   value = g_dbus_proxy_call_sync (G_DBUS_PROXY (user),
300                                   "Frobnicate",
301                                   g_variant_new ("(si)",
302                                                  flux,
303                                                  baz),
304                                   G_DBUS_CALL_FLAGS_NONE,
305                                   -1,
306                                   cancellable,
307                                   error);
308   if (value != NULL)
309     {
310       g_variant_get (value, "(s)", &ret);
311       ret = g_strdup (ret);
312       g_variant_unref (value);
313     }
314   return ret;
315 }
316
317 void
318 accounts_user_frobnicate (AccountsUser        *user,
319                           const gchar         *flux,
320                           gint                 baz,
321                           GCancellable        *cancellable,
322                           GAsyncReadyCallback  callback,
323                           gpointer             user_data)
324 {
325   g_return_if_fail (ACCOUNTS_IS_USER (user));
326   g_dbus_proxy_call (G_DBUS_PROXY (user),
327                      "Frobnicate",
328                      g_variant_new ("(si)",
329                                     flux,
330                                     baz),
331                      G_DBUS_CALL_FLAGS_NONE,
332                      -1,
333                      cancellable,
334                      callback,
335                      user_data);
336 }
337
338
339 gchar *
340 accounts_user_frobnicate_finish (AccountsUser        *user,
341                                  GAsyncResult        *res,
342                                  GError             **error)
343 {
344   gchar *ret;
345   GVariant *value;
346
347   ret = NULL;
348   value = g_dbus_proxy_call_finish (G_DBUS_PROXY (user), res, error);
349   if (value != NULL)
350     {
351       g_variant_get (value, "(s)", &ret);
352       ret = g_strdup (ret);
353       g_variant_unref (value);
354     }
355   return ret;
356 }
357
358 /* ---------------------------------------------------------------------------------------------------- */
359 /* Example usage of the AccountsUser type */
360 /* ---------------------------------------------------------------------------------------------------- */
361
362 static void
363 print_user (AccountsUser *user)
364 {
365   g_print ("  user-name       = `%s'\n", accounts_user_get_user_name (user));
366   g_print ("  real-name       = `%s'\n", accounts_user_get_real_name (user));
367   g_print ("  automatic-login = %s\n", accounts_user_get_automatic_login (user) ? "true" : "false");
368 }
369
370 static void
371 on_changed (AccountsUser *user,
372             gpointer      user_data)
373 {
374   g_print ("+++ Received the AccountsUser::changed signal\n");
375   print_user (user);
376 }
377
378 static void
379 on_notify (GObject    *object,
380            GParamSpec *pspec,
381            gpointer    user_data)
382 {
383   AccountsUser *user = ACCOUNTS_USER (object);
384   g_print ("+++ Received the GObject::notify signal for property `%s'\n",
385            pspec->name);
386   print_user (user);
387 }
388
389 static void
390 on_proxy_appeared (GDBusConnection *connection,
391                    const gchar     *name,
392                    const gchar     *name_owner,
393                    GDBusProxy      *proxy,
394                    gpointer         user_data)
395 {
396   AccountsUser *user = ACCOUNTS_USER (proxy);
397
398   g_print ("+++ Acquired proxy for user\n");
399   print_user (user);
400
401   g_signal_connect (proxy,
402                     "notify",
403                     G_CALLBACK (on_notify),
404                     NULL);
405   g_signal_connect (user,
406                     "changed",
407                     G_CALLBACK (on_changed),
408                     NULL);
409 }
410
411 static void
412 on_proxy_vanished (GDBusConnection *connection,
413                    const gchar     *name,
414                    gpointer         user_data)
415 {
416   g_print ("--- Cannot create proxy for user: no remote object\n");
417 }
418
419 /* ---------------------------------------------------------------------------------------------------- */
420
421 gint
422 main (gint argc, gchar *argv[])
423 {
424   guint watcher_id;
425   GMainLoop *loop;
426
427   g_type_init ();
428
429   watcher_id = g_bus_watch_proxy (G_BUS_TYPE_SYSTEM,
430                                   "org.freedesktop.Accounts",
431                                   G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
432                                   "/org/freedesktop/Accounts/User500",
433                                   "org.freedesktop.Accounts.User",
434                                   ACCOUNTS_TYPE_USER,
435                                   G_DBUS_PROXY_FLAGS_NONE,
436                                   on_proxy_appeared,
437                                   on_proxy_vanished,
438                                   NULL,
439                                   NULL);
440
441   loop = g_main_loop_new (NULL, FALSE);
442   g_main_loop_run (loop);
443   g_main_loop_unref (loop);
444   g_bus_unwatch_proxy (watcher_id);
445
446   return 0;
447 }