Merge branch 'upstream' into tizen
[platform/upstream/glib.git] / gio / gdbusnamewatching.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "gdbusutils.h"
27 #include "gdbusnamewatching.h"
28 #include "gdbuserror.h"
29 #include "gdbusprivate.h"
30 #include "gdbusconnection.h"
31
32 #include "glibintl.h"
33
34 /**
35  * SECTION:gdbusnamewatching
36  * @title: Watching Bus Names
37  * @short_description: Simple API for watching bus names
38  * @include: gio/gio.h
39  *
40  * Convenience API for watching bus names.
41  *
42  * A simple example for watching a name can be found in
43  * [gdbus-example-watch-name.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-watch-name.c)
44  */
45
46 G_LOCK_DEFINE_STATIC (lock);
47
48 /* ---------------------------------------------------------------------------------------------------- */
49
50 typedef enum
51 {
52   PREVIOUS_CALL_NONE = 0,
53   PREVIOUS_CALL_APPEARED,
54   PREVIOUS_CALL_VANISHED,
55 } PreviousCall;
56
57 typedef struct
58 {
59   gint                      ref_count;  /* (atomic) */
60   guint                     id;
61   gchar                    *name;
62   GBusNameWatcherFlags      flags;
63   gchar                    *name_owner;
64   GBusNameAppearedCallback  name_appeared_handler;
65   GBusNameVanishedCallback  name_vanished_handler;
66   gpointer                  user_data;
67   GDestroyNotify            user_data_free_func;
68   GMainContext             *main_context;
69
70   GDBusConnection          *connection;
71   gulong                    disconnected_signal_handler_id;
72   guint                     name_owner_changed_subscription_id;
73
74   PreviousCall              previous_call;
75
76   gboolean                  cancelled;
77   gboolean                  initialized;
78 } Client;
79
80 /* Must be accessed atomically. */
81 static guint next_global_id = 1;  /* (atomic) */
82
83 /* Must be accessed with @lock held. */
84 static GHashTable *map_id_to_client = NULL;
85
86 static Client *
87 client_ref (Client *client)
88 {
89   g_atomic_int_inc (&client->ref_count);
90   return client;
91 }
92
93 static gboolean
94 free_user_data_cb (gpointer user_data)
95 {
96   /* The user data is actually freed by the GDestroyNotify for the idle source */
97   return G_SOURCE_REMOVE;
98 }
99
100 static void
101 client_unref (Client *client)
102 {
103   if (g_atomic_int_dec_and_test (&client->ref_count))
104     {
105       if (client->connection != NULL)
106         {
107           if (client->name_owner_changed_subscription_id > 0)
108             g_dbus_connection_signal_unsubscribe (client->connection, client->name_owner_changed_subscription_id);
109           if (client->disconnected_signal_handler_id > 0)
110             g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
111           g_object_unref (client->connection);
112         }
113       g_free (client->name);
114       g_free (client->name_owner);
115
116       if (client->user_data_free_func != NULL)
117         {
118           /* Ensure client->user_data_free_func() is called from the right thread */
119           if (client->main_context != g_main_context_get_thread_default ())
120             {
121               GSource *idle_source = g_idle_source_new ();
122               g_source_set_callback (idle_source, free_user_data_cb,
123                                      client->user_data,
124                                      client->user_data_free_func);
125               g_source_set_name (idle_source, "[gio, gdbusnamewatching.c] free_user_data_cb");
126               g_source_attach (idle_source, client->main_context);
127               g_source_unref (idle_source);
128             }
129           else
130             client->user_data_free_func (client->user_data);
131         }
132
133       g_main_context_unref (client->main_context);
134
135       g_free (client);
136     }
137 }
138
139 /* ---------------------------------------------------------------------------------------------------- */
140
141 typedef enum
142 {
143   CALL_TYPE_NAME_APPEARED,
144   CALL_TYPE_NAME_VANISHED
145 } CallType;
146
147 typedef struct
148 {
149   Client *client;
150
151   /* keep this separate because client->connection may
152    * be set to NULL after scheduling the call
153    */
154   GDBusConnection *connection;
155
156   /* ditto */
157   gchar *name_owner;
158
159   CallType call_type;
160 } CallHandlerData;
161
162 static void
163 call_handler_data_free (CallHandlerData *data)
164 {
165   if (data->connection != NULL)
166     g_object_unref (data->connection);
167   g_free (data->name_owner);
168   client_unref (data->client);
169   g_free (data);
170 }
171
172 static void
173 actually_do_call (Client *client, GDBusConnection *connection, const gchar *name_owner, CallType call_type)
174 {
175   /* The client might have been cancelled (g_bus_unwatch_name()) while we were
176    * sitting in the #GMainContext dispatch queue. */
177   if (client->cancelled)
178     return;
179
180   switch (call_type)
181     {
182     case CALL_TYPE_NAME_APPEARED:
183       if (client->name_appeared_handler != NULL)
184         {
185           client->name_appeared_handler (connection,
186                                          client->name,
187                                          name_owner,
188                                          client->user_data);
189         }
190       break;
191
192     case CALL_TYPE_NAME_VANISHED:
193       if (client->name_vanished_handler != NULL)
194         {
195           client->name_vanished_handler (connection,
196                                          client->name,
197                                          client->user_data);
198         }
199       break;
200
201     default:
202       g_assert_not_reached ();
203       break;
204     }
205 }
206
207 static gboolean
208 call_in_idle_cb (gpointer _data)
209 {
210   CallHandlerData *data = _data;
211   actually_do_call (data->client, data->connection, data->name_owner, data->call_type);
212   return FALSE;
213 }
214
215 static void
216 schedule_call_in_idle (Client *client, CallType call_type)
217 {
218   CallHandlerData *data;
219   GSource *idle_source;
220
221   data = g_new0 (CallHandlerData, 1);
222   data->client = client_ref (client);
223   data->connection = client->connection != NULL ? g_object_ref (client->connection) : NULL;
224   data->name_owner = g_strdup (client->name_owner);
225   data->call_type = call_type;
226
227   idle_source = g_idle_source_new ();
228   g_source_set_priority (idle_source, G_PRIORITY_HIGH);
229   g_source_set_callback (idle_source,
230                          call_in_idle_cb,
231                          data,
232                          (GDestroyNotify) call_handler_data_free);
233   g_source_set_static_name (idle_source, "[gio, gdbusnamewatching.c] call_in_idle_cb");
234   g_source_attach (idle_source, client->main_context);
235   g_source_unref (idle_source);
236 }
237
238 static void
239 do_call (Client *client, CallType call_type)
240 {
241   GMainContext *current_context;
242
243   /* only schedule in idle if we're not in the right thread */
244   current_context = g_main_context_ref_thread_default ();
245   if (current_context != client->main_context)
246     schedule_call_in_idle (client, call_type);
247   else
248     actually_do_call (client, client->connection, client->name_owner, call_type);
249   g_main_context_unref (current_context);
250 }
251
252 static void
253 call_appeared_handler (Client *client)
254 {
255   if (client->previous_call != PREVIOUS_CALL_APPEARED)
256     {
257       client->previous_call = PREVIOUS_CALL_APPEARED;
258       if (!client->cancelled && client->name_appeared_handler != NULL)
259         {
260           do_call (client, CALL_TYPE_NAME_APPEARED);
261         }
262     }
263 }
264
265 static void
266 call_vanished_handler (Client *client)
267 {
268   if (client->previous_call != PREVIOUS_CALL_VANISHED)
269     {
270       client->previous_call = PREVIOUS_CALL_VANISHED;
271       if (!client->cancelled && client->name_vanished_handler != NULL)
272         {
273           do_call (client, CALL_TYPE_NAME_VANISHED);
274         }
275     }
276 }
277
278 /* ---------------------------------------------------------------------------------------------------- */
279
280 /* Return a reference to the #Client for @watcher_id, or %NULL if it’s been
281  * unwatched. This is safe to call from any thread. */
282 static Client *
283 dup_client (guint watcher_id)
284 {
285   Client *client;
286
287   G_LOCK (lock);
288
289   g_assert (watcher_id != 0);
290   g_assert (map_id_to_client != NULL);
291
292   client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id));
293
294   if (client != NULL)
295     client_ref (client);
296
297   G_UNLOCK (lock);
298
299   return client;
300 }
301
302 /* Could be called from any thread, so it could be called after client_unref()
303  * has started finalising the #Client. Avoid that by looking up the #Client
304  * atomically. */
305 static void
306 on_connection_disconnected (GDBusConnection *connection,
307                             gboolean         remote_peer_vanished,
308                             GError          *error,
309                             gpointer         user_data)
310 {
311   guint watcher_id = GPOINTER_TO_UINT (user_data);
312   Client *client = NULL;
313
314   client = dup_client (watcher_id);
315   if (client == NULL)
316     return;
317
318   if (client->name_owner_changed_subscription_id > 0)
319     g_dbus_connection_signal_unsubscribe (client->connection, client->name_owner_changed_subscription_id);
320   if (client->disconnected_signal_handler_id > 0)
321     g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
322   g_object_unref (client->connection);
323   client->disconnected_signal_handler_id = 0;
324   client->name_owner_changed_subscription_id = 0;
325   client->connection = NULL;
326
327   call_vanished_handler (client);
328
329   client_unref (client);
330 }
331
332 /* ---------------------------------------------------------------------------------------------------- */
333
334 /* Will always be called from the thread which acquired client->main_context. */
335 static void
336 on_name_owner_changed (GDBusConnection *connection,
337                        const gchar      *sender_name,
338                        const gchar      *object_path,
339                        const gchar      *interface_name,
340                        const gchar      *signal_name,
341                        GVariant         *parameters,
342                        gpointer          user_data)
343 {
344   guint watcher_id = GPOINTER_TO_UINT (user_data);
345   Client *client = NULL;
346   const gchar *name;
347   const gchar *old_owner;
348   const gchar *new_owner;
349
350   client = dup_client (watcher_id);
351   if (client == NULL)
352     return;
353
354   if (g_strcmp0 (object_path, "/org/freedesktop/DBus") != 0 ||
355       g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0 ||
356       g_strcmp0 (sender_name, "org.freedesktop.DBus") != 0)
357     goto out;
358
359   g_variant_get (parameters,
360                  "(&s&s&s)",
361                  &name,
362                  &old_owner,
363                  &new_owner);
364
365   /* we only care about a specific name */
366   if (g_strcmp0 (name, client->name) != 0)
367     goto out;
368
369   if (old_owner != NULL && strlen (old_owner) > 0)
370     {
371       g_free (client->name_owner);
372       client->name_owner = NULL;
373       call_vanished_handler (client);
374     }
375
376   if (new_owner != NULL && strlen (new_owner) > 0)
377     {
378       g_free (client->name_owner);
379       client->name_owner = g_strdup (new_owner);
380       call_appeared_handler (client);
381     }
382
383   /* initialized set to TRUE means that signal was delivered and processed.
384    * Now, if we receive a reply to GetNameOwner call, we may just ignore it as it carries the same
385    * information as the current signal, or if something changed in the meantime we will
386    * get next signal very soon.
387    */
388   client->initialized = TRUE;
389
390  out:
391   client_unref (client);
392 }
393
394 /* ---------------------------------------------------------------------------------------------------- */
395
396 static void
397 get_name_owner_cb (GObject      *source_object,
398                    GAsyncResult *res,
399                    gpointer      user_data)
400 {
401   Client *client = user_data;
402   GVariant *result;
403   const char *name_owner;
404
405   name_owner = NULL;
406   result = NULL;
407
408   result = g_dbus_connection_call_finish (client->connection,
409                                           res,
410                                           NULL);
411   /* In case we already received NameOwnerChanged signal, we don't need to
412    * process GetNameOwner answer, because all the information we needed was already
413    * delivered with the signal and processed by the signal handler.
414    */
415   if (client->initialized)
416     goto out;
417
418   if (result != NULL)
419     {
420       g_variant_get (result, "(&s)", &name_owner);
421     }
422
423   if (name_owner != NULL)
424     {
425       g_warn_if_fail (client->name_owner == NULL);
426       client->name_owner = g_strdup (name_owner);
427       call_appeared_handler (client);
428     }
429   else
430     {
431       call_vanished_handler (client);
432     }
433
434  out:
435   if (result != NULL)
436     g_variant_unref (result);
437
438   client_unref (client);
439 }
440
441 /* ---------------------------------------------------------------------------------------------------- */
442
443 static void
444 invoke_get_name_owner (Client *client)
445 {
446   g_dbus_connection_call (client->connection,
447                           "org.freedesktop.DBus",  /* bus name */
448                           "/org/freedesktop/DBus", /* object path */
449                           "org.freedesktop.DBus",  /* interface name */
450                           "GetNameOwner",          /* method name */
451                           g_variant_new ("(s)", client->name),
452                           G_VARIANT_TYPE ("(s)"),
453                           G_DBUS_CALL_FLAGS_NONE,
454                           -1,
455                           NULL,
456                           (GAsyncReadyCallback) get_name_owner_cb,
457                           client_ref (client));
458 }
459
460 /* ---------------------------------------------------------------------------------------------------- */
461
462 static void
463 start_service_by_name_cb (GObject      *source_object,
464                           GAsyncResult *res,
465                           gpointer      user_data)
466 {
467   Client *client = user_data;
468   GVariant *result;
469
470   result = NULL;
471
472   result = g_dbus_connection_call_finish (client->connection,
473                                           res,
474                                           NULL);
475   if (result != NULL)
476     {
477       guint32 start_service_result;
478       g_variant_get (result, "(u)", &start_service_result);
479
480       if (start_service_result == 1) /* DBUS_START_REPLY_SUCCESS */
481         {
482           invoke_get_name_owner (client);
483         }
484       else if (start_service_result == 2) /* DBUS_START_REPLY_ALREADY_RUNNING */
485         {
486           invoke_get_name_owner (client);
487         }
488       else
489         {
490           g_warning ("Unexpected reply %d from StartServiceByName() method", start_service_result);
491           call_vanished_handler (client);
492           client->initialized = TRUE;
493         }
494     }
495   else
496     {
497       /* Errors are not unexpected; the bus will reply e.g.
498        *
499        *   org.freedesktop.DBus.Error.ServiceUnknown: The name org.gnome.Epiphany2
500        *   was not provided by any .service files
501        *
502        * This doesn't mean that the name doesn't have an owner, just
503        * that it's not provided by a .service file. So proceed to
504        * invoke GetNameOwner().
505        */
506       invoke_get_name_owner (client);
507     }
508
509   if (result != NULL)
510     g_variant_unref (result);
511   client_unref (client);
512 }
513
514 /* ---------------------------------------------------------------------------------------------------- */
515
516 static void
517 has_connection (Client *client)
518 {
519   /* listen for disconnection */
520   client->disconnected_signal_handler_id = g_signal_connect (client->connection,
521                                                              "closed",
522                                                              G_CALLBACK (on_connection_disconnected),
523                                                              GUINT_TO_POINTER (client->id));
524
525   /* start listening to NameOwnerChanged messages immediately */
526   client->name_owner_changed_subscription_id = g_dbus_connection_signal_subscribe (client->connection,
527                                                                                    "org.freedesktop.DBus",  /* name */
528                                                                                    "org.freedesktop.DBus",  /* if */
529                                                                                    "NameOwnerChanged",      /* signal */
530                                                                                    "/org/freedesktop/DBus", /* path */
531                                                                                    client->name,
532                                                                                    G_DBUS_SIGNAL_FLAGS_NONE,
533                                                                                    on_name_owner_changed,
534                                                                                    GUINT_TO_POINTER (client->id),
535                                                                                    NULL);
536
537   if (client->flags & G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
538     {
539       g_dbus_connection_call (client->connection,
540                               "org.freedesktop.DBus",  /* bus name */
541                               "/org/freedesktop/DBus", /* object path */
542                               "org.freedesktop.DBus",  /* interface name */
543                               "StartServiceByName",    /* method name */
544                               g_variant_new ("(su)", client->name, 0),
545                               G_VARIANT_TYPE ("(u)"),
546                               G_DBUS_CALL_FLAGS_NONE,
547                               -1,
548                               NULL,
549                               (GAsyncReadyCallback) start_service_by_name_cb,
550                               client_ref (client));
551     }
552   else
553     {
554       /* check owner */
555       invoke_get_name_owner (client);
556     }
557 }
558
559
560 static void
561 connection_get_cb (GObject      *source_object,
562                    GAsyncResult *res,
563                    gpointer      user_data)
564 {
565   Client *client = user_data;
566
567   client->connection = g_bus_get_finish (res, NULL);
568   if (client->connection == NULL)
569     {
570       call_vanished_handler (client);
571       goto out;
572     }
573
574   has_connection (client);
575
576  out:
577   client_unref (client);
578 }
579
580 /* ---------------------------------------------------------------------------------------------------- */
581
582 /**
583  * g_bus_watch_name:
584  * @bus_type: The type of bus to watch a name on.
585  * @name: The name (well-known or unique) to watch.
586  * @flags: Flags from the #GBusNameWatcherFlags enumeration.
587  * @name_appeared_handler: (nullable): Handler to invoke when @name is known to exist or %NULL.
588  * @name_vanished_handler: (nullable): Handler to invoke when @name is known to not exist or %NULL.
589  * @user_data: User data to pass to handlers.
590  * @user_data_free_func: (nullable): Function for freeing @user_data or %NULL.
591  *
592  * Starts watching @name on the bus specified by @bus_type and calls
593  * @name_appeared_handler and @name_vanished_handler when the name is
594  * known to have an owner respectively known to lose its
595  * owner. Callbacks will be invoked in the
596  * [thread-default main context][g-main-context-push-thread-default]
597  * of the thread you are calling this function from.
598  *
599  * You are guaranteed that one of the handlers will be invoked after
600  * calling this function. When you are done watching the name, just
601  * call g_bus_unwatch_name() with the watcher id this function
602  * returns.
603  *
604  * If the name vanishes or appears (for example the application owning
605  * the name could restart), the handlers are also invoked. If the
606  * #GDBusConnection that is used for watching the name disconnects, then
607  * @name_vanished_handler is invoked since it is no longer
608  * possible to access the name.
609  *
610  * Another guarantee is that invocations of @name_appeared_handler
611  * and @name_vanished_handler are guaranteed to alternate; that
612  * is, if @name_appeared_handler is invoked then you are
613  * guaranteed that the next time one of the handlers is invoked, it
614  * will be @name_vanished_handler. The reverse is also true.
615  *
616  * This behavior makes it very simple to write applications that want
617  * to take action when a certain [name exists][gdbus-watching-names].
618  * Basically, the application should create object proxies in
619  * @name_appeared_handler and destroy them again (if any) in
620  * @name_vanished_handler.
621  *
622  * Returns: An identifier (never 0) that can be used with
623  * g_bus_unwatch_name() to stop watching the name.
624  *
625  * Since: 2.26
626  */
627 guint
628 g_bus_watch_name (GBusType                  bus_type,
629                   const gchar              *name,
630                   GBusNameWatcherFlags      flags,
631                   GBusNameAppearedCallback  name_appeared_handler,
632                   GBusNameVanishedCallback  name_vanished_handler,
633                   gpointer                  user_data,
634                   GDestroyNotify            user_data_free_func)
635 {
636   Client *client;
637
638   g_return_val_if_fail (g_dbus_is_name (name), 0);
639
640   G_LOCK (lock);
641
642   client = g_new0 (Client, 1);
643   client->ref_count = 1;
644   client->id = (guint) g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */
645   client->name = g_strdup (name);
646   client->flags = flags;
647   client->name_appeared_handler = name_appeared_handler;
648   client->name_vanished_handler = name_vanished_handler;
649   client->user_data = user_data;
650   client->user_data_free_func = user_data_free_func;
651   client->main_context = g_main_context_ref_thread_default ();
652
653   if (map_id_to_client == NULL)
654     {
655       map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
656     }
657   g_hash_table_insert (map_id_to_client,
658                        GUINT_TO_POINTER (client->id),
659                        client);
660
661   g_bus_get (bus_type,
662              NULL,
663              connection_get_cb,
664              client_ref (client));
665
666   G_UNLOCK (lock);
667
668   return client->id;
669 }
670
671 /**
672  * g_bus_watch_name_on_connection:
673  * @connection: A #GDBusConnection.
674  * @name: The name (well-known or unique) to watch.
675  * @flags: Flags from the #GBusNameWatcherFlags enumeration.
676  * @name_appeared_handler: (nullable): Handler to invoke when @name is known to exist or %NULL.
677  * @name_vanished_handler: (nullable): Handler to invoke when @name is known to not exist or %NULL.
678  * @user_data: User data to pass to handlers.
679  * @user_data_free_func: (nullable): Function for freeing @user_data or %NULL.
680  *
681  * Like g_bus_watch_name() but takes a #GDBusConnection instead of a
682  * #GBusType.
683  *
684  * Returns: An identifier (never 0) that can be used with
685  * g_bus_unwatch_name() to stop watching the name.
686  *
687  * Since: 2.26
688  */
689 guint g_bus_watch_name_on_connection (GDBusConnection          *connection,
690                                       const gchar              *name,
691                                       GBusNameWatcherFlags      flags,
692                                       GBusNameAppearedCallback  name_appeared_handler,
693                                       GBusNameVanishedCallback  name_vanished_handler,
694                                       gpointer                  user_data,
695                                       GDestroyNotify            user_data_free_func)
696 {
697   Client *client;
698
699   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
700   g_return_val_if_fail (g_dbus_is_name (name), 0);
701
702   G_LOCK (lock);
703
704   client = g_new0 (Client, 1);
705   client->ref_count = 1;
706   client->id = (guint) g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */
707   client->name = g_strdup (name);
708   client->flags = flags;
709   client->name_appeared_handler = name_appeared_handler;
710   client->name_vanished_handler = name_vanished_handler;
711   client->user_data = user_data;
712   client->user_data_free_func = user_data_free_func;
713   client->main_context = g_main_context_ref_thread_default ();
714
715   if (map_id_to_client == NULL)
716     map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
717
718   g_hash_table_insert (map_id_to_client,
719                        GUINT_TO_POINTER (client->id),
720                        client);
721
722   client->connection = g_object_ref (connection);
723   G_UNLOCK (lock);
724
725   has_connection (client);
726
727   return client->id;
728 }
729
730 typedef struct {
731   GClosure *name_appeared_closure;
732   GClosure *name_vanished_closure;
733 } WatchNameData;
734
735 static WatchNameData *
736 watch_name_data_new (GClosure *name_appeared_closure,
737                      GClosure *name_vanished_closure)
738 {
739   WatchNameData *data;
740
741   data = g_new0 (WatchNameData, 1);
742
743   if (name_appeared_closure != NULL)
744     {
745       data->name_appeared_closure = g_closure_ref (name_appeared_closure);
746       g_closure_sink (name_appeared_closure);
747       if (G_CLOSURE_NEEDS_MARSHAL (name_appeared_closure))
748         g_closure_set_marshal (name_appeared_closure, g_cclosure_marshal_generic);
749     }
750
751   if (name_vanished_closure != NULL)
752     {
753       data->name_vanished_closure = g_closure_ref (name_vanished_closure);
754       g_closure_sink (name_vanished_closure);
755       if (G_CLOSURE_NEEDS_MARSHAL (name_vanished_closure))
756         g_closure_set_marshal (name_vanished_closure, g_cclosure_marshal_generic);
757     }
758
759   return data;
760 }
761
762 static void
763 watch_with_closures_on_name_appeared (GDBusConnection *connection,
764                                       const gchar     *name,
765                                       const gchar     *name_owner,
766                                       gpointer         user_data)
767 {
768   WatchNameData *data = user_data;
769   GValue params[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
770
771   g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
772   g_value_set_object (&params[0], connection);
773
774   g_value_init (&params[1], G_TYPE_STRING);
775   g_value_set_string (&params[1], name);
776
777   g_value_init (&params[2], G_TYPE_STRING);
778   g_value_set_string (&params[2], name_owner);
779
780   g_closure_invoke (data->name_appeared_closure, NULL, 3, params, NULL);
781
782   g_value_unset (params + 0);
783   g_value_unset (params + 1);
784   g_value_unset (params + 2);
785 }
786
787 static void
788 watch_with_closures_on_name_vanished (GDBusConnection *connection,
789                                       const gchar     *name,
790                                       gpointer         user_data)
791 {
792   WatchNameData *data = user_data;
793   GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
794
795   g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
796   g_value_set_object (&params[0], connection);
797
798   g_value_init (&params[1], G_TYPE_STRING);
799   g_value_set_string (&params[1], name);
800
801   g_closure_invoke (data->name_vanished_closure, NULL, 2, params, NULL);
802
803   g_value_unset (params + 0);
804   g_value_unset (params + 1);
805 }
806
807 static void
808 bus_watch_name_free_func (gpointer user_data)
809 {
810   WatchNameData *data = user_data;
811
812   if (data->name_appeared_closure != NULL)
813     g_closure_unref (data->name_appeared_closure);
814
815   if (data->name_vanished_closure != NULL)
816     g_closure_unref (data->name_vanished_closure);
817
818   g_free (data);
819 }
820
821 /**
822  * g_bus_watch_name_with_closures: (rename-to g_bus_watch_name)
823  * @bus_type: The type of bus to watch a name on.
824  * @name: The name (well-known or unique) to watch.
825  * @flags: Flags from the #GBusNameWatcherFlags enumeration.
826  * @name_appeared_closure: (nullable): #GClosure to invoke when @name is known
827  * to exist or %NULL.
828  * @name_vanished_closure: (nullable): #GClosure to invoke when @name is known
829  * to not exist or %NULL.
830  *
831  * Version of g_bus_watch_name() using closures instead of callbacks for
832  * easier binding in other languages.
833  *
834  * Returns: An identifier (never 0) that can be used with
835  * g_bus_unwatch_name() to stop watching the name.
836  *
837  * Since: 2.26
838  */
839 guint
840 g_bus_watch_name_with_closures (GBusType                 bus_type,
841                                 const gchar             *name,
842                                 GBusNameWatcherFlags     flags,
843                                 GClosure                *name_appeared_closure,
844                                 GClosure                *name_vanished_closure)
845 {
846   return g_bus_watch_name (bus_type,
847           name,
848           flags,
849           name_appeared_closure != NULL ? watch_with_closures_on_name_appeared : NULL,
850           name_vanished_closure != NULL ? watch_with_closures_on_name_vanished : NULL,
851           watch_name_data_new (name_appeared_closure, name_vanished_closure),
852           bus_watch_name_free_func);
853 }
854
855 /**
856  * g_bus_watch_name_on_connection_with_closures: (rename-to g_bus_watch_name_on_connection)
857  * @connection: A #GDBusConnection.
858  * @name: The name (well-known or unique) to watch.
859  * @flags: Flags from the #GBusNameWatcherFlags enumeration.
860  * @name_appeared_closure: (nullable): #GClosure to invoke when @name is known
861  * to exist or %NULL.
862  * @name_vanished_closure: (nullable): #GClosure to invoke when @name is known
863  * to not exist or %NULL.
864  *
865  * Version of g_bus_watch_name_on_connection() using closures instead of callbacks for
866  * easier binding in other languages.
867  *
868  * Returns: An identifier (never 0) that can be used with
869  * g_bus_unwatch_name() to stop watching the name.
870  *
871  * Since: 2.26
872  */
873 guint g_bus_watch_name_on_connection_with_closures (
874                                       GDBusConnection          *connection,
875                                       const gchar              *name,
876                                       GBusNameWatcherFlags      flags,
877                                       GClosure                 *name_appeared_closure,
878                                       GClosure                 *name_vanished_closure)
879 {
880   return g_bus_watch_name_on_connection (connection,
881           name,
882           flags,
883           name_appeared_closure != NULL ? watch_with_closures_on_name_appeared : NULL,
884           name_vanished_closure != NULL ? watch_with_closures_on_name_vanished : NULL,
885           watch_name_data_new (name_appeared_closure, name_vanished_closure),
886           bus_watch_name_free_func);
887 }
888
889 /**
890  * g_bus_unwatch_name:
891  * @watcher_id: An identifier obtained from g_bus_watch_name()
892  *
893  * Stops watching a name.
894  *
895  * Note that there may still be D-Bus traffic to process (relating to watching
896  * and unwatching the name) in the current thread-default #GMainContext after
897  * this function has returned. You should continue to iterate the #GMainContext
898  * until the #GDestroyNotify function passed to g_bus_watch_name() is called, in
899  * order to avoid memory leaks through callbacks queued on the #GMainContext
900  * after it’s stopped being iterated.
901  *
902  * Since: 2.26
903  */
904 void
905 g_bus_unwatch_name (guint watcher_id)
906 {
907   Client *client;
908
909   g_return_if_fail (watcher_id > 0);
910
911   client = NULL;
912
913   G_LOCK (lock);
914   if (watcher_id == 0 ||
915       map_id_to_client == NULL ||
916       (client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (watcher_id))) == NULL)
917     {
918       g_warning ("Invalid id %d passed to g_bus_unwatch_name()", watcher_id);
919       goto out;
920     }
921
922   client->cancelled = TRUE;
923   g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (watcher_id)));
924
925  out:
926   G_UNLOCK (lock);
927
928   /* do callback without holding lock */
929   if (client != NULL)
930     {
931       client_unref (client);
932     }
933 }