From 19bb0203e9ff24a00355f99015b1d44c75bff8af Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 15 Oct 2022 21:22:38 +0300 Subject: [PATCH 37/37] gtk: Make property_page_change_value() to refresh widget only for changes It was already documented to refresh widget when there was something to change. Not doing that failed to abort a loop where widget refresh triggered "changed" signal again, in gtk4-client See osdn #45874 Signed-off-by: Marko Lindqvist --- client/gui-gtk-3.0/editprop.c | 38 +++++++++++++++++----------- client/gui-gtk-3.22/editprop.c | 38 +++++++++++++++++----------- client/gui-gtk-4.0/editprop.c | 46 +++++++++++++++++++++------------- 3 files changed, 74 insertions(+), 48 deletions(-) diff --git a/client/gui-gtk-3.0/editprop.c b/client/gui-gtk-3.0/editprop.c index c9b7f6e60c..0ad842137d 100644 --- a/client/gui-gtk-3.0/editprop.c +++ b/client/gui-gtk-3.0/editprop.c @@ -219,7 +219,7 @@ static const char *valtype_get_name(enum value_types valtype); To add a new member to union propval_data, see the steps for adding a new value type above. - New property values are "constructed" by objbind_get_value_from_object. + New property values are "constructed" by objbind_get_value_from_object(). ****************************************************************************/ union propval_data { gpointer v_pointer; @@ -477,7 +477,7 @@ static bool objbind_get_allowed_value_span(struct objbind *ob, double *pmax, double *pstep, double *pbig_step); -static void objbind_set_modified_value(struct objbind *ob, +static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv); static struct propval *objbind_get_modified_value(struct objbind *ob, @@ -1187,9 +1187,10 @@ static bool propval_equal(struct propval *pva, case VALTYPE_BOOL: return pva->data.v_bool == pvb->data.v_bool; case VALTYPE_STRING: - if (pva->data.v_const_string && pvb->data.v_const_string) { - return 0 == strcmp(pva->data.v_const_string, - pvb->data.v_const_string); + if (pva->data.v_const_string != NULL + && pvb->data.v_const_string != NULL) { + return !strcmp(pva->data.v_const_string, + pvb->data.v_const_string); } return pva->data.v_const_string == pvb->data.v_const_string; case VALTYPE_PIXBUF: @@ -1428,7 +1429,7 @@ static void objbind_request_destroy_object(struct objbind *ob) Returns a newly allocated property value for the given object property on the object referenced by the given object bind, or NULL on failure. - NB: You must call propval_free on the non-NULL return value when it + NB: You must call propval_free() on the non-NULL return value when it no longer needed. ****************************************************************************/ static struct propval *objbind_get_value_from_object(struct objbind *ob, @@ -2097,8 +2098,10 @@ static void objbind_clear_all_modified_values(struct objbind *ob) /************************************************************************//** Store a modified property value, but only if it is different from the current value. Always makes a copy of the given value when storing. + + Returns whether anything changed. ****************************************************************************/ -static void objbind_set_modified_value(struct objbind *ob, +static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv) { @@ -2108,14 +2111,14 @@ static void objbind_set_modified_value(struct objbind *ob, enum object_property_ids propid; if (!ob || !op) { - return; + return FALSE; } propid = objprop_get_id(op); pv_old = objbind_get_value_from_object(ob, op); if (!pv_old) { - return; + return FALSE; } equal = propval_equal(pv, pv_old); @@ -2123,7 +2126,7 @@ static void objbind_set_modified_value(struct objbind *ob, if (equal) { objbind_clear_modified_value(ob, op); - return; + return FALSE; } pv_copy = propval_copy(pv); @@ -2134,6 +2137,8 @@ static void objbind_set_modified_value(struct objbind *ob, ps = propstate_new(op, pv_copy); propstate_hash_insert(ob->propstate_table, propid, ps); } + + return TRUE; } /************************************************************************//** @@ -3111,8 +3116,8 @@ static void objprop_refresh_widget(struct objprop *op, propid = objprop_get_id(op); /* NB: We must take care to propval_free the return value of - * objbind_get_value_from_object, since it always makes a - * copy, but to NOT free the result of objbind_get_modified_value + * objbind_get_value_from_object(), since it always makes a + * copy, but to NOT free the result of objbind_get_modified_value() * since it returns its own stored value. */ pv = objbind_get_value_from_object(ob, op); modified = objbind_property_is_modified(ob, op); @@ -5446,6 +5451,7 @@ static void property_page_change_value(struct property_page *pp, GtkTreePath *path; GtkTreeIter iter; struct objbind *ob; + bool changed = FALSE; if (!pp || !op || !pp->object_view) { return; @@ -5462,14 +5468,16 @@ static void property_page_change_value(struct property_page *pp, path = p->data; if (gtk_tree_model_get_iter(model, &iter, path)) { gtk_tree_model_get(model, &iter, 0, &ob, -1); - objbind_set_modified_value(ob, op, pv); + changed |= objbind_set_modified_value(ob, op, pv); } gtk_tree_path_free(path); } g_list_free(rows); - ob = property_page_get_focused_objbind(pp); - objprop_refresh_widget(op, ob); + if (changed) { + ob = property_page_get_focused_objbind(pp); + objprop_refresh_widget(op, ob); + } } /************************************************************************//** diff --git a/client/gui-gtk-3.22/editprop.c b/client/gui-gtk-3.22/editprop.c index c48ff75722..f04c1db1ae 100644 --- a/client/gui-gtk-3.22/editprop.c +++ b/client/gui-gtk-3.22/editprop.c @@ -219,7 +219,7 @@ static const char *valtype_get_name(enum value_types valtype); To add a new member to union propval_data, see the steps for adding a new value type above. - New property values are "constructed" by objbind_get_value_from_object. + New property values are "constructed" by objbind_get_value_from_object(). ****************************************************************************/ union propval_data { gpointer v_pointer; @@ -477,7 +477,7 @@ static bool objbind_get_allowed_value_span(struct objbind *ob, double *pmax, double *pstep, double *pbig_step); -static void objbind_set_modified_value(struct objbind *ob, +static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv); static struct propval *objbind_get_modified_value(struct objbind *ob, @@ -1187,9 +1187,10 @@ static bool propval_equal(struct propval *pva, case VALTYPE_BOOL: return pva->data.v_bool == pvb->data.v_bool; case VALTYPE_STRING: - if (pva->data.v_const_string && pvb->data.v_const_string) { - return 0 == strcmp(pva->data.v_const_string, - pvb->data.v_const_string); + if (pva->data.v_const_string != NULL + && pvb->data.v_const_string != NULL) { + return !strcmp(pva->data.v_const_string, + pvb->data.v_const_string); } return pva->data.v_const_string == pvb->data.v_const_string; case VALTYPE_PIXBUF: @@ -1428,7 +1429,7 @@ static void objbind_request_destroy_object(struct objbind *ob) Returns a newly allocated property value for the given object property on the object referenced by the given object bind, or NULL on failure. - NB: You must call propval_free on the non-NULL return value when it + NB: You must call propval_free() on the non-NULL return value when it no longer needed. ****************************************************************************/ static struct propval *objbind_get_value_from_object(struct objbind *ob, @@ -2097,8 +2098,10 @@ static void objbind_clear_all_modified_values(struct objbind *ob) /************************************************************************//** Store a modified property value, but only if it is different from the current value. Always makes a copy of the given value when storing. + + Returns whether anything changed. ****************************************************************************/ -static void objbind_set_modified_value(struct objbind *ob, +static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv) { @@ -2108,14 +2111,14 @@ static void objbind_set_modified_value(struct objbind *ob, enum object_property_ids propid; if (!ob || !op) { - return; + return FALSE; } propid = objprop_get_id(op); pv_old = objbind_get_value_from_object(ob, op); if (!pv_old) { - return; + return FALSE; } equal = propval_equal(pv, pv_old); @@ -2123,7 +2126,7 @@ static void objbind_set_modified_value(struct objbind *ob, if (equal) { objbind_clear_modified_value(ob, op); - return; + return FALSE; } pv_copy = propval_copy(pv); @@ -2134,6 +2137,8 @@ static void objbind_set_modified_value(struct objbind *ob, ps = propstate_new(op, pv_copy); propstate_hash_insert(ob->propstate_table, propid, ps); } + + return TRUE; } /************************************************************************//** @@ -3111,8 +3116,8 @@ static void objprop_refresh_widget(struct objprop *op, propid = objprop_get_id(op); /* NB: We must take care to propval_free the return value of - * objbind_get_value_from_object, since it always makes a - * copy, but to NOT free the result of objbind_get_modified_value + * objbind_get_value_from_object(), since it always makes a + * copy, but to NOT free the result of objbind_get_modified_value() * since it returns its own stored value. */ pv = objbind_get_value_from_object(ob, op); modified = objbind_property_is_modified(ob, op); @@ -5446,6 +5451,7 @@ static void property_page_change_value(struct property_page *pp, GtkTreePath *path; GtkTreeIter iter; struct objbind *ob; + bool changed = FALSE; if (!pp || !op || !pp->object_view) { return; @@ -5462,14 +5468,16 @@ static void property_page_change_value(struct property_page *pp, path = p->data; if (gtk_tree_model_get_iter(model, &iter, path)) { gtk_tree_model_get(model, &iter, 0, &ob, -1); - objbind_set_modified_value(ob, op, pv); + changed |= objbind_set_modified_value(ob, op, pv); } gtk_tree_path_free(path); } g_list_free(rows); - ob = property_page_get_focused_objbind(pp); - objprop_refresh_widget(op, ob); + if (changed) { + ob = property_page_get_focused_objbind(pp); + objprop_refresh_widget(op, ob); + } } /************************************************************************//** diff --git a/client/gui-gtk-4.0/editprop.c b/client/gui-gtk-4.0/editprop.c index 079e40f1f0..7d1857a97d 100644 --- a/client/gui-gtk-4.0/editprop.c +++ b/client/gui-gtk-4.0/editprop.c @@ -219,7 +219,7 @@ static const char *valtype_get_name(enum value_types valtype); To add a new member to union propval_data, see the steps for adding a new value type above. - New property values are "constructed" by objbind_get_value_from_object. + New property values are "constructed" by objbind_get_value_from_object(). ****************************************************************************/ union propval_data { gpointer v_pointer; @@ -437,7 +437,7 @@ static void objprop_set_extviewer(struct objprop *op, static struct extviewer *objprop_get_extviewer(struct objprop *op); static void objprop_refresh_widget(struct objprop *op, struct objbind *ob); -static void objprop_widget_text_changed(GtkText *text, gpointer userdata); +static void objprop_widget_text_changed(GtkEditable *text, gpointer userdata); static void objprop_widget_spin_button_changed(GtkSpinButton *spin, gpointer userdata); static void objprop_widget_toggle_button_changed(GtkToggleButton *button, @@ -477,7 +477,7 @@ static bool objbind_get_allowed_value_span(struct objbind *ob, double *pmax, double *pstep, double *pbig_step); -static void objbind_set_modified_value(struct objbind *ob, +static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv); static struct propval *objbind_get_modified_value(struct objbind *ob, @@ -1187,9 +1187,10 @@ static bool propval_equal(struct propval *pva, case VALTYPE_BOOL: return pva->data.v_bool == pvb->data.v_bool; case VALTYPE_STRING: - if (pva->data.v_const_string && pvb->data.v_const_string) { - return 0 == strcmp(pva->data.v_const_string, - pvb->data.v_const_string); + if (pva->data.v_const_string != NULL + && pvb->data.v_const_string != NULL) { + return !strcmp(pva->data.v_const_string, + pvb->data.v_const_string); } return pva->data.v_const_string == pvb->data.v_const_string; case VALTYPE_PIXBUF: @@ -1428,7 +1429,7 @@ static void objbind_request_destroy_object(struct objbind *ob) Returns a newly allocated property value for the given object property on the object referenced by the given object bind, or NULL on failure. - NB: You must call propval_free on the non-NULL return value when it + NB: You must call propval_free() on the non-NULL return value when it no longer needed. ****************************************************************************/ static struct propval *objbind_get_value_from_object(struct objbind *ob, @@ -2097,8 +2098,10 @@ static void objbind_clear_all_modified_values(struct objbind *ob) /************************************************************************//** Store a modified property value, but only if it is different from the current value. Always makes a copy of the given value when storing. + + Returns whether anything changed. ****************************************************************************/ -static void objbind_set_modified_value(struct objbind *ob, +static bool objbind_set_modified_value(struct objbind *ob, struct objprop *op, struct propval *pv) { @@ -2108,14 +2111,14 @@ static void objbind_set_modified_value(struct objbind *ob, enum object_property_ids propid; if (!ob || !op) { - return; + return FALSE; } propid = objprop_get_id(op); pv_old = objbind_get_value_from_object(ob, op); if (!pv_old) { - return; + return FALSE; } equal = propval_equal(pv, pv_old); @@ -2123,7 +2126,7 @@ static void objbind_set_modified_value(struct objbind *ob, if (equal) { objbind_clear_modified_value(ob, op); - return; + return FALSE; } pv_copy = propval_copy(pv); @@ -2134,6 +2137,8 @@ static void objbind_set_modified_value(struct objbind *ob, ps = propstate_new(op, pv_copy); propstate_hash_insert(ob->propstate_table, propid, ps); } + + return TRUE; } /************************************************************************//** @@ -2862,7 +2867,7 @@ static bool objprop_is_readonly(const struct objprop *op) /************************************************************************//** Callback for text widget 'changed' signal. ****************************************************************************/ -static void objprop_widget_text_changed(GtkText *text, gpointer userdata) +static void objprop_widget_text_changed(GtkEditable *text, gpointer userdata) { struct objprop *op; struct property_page *pp; @@ -2870,7 +2875,7 @@ static void objprop_widget_text_changed(GtkText *text, gpointer userdata) op = userdata; pp = objprop_get_property_page(op); - value.data.v_const_string = gtk_entry_buffer_get_text(gtk_text_get_buffer(text)); + value.data.v_const_string = gtk_entry_buffer_get_text(gtk_text_get_buffer(GTK_TEXT(text))); property_page_change_value(pp, op, &value); } @@ -3112,8 +3117,8 @@ static void objprop_refresh_widget(struct objprop *op, propid = objprop_get_id(op); /* NB: We must take care to propval_free the return value of - * objbind_get_value_from_object, since it always makes a - * copy, but to NOT free the result of objbind_get_modified_value + * objbind_get_value_from_object(), since it always makes a + * copy, but to NOT free the result of objbind_get_modified_value() * since it returns its own stored value. */ pv = objbind_get_value_from_object(ob, op); modified = objbind_property_is_modified(ob, op); @@ -3196,6 +3201,8 @@ static void objprop_refresh_widget(struct objprop *op, case OPID_TILE_LABEL: text = objprop_get_child_widget(op, "text"); if (pv) { + /* Most of these are semantically in "v_const_string", + * but this works as the address is the same regardless. */ gtk_entry_buffer_set_text(gtk_text_get_buffer(GTK_TEXT(text)), pv->data.v_string, -1); } else { @@ -5475,6 +5482,7 @@ static void property_page_change_value(struct property_page *pp, GtkTreePath *path; GtkTreeIter iter; struct objbind *ob; + bool changed = FALSE; if (!pp || !op || !pp->object_view) { return; @@ -5491,14 +5499,16 @@ static void property_page_change_value(struct property_page *pp, path = p->data; if (gtk_tree_model_get_iter(model, &iter, path)) { gtk_tree_model_get(model, &iter, 0, &ob, -1); - objbind_set_modified_value(ob, op, pv); + changed |= objbind_set_modified_value(ob, op, pv); } gtk_tree_path_free(path); } g_list_free(rows); - ob = property_page_get_focused_objbind(pp); - objprop_refresh_widget(op, ob); + if (changed) { + ob = property_page_get_focused_objbind(pp); + objprop_refresh_widget(op, ob); + } } /************************************************************************//** -- 2.35.1