Glib::Ex::SignalIds -- hold connected Glib signal handler IDs


 use Glib::Ex::SignalIds;
 my $ids = Glib::Ex::SignalIds->new
             ($obj, $obj->signal_connect (foo => \&do_foo),
                    $obj->signal_connect (bar => \&do_bar));

 # disconnected when object destroyed
 $ids = undef;


Glib::Ex::SignalIds holds a set of signal handler connection IDs (integers) and the object they're on. When the SignalIds is destroyed it disconnects those IDs.

This is designed as a reliable way to put connections on "external" objects which you should cleanup either in your own object destruction or when switching to a different target.

The SignalIds data object itself is compact so that it can be used on a large number of objects.

Target Object Usage

A typical use is connecting to signals on a target object which is in one of your properties. For example a Gtk2::TreeModel target in a viewer, or a Gtk2::Adjustment for scrolling. The SET_PROPERTY in a class might look like

    sub SET_PROPERTY {
      my ($self, $pspec, $newval) = @_;
      my $pname = $pspec->get_name;
      $self->{$pname} = $newval;  # per default GET_PROPERTY

      if ($pname eq 'model') {
        my $model = $newval;
        $self->{'model_ids'} = $model && Glib::Ex::SignalIds->new
               (row_inserted => \&my_insert_handler, $self),
               (row_deleted  => \&my_delete_handler, $self));

The $model && part allows undef for no model, in which case the model_ids becomes undef. Any previous SignalIds object in model_ids is discarded and thus disconnects the previous model. In real code you won't want $self in the signal user data, but something weakened to avoid a circular reference, the same as for all signal connections.

The key to this is that the target object might change and you want a convenient way to connect to the new and disconnect from the old. If instead a sub-object or sub-widget belongs exclusively to you, never changes, and is destroyed at the same time as your object, then there's no need for disconnection and you don't need a SignalIds.


SignalIds only keeps a weak reference to the target object, letting whoever or whatever has connected the IDs manage the target lifetime. In particular this weakening means a SignalIds object can be kept in the instance data of the target object itself without creating a circular reference.

If the target object is destroyed then all its signals are disconnected. SignalIds knows no explicit disconnects are needed in that case. SignalIds also knows some forms of weakening can give slightly odd situations where the target object has disconnected its signals but Perl hasn't yet zapped references to the object. For that reason SignalIds checks whether IDs are still connected before disconnecting, to avoid warnings from Glib.

Warnings for "already disconnected" during target object destruction tend to be a bit subtle. You can end up with the Perl-level object hash still existing yet all signals on the object already disconnected. SignalIds is a handy way to avoid trouble.

Global Destruction

During global destruction SignalIds doesn't disconnect any signals. This avoids warnings like

    (in cleanup) Foo=HASH(0x91e6ca0) is not a proper Glib::Object
        (it doesn't contain the right magic)
        at /usr/share/perl5/Glib/Ex/ line 70 during global destruction.

Objects are destroyed in an unspecified order during global destruction so it can happen that the target is already gone. Perl is about to exit anyway so disconnecting handlers is not necessary. (See "Global Destruction" in perlobj.)


$sigids = Glib::Ex::SignalIds->new ($object, $id1,$id2,...)

Create and return a SignalIds object holding the given $id signal handler IDs (integers) which are connected on $object (a Glib::Object).

SignalIds doesn't actually connect handlers. You do that with signal_connect() etc in the usual ways and all the various possible "before", "after", user data, detail, etc, then just pass the resulting ID to SignalIds to look after. Eg.

    my $sigids = Glib::Ex::SignalIds->new
        ($obj, $obj->signal_connect (foo => \&do_foo),
               $obj->signal_connect_after (bar => \&do_bar));
$sigids->add ($id1, $id2, ...)

Add further signal IDs to $sigids for the $object. This can be a further connection made later on, or only conditionally.

    my $sigids = Glib::Ex::SignalIds->new ($obj);
    $sigids->add ($obj->signal_connect (foo => \&do_foo));
    $sigids->add ($obj->signal_connect (bar => \&do_bar));

Adding IDs one by one is good if one of the signal_connect() calls might error out. Previous connections are safely in the $sigids and will be cleaned up, whereas in a multiple-ID call some could leak on an error. An error making a connection is unlikely, unless perhaps the signal name comes in externally, or the target object class hasn't been checked.

$object = $sigids->object()

Return the object held in $sigids, or undef if it's been destroyed (zapped by weakening).

@ids = $sigids->ids()

Return a list of the signal IDs held in $sigids (possibly an empty list if nothing held).


Disconnect all the signal IDs held in $sigids, if not already disconnected.

This is done automatically when $sigids is garbage collected, but you can do it explicitly sooner if desired. New signal IDs on the same $obj can be added again later with add.


Glib::Object, Glib::Ex::SourceIds, Glib::Ex::SignalBits



Copyright 2008, 2009, 2010, 2011, 2012, 2014 Kevin Ryde

Glib-Ex-ObjectBits is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

Glib-Ex-ObjectBits is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Glib-Ex-ObjectBits. If not, see