NAME

Glib::Ex::ConnectProperties -- link properties between objects

SYNOPSIS

use Glib::Ex::ConnectProperties;
my $conn = Glib::Ex::ConnectProperties->new ([$check,'active'],
                                             [$widget,'visible']);

$conn->disconnect;   # explicit disconnect

DESCRIPTION

Glib::Ex::ConnectProperties links together specified properties on two or more Glib::Objects (including Gtk widgets) so a change made to any one of them is propagated to the others.

This is an easy way to tie a user control widget to a setting elsewhere. For example a CheckButton active could be linked to the visible of another widget, letting the user click to hide or show it.

+--------------------+             +-------------+
| CheckButton/active |  <------->  | Foo/visible |
+--------------------+             +-------------+

The advantage of ConnectProperties is that it's bi-directional, so if other code changes "Foo/visible" then that change is sent to "CheckButton/active" too, ensuring the button display is up-to-date with what it's controlling, no matter how the target changes.

Property types

String, number, enum, flags, and object type properties are supported. Some boxed types like Gtk2::Gdk::Color work too, but others have potential problems (see "IMPLEMENATION NOTES" below).

Read-only properties can be given. They're read and propagated, but changes in other linked properties skip read-only destinations, which will leave different values, rather defeating the purpose of the linkage. Including a read-only probably only makes sense if the read-only one is the only one changing.

Write-only properties can be given, nothing is read out of them, they're just set from the other linked properties. Write-only properties are often pseudo "add" methods etc, so it's probably unlikely linking a write-only will do much good.

It works to connect two properties on the same object; doing so can ensure they update together. It also works to have two ConnectProperties groups with an object/property in common; a change coming from one group propagates through to the other just fine. In fact such a setup arises quite naturally if you've got two controls for the same target; neither of them needs to know the other exists.

Currently there's no transformations applied to values transferred between property settings. The intention is to have some "map" options or transformation functions on a per object+property basis.

FUNCTIONS

Glib::Ex::ConnectProperties->new ([$obj1,$prop1],[$obj,$prop2],...)

Connect two or more given object+property combinations. Each argument is an array ref to an object and a property name. For example

$conn = Glib::Ex::ConnectProperties->new
            ([$first_object, 'first-property-name'],
             [$second_object, 'second-property-name']);

The return value is a Perl object of type Glib::Ex::ConnectProperties. You can keep that to later explicitly break the connection with disconnect below, or otherwise you can ignore it.

A ConnectProperties linkage lasts as long as the linked objects exist, but it only keeps weak references to those objects, so the linkage doesn't prevent some or all of them being garbage collected.

$conn->disconnect()

Disconnect the given ConnectProperties linkage.

IMPLEMENTATION NOTES

ConnectProperties uses a notify signal handler on each object to update the others. Calling set to update makes those others emit further notify signals (even if the value is unchanged), so some care must be taken not to cause an infinite loop. The present strategy for that is twofold

  • An "in progress" flag in the ConnectProperties object, so during an update any further notify emissions are recognised as its own doing and can be ignored.

  • The value from a get is compared before doing a set. If it's already what's wanted then the set call is not made at all.

The in-progress flag is effective against immediate further notifys. They could also be avoided by disconnecting or blocking the handlers temporarily, but that'd probably take more work and bookkeeping than ignoring.

The compare-before-set is essential to cope with freeze_notify, because in that case the notify calls don't come while the "in progress" flag is on, only later, perhaps a long time later.

It might be wondered if something simpler is possible, and the short answer is that for the general case, no. The specific set_foo methods on most widgets and objects will skip an unchanged setting, but alas when using set the protection above is needed.

Equality

Glib doesn't offer much help for an "equal" test of arbitrary property values for the compare-before-set. ConnectProperties recognises the types noted above, and can use an equal or compare method at the Perl level like boxed types Gtk2::Gdk::Region and Gtk2::TreePath have. (Boxed types get copied so unfortunately you don't see the same pointer twice, let alone the same Perl ref.)

Notifies

By the way, if you're writing a widget don't forget you have to explicitly notify if changing a property anywhere outside your SET_PROPERTY method. (Extra notifies from within that method are ok and are collapsed to just one emission at the end.) This of course is a requirement of any widget, but failing to do so in particular means ConnectProperties won't work.

SEE ALSO

Glib::Object

HOME PAGE

http://www.geocities.com/user42_kevin/glib-ex-connectproperties/index.html

LICENSE

Copyright 2007, 2008 Kevin Ryde

Glib-Ex-ConnectProperties 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-ConnectProperties 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-ConnectProperties. If not, see http://www.gnu.org/licenses/.