1  /* GObject - GLib Type, Object, Parameter and Signal Library
       2   *
       3   * Copyright (C) 2015-2022 Christian Hergert <christian@hergert.me>
       4   * Copyright (C) 2015 Garrett Regier <garrettregier@gmail.com>
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General
      17   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * SPDX-License-Identifier: LGPL-2.1-or-later
      20   */
      21  
      22  #include "config.h"
      23  #include "glib.h"
      24  #include "glibintl.h"
      25  
      26  #include "gparamspecs.h"
      27  #include "gsignalgroup.h"
      28  #include "gvaluetypes.h"
      29  
      30  /**
      31   * GSignalGroup:
      32   *
      33   * `GSignalGroup` manages a collection of signals on a `GObject`.
      34   *
      35   * `GSignalGroup` simplifies the process of connecting  many signals to a `GObject`
      36   * as a group. As such there is no API to disconnect a signal from the group.
      37   *
      38   * In particular, this allows you to:
      39   *
      40   *  - Change the target instance, which automatically causes disconnection
      41   *    of the signals from the old instance and connecting to the new instance.
      42   *  - Block and unblock signals as a group
      43   *  - Ensuring that blocked state transfers across target instances.
      44   *
      45   * One place you might want to use such a structure is with `GtkTextView` and
      46   * `GtkTextBuffer`. Often times, you'll need to connect to many signals on
      47   * `GtkTextBuffer` from a `GtkTextView` subclass. This allows you to create a
      48   * signal group during instance construction, simply bind the
      49   * `GtkTextView:buffer` property to `GSignalGroup:target` and connect
      50   * all the signals you need. When the `GtkTextView:buffer` property changes
      51   * all of the signals will be transitioned correctly.
      52   *
      53   * Since: 2.72
      54   */
      55  
      56  struct _GSignalGroup
      57  {
      58    GObject     parent_instance;
      59  
      60    GWeakRef    target_ref;
      61    GRecMutex   mutex;
      62    GPtrArray  *handlers;
      63    GType       target_type;
      64    gssize      block_count;
      65  
      66    guint       has_bound_at_least_once : 1;
      67  };
      68  
      69  typedef struct _GSignalGroupClass
      70  {
      71    GObjectClass parent_class;
      72  
      73    void (*bind) (GSignalGroup *self,
      74                  GObject      *target);
      75  } GSignalGroupClass;
      76  
      77  typedef struct
      78  {
      79    GSignalGroup *group;
      80    gulong             handler_id;
      81    GClosure          *closure;
      82    guint              signal_id;
      83    GQuark             signal_detail;
      84    guint              connect_after : 1;
      85  } SignalHandler;
      86  
      87  G_DEFINE_TYPE (GSignalGroup, g_signal_group, G_TYPE_OBJECT)
      88  
      89  typedef enum
      90  {
      91    PROP_TARGET = 1,
      92    PROP_TARGET_TYPE,
      93    LAST_PROP
      94  } GSignalGroupProperty;
      95  
      96  enum
      97  {
      98    BIND,
      99    UNBIND,
     100    LAST_SIGNAL
     101  };
     102  
     103  static GParamSpec *properties[LAST_PROP];
     104  static guint signals[LAST_SIGNAL];
     105  
     106  static void
     107  g_signal_group_set_target_type (GSignalGroup *self,
     108                                  GType         target_type)
     109  {
     110    g_assert (G_IS_SIGNAL_GROUP (self));
     111    g_assert (g_type_is_a (target_type, G_TYPE_OBJECT));
     112  
     113    self->target_type = target_type;
     114  
     115    /* The class must be created at least once for the signals
     116     * to be registered, otherwise g_signal_parse_name() will fail
     117     */
     118    if (G_TYPE_IS_INTERFACE (target_type))
     119      {
     120        if (g_type_default_interface_peek (target_type) == NULL)
     121          g_type_default_interface_unref (g_type_default_interface_ref (target_type));
     122      }
     123    else
     124      {
     125        if (g_type_class_peek (target_type) == NULL)
     126          g_type_class_unref (g_type_class_ref (target_type));
     127      }
     128  }
     129  
     130  static void
     131  g_signal_group_gc_handlers (GSignalGroup *self)
     132  {
     133    guint i;
     134  
     135    g_assert (G_IS_SIGNAL_GROUP (self));
     136  
     137    /*
     138     * Remove any handlers for which the closures have become invalid. We do
     139     * this cleanup lazily to avoid situations where we could have disposal
     140     * active on both the signal group and the peer object.
     141     */
     142  
     143    for (i = self->handlers->len; i > 0; i--)
     144      {
     145        const SignalHandler *handler = g_ptr_array_index (self->handlers, i - 1);
     146  
     147        g_assert (handler != NULL);
     148        g_assert (handler->closure != NULL);
     149  
     150        if (handler->closure->is_invalid)
     151          g_ptr_array_remove_index (self->handlers, i - 1);
     152      }
     153  }
     154  
     155  static void
     156  g_signal_group__target_weak_notify (gpointer  data,
     157                                      GObject  *where_object_was)
     158  {
     159    GSignalGroup *self = data;
     160    guint i;
     161  
     162    g_assert (G_IS_SIGNAL_GROUP (self));
     163    g_assert (where_object_was != NULL);
     164  
     165    g_rec_mutex_lock (&self->mutex);
     166  
     167    g_weak_ref_set (&self->target_ref, NULL);
     168  
     169    for (i = 0; i < self->handlers->len; i++)
     170      {
     171        SignalHandler *handler = g_ptr_array_index (self->handlers, i);
     172  
     173        handler->handler_id = 0;
     174      }
     175  
     176    g_signal_emit (self, signals[UNBIND], 0);
     177    g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TARGET]);
     178  
     179    g_rec_mutex_unlock (&self->mutex);
     180  }
     181  
     182  static void
     183  g_signal_group_bind_handler (GSignalGroup  *self,
     184                               SignalHandler *handler,
     185                               GObject       *target)
     186  {
     187    gssize i;
     188  
     189    g_assert (self != NULL);
     190    g_assert (G_IS_OBJECT (target));
     191    g_assert (handler != NULL);
     192    g_assert (handler->signal_id != 0);
     193    g_assert (handler->closure != NULL);
     194    g_assert (handler->closure->is_invalid == 0);
     195    g_assert (handler->handler_id == 0);
     196  
     197    handler->handler_id = g_signal_connect_closure_by_id (target,
     198                                                          handler->signal_id,
     199                                                          handler->signal_detail,
     200                                                          handler->closure,
     201                                                          handler->connect_after);
     202  
     203    g_assert (handler->handler_id != 0);
     204  
     205    for (i = 0; i < self->block_count; i++)
     206      g_signal_handler_block (target, handler->handler_id);
     207  }
     208  
     209  static void
     210  g_signal_group_bind (GSignalGroup *self,
     211                       GObject      *target)
     212  {
     213    GObject *hold;
     214    guint i;
     215  
     216    g_assert (G_IS_SIGNAL_GROUP (self));
     217    g_assert (!target || G_IS_OBJECT (target));
     218  
     219    if (target == NULL)
     220      return;
     221  
     222    self->has_bound_at_least_once = TRUE;
     223  
     224    hold = g_object_ref (target);
     225  
     226    g_weak_ref_set (&self->target_ref, hold);
     227    g_object_weak_ref (hold, g_signal_group__target_weak_notify, self);
     228  
     229    g_signal_group_gc_handlers (self);
     230  
     231    for (i = 0; i < self->handlers->len; i++)
     232      {
     233        SignalHandler *handler = g_ptr_array_index (self->handlers, i);
     234  
     235        g_signal_group_bind_handler (self, handler, hold);
     236      }
     237  
     238    g_signal_emit (self, signals [BIND], 0, hold);
     239  
     240    g_object_unref (hold);
     241  }
     242  
     243  static void
     244  g_signal_group_unbind (GSignalGroup *self)
     245  {
     246    GObject *target;
     247    guint i;
     248  
     249    g_return_if_fail (G_IS_SIGNAL_GROUP (self));
     250  
     251    target = g_weak_ref_get (&self->target_ref);
     252  
     253    /*
     254     * Target may be NULL by this point, as we got notified of its destruction.
     255     * However, if we're early enough, we may get a full reference back and can
     256     * cleanly disconnect our connections.
     257     */
     258  
     259    if (target != NULL)
     260      {
     261        g_weak_ref_set (&self->target_ref, NULL);
     262  
     263        /*
     264         * Let go of our weak reference now that we have a full reference
     265         * for the life of this function.
     266         */
     267        g_object_weak_unref (target,
     268                             g_signal_group__target_weak_notify,
     269                             self);
     270      }
     271  
     272    g_signal_group_gc_handlers (self);
     273  
     274    for (i = 0; i < self->handlers->len; i++)
     275      {
     276        SignalHandler *handler;
     277        gulong handler_id;
     278  
     279        handler = g_ptr_array_index (self->handlers, i);
     280  
     281        g_assert (handler != NULL);
     282        g_assert (handler->signal_id != 0);
     283        g_assert (handler->closure != NULL);
     284  
     285        handler_id = handler->handler_id;
     286        handler->handler_id = 0;
     287  
     288        /*
     289         * If @target is NULL, we lost a race to cleanup the weak
     290         * instance and the signal connections have already been
     291         * finalized and therefore nothing to do.
     292         */
     293  
     294        if (target != NULL && handler_id != 0)
     295          g_signal_handler_disconnect (target, handler_id);
     296      }
     297  
     298    g_signal_emit (self, signals [UNBIND], 0);
     299  
     300    g_clear_object (&target);
     301  }
     302  
     303  static gboolean
     304  g_signal_group_check_target_type (GSignalGroup *self,
     305                                    gpointer      target)
     306  {
     307    if ((target != NULL) &&
     308        !g_type_is_a (G_OBJECT_TYPE (target), self->target_type))
     309      {
     310        g_critical ("Failed to set GSignalGroup of target type %s "
     311                    "using target %p of type %s",
     312                    g_type_name (self->target_type),
     313                    target, G_OBJECT_TYPE_NAME (target));
     314        return FALSE;
     315      }
     316  
     317    return TRUE;
     318  }
     319  
     320  /**
     321   * g_signal_group_block:
     322   * @self: the #GSignalGroup
     323   *
     324   * Blocks all signal handlers managed by @self so they will not
     325   * be called during any signal emissions. Must be unblocked exactly
     326   * the same number of times it has been blocked to become active again.
     327   *
     328   * This blocked state will be kept across changes of the target instance.
     329   *
     330   * Since: 2.72
     331   */
     332  void
     333  g_signal_group_block (GSignalGroup *self)
     334  {
     335    GObject *target;
     336    guint i;
     337  
     338    g_return_if_fail (G_IS_SIGNAL_GROUP (self));
     339    g_return_if_fail (self->block_count >= 0);
     340  
     341    g_rec_mutex_lock (&self->mutex);
     342  
     343    self->block_count++;
     344  
     345    target = g_weak_ref_get (&self->target_ref);
     346  
     347    if (target == NULL)
     348      goto unlock;
     349  
     350    for (i = 0; i < self->handlers->len; i++)
     351      {
     352        const SignalHandler *handler = g_ptr_array_index (self->handlers, i);
     353  
     354        g_assert (handler != NULL);
     355        g_assert (handler->signal_id != 0);
     356        g_assert (handler->closure != NULL);
     357        g_assert (handler->handler_id != 0);
     358  
     359        g_signal_handler_block (target, handler->handler_id);
     360      }
     361  
     362    g_object_unref (target);
     363  
     364  unlock:
     365    g_rec_mutex_unlock (&self->mutex);
     366  }
     367  
     368  /**
     369   * g_signal_group_unblock:
     370   * @self: the #GSignalGroup
     371   *
     372   * Unblocks all signal handlers managed by @self so they will be
     373   * called again during any signal emissions unless it is blocked
     374   * again. Must be unblocked exactly the same number of times it
     375   * has been blocked to become active again.
     376   *
     377   * Since: 2.72
     378   */
     379  void
     380  g_signal_group_unblock (GSignalGroup *self)
     381  {
     382    GObject *target;
     383    guint i;
     384  
     385    g_return_if_fail (G_IS_SIGNAL_GROUP (self));
     386    g_return_if_fail (self->block_count > 0);
     387  
     388    g_rec_mutex_lock (&self->mutex);
     389  
     390    self->block_count--;
     391  
     392    target = g_weak_ref_get (&self->target_ref);
     393    if (target == NULL)
     394      goto unlock;
     395  
     396    for (i = 0; i < self->handlers->len; i++)
     397      {
     398        const SignalHandler *handler = g_ptr_array_index (self->handlers, i);
     399  
     400        g_assert (handler != NULL);
     401        g_assert (handler->signal_id != 0);
     402        g_assert (handler->closure != NULL);
     403        g_assert (handler->handler_id != 0);
     404  
     405        g_signal_handler_unblock (target, handler->handler_id);
     406      }
     407  
     408    g_object_unref (target);
     409  
     410  unlock:
     411    g_rec_mutex_unlock (&self->mutex);
     412  }
     413  
     414  /**
     415   * g_signal_group_dup_target:
     416   * @self: the #GSignalGroup
     417   *
     418   * Gets the target instance used when connecting signals.
     419   *
     420   * Returns: (nullable) (transfer full) (type GObject): The target instance
     421   *
     422   * Since: 2.72
     423   */
     424  gpointer
     425  g_signal_group_dup_target (GSignalGroup *self)
     426  {
     427    GObject *target;
     428  
     429    g_return_val_if_fail (G_IS_SIGNAL_GROUP (self), NULL);
     430  
     431    g_rec_mutex_lock (&self->mutex);
     432    target = g_weak_ref_get (&self->target_ref);
     433    g_rec_mutex_unlock (&self->mutex);
     434  
     435    return target;
     436  }
     437  
     438  /**
     439   * g_signal_group_set_target:
     440   * @self: the #GSignalGroup.
     441   * @target: (nullable) (type GObject) (transfer none): The target instance used
     442   *     when connecting signals.
     443   *
     444   * Sets the target instance used when connecting signals. Any signal
     445   * that has been registered with g_signal_group_connect_object() or
     446   * similar functions will be connected to this object.
     447   *
     448   * If the target instance was previously set, signals will be
     449   * disconnected from that object prior to connecting to @target.
     450   *
     451   * Since: 2.72
     452   */
     453  void
     454  g_signal_group_set_target (GSignalGroup *self,
     455                             gpointer      target)
     456  {
     457    GObject *object;
     458  
     459    g_return_if_fail (G_IS_SIGNAL_GROUP (self));
     460  
     461    g_rec_mutex_lock (&self->mutex);
     462  
     463    object = g_weak_ref_get (&self->target_ref);
     464  
     465    if (object == (GObject *)target)
     466      goto cleanup;
     467  
     468    if (!g_signal_group_check_target_type (self, target))
     469      goto cleanup;
     470  
     471    /* Only emit unbind if we've ever called bind */
     472    if (self->has_bound_at_least_once)
     473      g_signal_group_unbind (self);
     474  
     475    g_signal_group_bind (self, target);
     476  
     477    g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TARGET]);
     478  
     479  cleanup:
     480    g_clear_object (&object);
     481    g_rec_mutex_unlock (&self->mutex);
     482  }
     483  
     484  static void
     485  signal_handler_free (gpointer data)
     486  {
     487    SignalHandler *handler = data;
     488  
     489    if (handler->closure != NULL)
     490      g_closure_invalidate (handler->closure);
     491  
     492    handler->handler_id = 0;
     493    handler->signal_id = 0;
     494    handler->signal_detail = 0;
     495    g_clear_pointer (&handler->closure, g_closure_unref);
     496    g_slice_free (SignalHandler, handler);
     497  }
     498  
     499  static void
     500  g_signal_group_constructed (GObject *object)
     501  {
     502    GSignalGroup *self = (GSignalGroup *)object;
     503    GObject *target;
     504  
     505    g_rec_mutex_lock (&self->mutex);
     506  
     507    target = g_weak_ref_get (&self->target_ref);
     508    if (!g_signal_group_check_target_type (self, target))
     509      g_signal_group_set_target (self, NULL);
     510  
     511    G_OBJECT_CLASS (g_signal_group_parent_class)->constructed (object);
     512  
     513    g_clear_object (&target);
     514  
     515    g_rec_mutex_unlock (&self->mutex);
     516  }
     517  
     518  static void
     519  g_signal_group_dispose (GObject *object)
     520  {
     521    GSignalGroup *self = (GSignalGroup *)object;
     522  
     523    g_rec_mutex_lock (&self->mutex);
     524  
     525    g_signal_group_gc_handlers (self);
     526  
     527    if (self->has_bound_at_least_once)
     528      g_signal_group_unbind (self);
     529  
     530    g_clear_pointer (&self->handlers, g_ptr_array_unref);
     531  
     532    g_rec_mutex_unlock (&self->mutex);
     533  
     534    G_OBJECT_CLASS (g_signal_group_parent_class)->dispose (object);
     535  }
     536  
     537  static void
     538  g_signal_group_finalize (GObject *object)
     539  {
     540    GSignalGroup *self = (GSignalGroup *)object;
     541  
     542    g_weak_ref_clear (&self->target_ref);
     543    g_rec_mutex_clear (&self->mutex);
     544  
     545    G_OBJECT_CLASS (g_signal_group_parent_class)->finalize (object);
     546  }
     547  
     548  static void
     549  g_signal_group_get_property (GObject    *object,
     550                               guint       prop_id,
     551                               GValue     *value,
     552                               GParamSpec *pspec)
     553  {
     554    GSignalGroup *self = G_SIGNAL_GROUP (object);
     555  
     556    switch ((GSignalGroupProperty) prop_id)
     557      {
     558      case PROP_TARGET:
     559        g_value_take_object (value, g_signal_group_dup_target (self));
     560        break;
     561  
     562      case PROP_TARGET_TYPE:
     563        g_value_set_gtype (value, self->target_type);
     564        break;
     565  
     566      default:
     567        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     568      }
     569  }
     570  
     571  static void
     572  g_signal_group_set_property (GObject      *object,
     573                               guint         prop_id,
     574                               const GValue *value,
     575                               GParamSpec   *pspec)
     576  {
     577    GSignalGroup *self = G_SIGNAL_GROUP (object);
     578  
     579    switch ((GSignalGroupProperty) prop_id)
     580      {
     581      case PROP_TARGET:
     582        g_signal_group_set_target (self, g_value_get_object (value));
     583        break;
     584  
     585      case PROP_TARGET_TYPE:
     586        g_signal_group_set_target_type (self, g_value_get_gtype (value));
     587        break;
     588  
     589      default:
     590        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     591      }
     592  }
     593  
     594  static void
     595  g_signal_group_class_init (GSignalGroupClass *klass)
     596  {
     597    GObjectClass *object_class = G_OBJECT_CLASS (klass);
     598  
     599    object_class->constructed = g_signal_group_constructed;
     600    object_class->dispose = g_signal_group_dispose;
     601    object_class->finalize = g_signal_group_finalize;
     602    object_class->get_property = g_signal_group_get_property;
     603    object_class->set_property = g_signal_group_set_property;
     604  
     605    /**
     606     * GSignalGroup:target
     607     *
     608     * The target instance used when connecting signals.
     609     *
     610     * Since: 2.72
     611     */
     612    properties[PROP_TARGET] =
     613        g_param_spec_object ("target", NULL, NULL,
     614                             G_TYPE_OBJECT,
     615                             (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
     616  
     617    /**
     618     * GSignalGroup:target-type
     619     *
     620     * The #GType of the target property.
     621     *
     622     * Since: 2.72
     623     */
     624    properties[PROP_TARGET_TYPE] =
     625        g_param_spec_gtype ("target-type", NULL, NULL,
     626                            G_TYPE_OBJECT,
     627                            (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
     628  
     629    g_object_class_install_properties (object_class, LAST_PROP, properties);
     630  
     631    /**
     632     * GSignalGroup::bind:
     633     * @self: the #GSignalGroup
     634     * @instance: a #GObject containing the new value for #GSignalGroup:target
     635     *
     636     * This signal is emitted when #GSignalGroup:target is set to a new value
     637     * other than %NULL. It is similar to #GObject::notify on `target` except it
     638     * will not emit when #GSignalGroup:target is %NULL and also allows for
     639     * receiving the #GObject without a data-race.
     640     *
     641     * Since: 2.72
     642     */
     643    signals[BIND] =
     644        g_signal_new ("bind",
     645                      G_TYPE_FROM_CLASS (klass),
     646                      G_SIGNAL_RUN_LAST,
     647                      0,
     648                      NULL, NULL, NULL,
     649                      G_TYPE_NONE,
     650                      1,
     651                      G_TYPE_OBJECT);
     652  
     653    /**
     654     * GSignalGroup::unbind:
     655     * @self: a #GSignalGroup
     656     *
     657     * This signal is emitted when the target instance of @self is set to a
     658     * new #GObject.
     659     *
     660     * This signal will only be emitted if the previous target of @self is
     661     * non-%NULL.
     662     *
     663     * Since: 2.72
     664     */
     665    signals[UNBIND] =
     666        g_signal_new ("unbind",
     667                      G_TYPE_FROM_CLASS (klass),
     668                      G_SIGNAL_RUN_LAST,
     669                      0,
     670                      NULL, NULL, NULL,
     671                      G_TYPE_NONE,
     672                      0);
     673  }
     674  
     675  static void
     676  g_signal_group_init (GSignalGroup *self)
     677  {
     678    g_rec_mutex_init (&self->mutex);
     679    self->handlers = g_ptr_array_new_with_free_func (signal_handler_free);
     680    self->target_type = G_TYPE_OBJECT;
     681  }
     682  
     683  /**
     684   * g_signal_group_new:
     685   * @target_type: the #GType of the target instance.
     686   *
     687   * Creates a new #GSignalGroup for target instances of @target_type.
     688   *
     689   * Returns: (transfer full): a new #GSignalGroup
     690   *
     691   * Since: 2.72
     692   */
     693  GSignalGroup *
     694  g_signal_group_new (GType target_type)
     695  {
     696    g_return_val_if_fail (g_type_is_a (target_type, G_TYPE_OBJECT), NULL);
     697  
     698    return g_object_new (G_TYPE_SIGNAL_GROUP,
     699                         "target-type", target_type,
     700                         NULL);
     701  }
     702  
     703  static gboolean
     704  g_signal_group_connect_closure_ (GSignalGroup   *self,
     705                                   const gchar    *detailed_signal,
     706                                   GClosure       *closure,
     707                                   gboolean        after)
     708  {
     709    GObject *target;
     710    SignalHandler *handler;
     711    guint signal_id;
     712    GQuark signal_detail;
     713  
     714    g_return_val_if_fail (G_IS_SIGNAL_GROUP (self), FALSE);
     715    g_return_val_if_fail (detailed_signal != NULL, FALSE);
     716    g_return_val_if_fail (closure != NULL, FALSE);
     717  
     718    if (!g_signal_parse_name (detailed_signal, self->target_type,
     719                              &signal_id, &signal_detail, TRUE))
     720      {
     721        g_critical ("Invalid signal name “%s”", detailed_signal);
     722        return FALSE;
     723      }
     724  
     725    g_rec_mutex_lock (&self->mutex);
     726  
     727    if (self->has_bound_at_least_once)
     728      {
     729        g_critical ("Cannot add signals after setting target");
     730        g_rec_mutex_unlock (&self->mutex);
     731        return FALSE;
     732      }
     733  
     734    handler = g_slice_new0 (SignalHandler);
     735    handler->group = self;
     736    handler->signal_id = signal_id;
     737    handler->signal_detail = signal_detail;
     738    handler->closure = g_closure_ref (closure);
     739    handler->connect_after = after;
     740  
     741    g_closure_sink (closure);
     742  
     743    g_ptr_array_add (self->handlers, handler);
     744  
     745    target = g_weak_ref_get (&self->target_ref);
     746  
     747    if (target != NULL)
     748      {
     749        g_signal_group_bind_handler (self, handler, target);
     750        g_object_unref (target);
     751      }
     752  
     753    /* Lazily remove any old handlers on connect */
     754    g_signal_group_gc_handlers (self);
     755  
     756    g_rec_mutex_unlock (&self->mutex);
     757    return TRUE;
     758  }
     759  
     760  /**
     761   * g_signal_group_connect_closure:
     762   * @self: a #GSignalGroup
     763   * @detailed_signal: a string of the form `signal-name` with optional `::signal-detail`
     764   * @closure: (not nullable): the closure to connect.
     765   * @after: whether the handler should be called before or after the
     766   *  default handler of the signal.
     767   *
     768   * Connects @closure to the signal @detailed_signal on #GSignalGroup:target.
     769   *
     770   * You cannot connect a signal handler after #GSignalGroup:target has been set.
     771   *
     772   * Since: 2.74
     773   */
     774  void
     775  g_signal_group_connect_closure (GSignalGroup   *self,
     776                                  const gchar    *detailed_signal,
     777                                  GClosure       *closure,
     778                                  gboolean        after)
     779  {
     780    g_signal_group_connect_closure_ (self, detailed_signal, closure, after);
     781  }
     782  
     783  static void
     784  g_signal_group_connect_full (GSignalGroup   *self,
     785                               const gchar    *detailed_signal,
     786                               GCallback       c_handler,
     787                               gpointer        data,
     788                               GClosureNotify  notify,
     789                               GConnectFlags   flags,
     790                               gboolean        is_object)
     791  {
     792    GClosure *closure;
     793  
     794    g_return_if_fail (c_handler != NULL);
     795    g_return_if_fail (!is_object || G_IS_OBJECT (data));
     796  
     797    if ((flags & G_CONNECT_SWAPPED) != 0)
     798      closure = g_cclosure_new_swap (c_handler, data, notify);
     799    else
     800      closure = g_cclosure_new (c_handler, data, notify);
     801  
     802    if (is_object)
     803      {
     804        /* Set closure->is_invalid when data is disposed. We only track this to avoid
     805         * reconnecting in the future. However, we do a round of cleanup when ever we
     806         * connect a new object or the target changes to GC the old handlers.
     807         */
     808        g_object_watch_closure (data, closure);
     809      }
     810  
     811    if (!g_signal_group_connect_closure_ (self,
     812                                          detailed_signal,
     813                                          closure,
     814                                          (flags & G_CONNECT_AFTER) != 0))
     815      g_closure_unref (closure);
     816  }
     817  
     818  /**
     819   * g_signal_group_connect_object: (skip)
     820   * @self: a #GSignalGroup
     821   * @detailed_signal: a string of the form `signal-name` with optional `::signal-detail`
     822   * @c_handler: (scope notified): the #GCallback to connect
     823   * @object: (not nullable) (transfer none): the #GObject to pass as data to @c_handler calls
     824   * @flags: #GConnectFlags for the signal connection
     825   *
     826   * Connects @c_handler to the signal @detailed_signal on #GSignalGroup:target.
     827   *
     828   * Ensures that the @object stays alive during the call to @c_handler
     829   * by temporarily adding a reference count. When the @object is destroyed
     830   * the signal handler will automatically be removed.
     831   *
     832   * You cannot connect a signal handler after #GSignalGroup:target has been set.
     833   *
     834   * Since: 2.72
     835   */
     836  void
     837  g_signal_group_connect_object (GSignalGroup  *self,
     838                                 const gchar   *detailed_signal,
     839                                 GCallback      c_handler,
     840                                 gpointer       object,
     841                                 GConnectFlags  flags)
     842  {
     843    g_return_if_fail (G_IS_OBJECT (object));
     844  
     845    g_signal_group_connect_full (self, detailed_signal, c_handler, object, NULL,
     846                                 flags, TRUE);
     847  }
     848  
     849  /**
     850   * g_signal_group_connect_data:
     851   * @self: a #GSignalGroup
     852   * @detailed_signal: a string of the form "signal-name::detail"
     853   * @c_handler: (scope notified) (closure data) (destroy notify): the #GCallback to connect
     854   * @data: the data to pass to @c_handler calls
     855   * @notify: function to be called when disposing of @self
     856   * @flags: the flags used to create the signal connection
     857   *
     858   * Connects @c_handler to the signal @detailed_signal
     859   * on the target instance of @self.
     860   *
     861   * You cannot connect a signal handler after #GSignalGroup:target has been set.
     862   *
     863   * Since: 2.72
     864   */
     865  void
     866  g_signal_group_connect_data (GSignalGroup   *self,
     867                               const gchar    *detailed_signal,
     868                               GCallback       c_handler,
     869                               gpointer        data,
     870                               GClosureNotify  notify,
     871                               GConnectFlags   flags)
     872  {
     873    g_signal_group_connect_full (self, detailed_signal, c_handler, data, notify,
     874                                 flags, FALSE);
     875  }
     876  
     877  /**
     878   * g_signal_group_connect: (skip)
     879   * @self: a #GSignalGroup
     880   * @detailed_signal: a string of the form "signal-name::detail"
     881   * @c_handler: (scope notified): the #GCallback to connect
     882   * @data: the data to pass to @c_handler calls
     883   *
     884   * Connects @c_handler to the signal @detailed_signal
     885   * on the target instance of @self.
     886   *
     887   * You cannot connect a signal handler after #GSignalGroup:target has been set.
     888   *
     889   * Since: 2.72
     890   */
     891  void
     892  g_signal_group_connect (GSignalGroup *self,
     893                          const gchar  *detailed_signal,
     894                          GCallback     c_handler,
     895                          gpointer      data)
     896  {
     897    g_signal_group_connect_full (self, detailed_signal, c_handler, data, NULL,
     898                                 0, FALSE);
     899  }
     900  
     901  /**
     902   * g_signal_group_connect_after: (skip)
     903   * @self: a #GSignalGroup
     904   * @detailed_signal: a string of the form "signal-name::detail"
     905   * @c_handler: (scope notified): the #GCallback to connect
     906   * @data: the data to pass to @c_handler calls
     907   *
     908   * Connects @c_handler to the signal @detailed_signal
     909   * on the target instance of @self.
     910   *
     911   * The @c_handler will be called after the default handler of the signal.
     912   *
     913   * You cannot connect a signal handler after #GSignalGroup:target has been set.
     914   *
     915   * Since: 2.72
     916   */
     917  void
     918  g_signal_group_connect_after (GSignalGroup *self,
     919                                const gchar  *detailed_signal,
     920                                GCallback     c_handler,
     921                                gpointer      data)
     922  {
     923    g_signal_group_connect_full (self, detailed_signal, c_handler,
     924                                 data, NULL, G_CONNECT_AFTER, FALSE);
     925  }
     926  
     927  /**
     928   * g_signal_group_connect_swapped:
     929   * @self: a #GSignalGroup
     930   * @detailed_signal: a string of the form "signal-name::detail"
     931   * @c_handler: (scope async): the #GCallback to connect
     932   * @data: the data to pass to @c_handler calls
     933   *
     934   * Connects @c_handler to the signal @detailed_signal
     935   * on the target instance of @self.
     936   *
     937   * The instance on which the signal is emitted and @data
     938   * will be swapped when calling @c_handler.
     939   *
     940   * You cannot connect a signal handler after #GSignalGroup:target has been set.
     941   *
     942   * Since: 2.72
     943   */
     944  void
     945  g_signal_group_connect_swapped (GSignalGroup *self,
     946                                  const gchar  *detailed_signal,
     947                                  GCallback     c_handler,
     948                                  gpointer      data)
     949  {
     950    g_signal_group_connect_full (self, detailed_signal, c_handler, data, NULL,
     951                                 G_CONNECT_SWAPPED, FALSE);
     952  }