gtk-rs-core icon indicating copy to clipboard operation
gtk-rs-core copied to clipboard

[FEATURE REQUEST] Properties macro doesn't check for equality

Open BrainBlasted opened this issue 2 years ago • 7 comments

Usually setters for GObject properties check new values for equality and return if the value is equal to the current value. This is to prevent over notifying.

BrainBlasted avatar Feb 10 '23 22:02 BrainBlasted

This will have to be opt-in as not every value is comparable in a useful way, and you probably also want to be able to provide a custom equality function to not e.g. compare GInetAddresses by pointer but by value.

Do you have a suggestion how the API could look like?

sdroege avatar Feb 10 '23 22:02 sdroege

How about:

// Uses `Eq/PartialEq`
#[property(get, set, check_eq)]
pub child: RefCell<Option<gtk::Widget>>,
// Uses custom function that takes two of `T`
#[property(get, set, check_eq = compare_address)]
pub ip: RefCell<Option<gio::InetAddress>>

BrainBlasted avatar Feb 10 '23 23:02 BrainBlasted

I think having something in the name about notification would be useful. The only difference in behaviour is that it would do a comparison and only notify if the comparison fails.

sdroege avatar Feb 11 '23 08:02 sdroege

CC @ranfdev

sdroege avatar Feb 11 '23 10:02 sdroege

I agree it's needed, I'm just not convinced about the API. In the meantime it can be implemented by the user using a custom macro set_if_changed!

#[properties(get, set = set_if_changed!(ip), explicit_notify)]
pub ip: RefCell<Option<gio::InetAddress>>

set_if_changed! can take advantage of the trait PropertySet to write inside a property. It would wrap PropertySet::set and check for equality before calling the method.

ranfdev avatar Feb 12 '23 22:02 ranfdev

There you go, it should cover 99% of the gtk use cases.

macro_rules! set_if_changed {
    ($ident:ident) => {
        |this: &&Self, val| {
            if glib::PropertyGet::get(&this.$ident, |old_val| old_val == &val) {
                return;
            }
            glib::PropertySet::set(&this.$ident, val);
            this.obj().notify(stringify!($ident));
        }

    }
}

struct MyStruct {
  #[properties(get, set = set_if_changed!(ip), explicit_notify)]
  pub ip: RefCell<Option<gio::InetAddress>>
}

ranfdev avatar Feb 12 '23 22:02 ranfdev

This unfortunately is problematic on properties with -

SeaDve avatar Feb 19 '23 03:02 SeaDve