st/adjustment: Ensure changed signal emission is compressed

The docs say that `st_adjustment_set_values()` emits the `changed`
signal only once but it's actually emitted for each changed property,
this uses the `dispatch_properties_changed` vfunc to emit the `changed`
signal only per call to `st_adjustment_set_values()`. As a positive
side effect this also makes it possible to use `g_object_freeze/thaw_notify`
to compress the `changed` signal emission when using the setters for
properties.

This also fixes the wrong emission of the `changed` signal in
`st_adjustment_set_values()` when only the `value` property is changed.

Side note: the code is heavily inspired by GtkAdjustment

Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3023>
This commit is contained in:
Julian Sparber 2023-11-21 11:20:06 +01:00
parent 81f18d7ddb
commit 78eb5f2a68

View File

@ -282,6 +282,34 @@ st_adjustment_dispose (GObject *object)
G_OBJECT_CLASS (st_adjustment_parent_class)->dispose (object); G_OBJECT_CLASS (st_adjustment_parent_class)->dispose (object);
} }
static void
st_adjustment_dispatch_properties_changed (GObject *object,
guint n_pspecs,
GParamSpec **pspecs)
{
gboolean changed = FALSE;
gint i;
G_OBJECT_CLASS (st_adjustment_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
for (i = 0; i < n_pspecs; i++)
switch (pspecs[i]->param_id)
{
case PROP_LOWER:
case PROP_UPPER:
case PROP_STEP_INC:
case PROP_PAGE_INC:
case PROP_PAGE_SIZE:
changed = TRUE;
break;
default:
break;
}
if (changed)
g_signal_emit (object, signals[CHANGED], 0);
}
static void static void
st_adjustment_class_init (StAdjustmentClass *klass) st_adjustment_class_init (StAdjustmentClass *klass)
{ {
@ -291,6 +319,7 @@ st_adjustment_class_init (StAdjustmentClass *klass)
object_class->get_property = st_adjustment_get_property; object_class->get_property = st_adjustment_get_property;
object_class->set_property = st_adjustment_set_property; object_class->set_property = st_adjustment_set_property;
object_class->dispose = st_adjustment_dispose; object_class->dispose = st_adjustment_dispose;
object_class->dispatch_properties_changed = st_adjustment_dispatch_properties_changed;
/** /**
* StAdjustment:actor: * StAdjustment:actor:
@ -544,11 +573,11 @@ st_adjustment_clamp_page (StAdjustment *adjustment,
* When setting multiple adjustment properties via their individual * When setting multiple adjustment properties via their individual
* setters, multiple #GObject::notify and #StAdjustment::changed * setters, multiple #GObject::notify and #StAdjustment::changed
* signals will be emitted. However, its possible to compress the * signals will be emitted. However, its possible to compress the
* #GObject::notify signals into one by calling * #GObject::notify and #StAdjustment::changed signals into one of each
* g_object_freeze_notify() and g_object_thaw_notify() around the * by calling g_object_freeze_notify() and g_object_thaw_notify() around the
* calls to the individual setters. * calls to the individual setters.
* *
* Alternatively, using st_adjustment_set_values() will compress both * Alternatively, st_adjustment_set_values() can be used to compress
* #GObject::notify and #StAdjustment::changed emissions. * #GObject::notify and #StAdjustment::changed emissions.
*/ */
static gboolean static gboolean
@ -561,8 +590,6 @@ st_adjustment_set_lower (StAdjustment *adjustment,
{ {
priv->lower = lower; priv->lower = lower;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_LOWER]); g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_LOWER]);
/* Defer clamp until after construction. */ /* Defer clamp until after construction. */
@ -600,8 +627,6 @@ st_adjustment_set_upper (StAdjustment *adjustment,
{ {
priv->upper = upper; priv->upper = upper;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_UPPER]); g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_UPPER]);
/* Defer clamp until after construction. */ /* Defer clamp until after construction. */
@ -636,8 +661,6 @@ st_adjustment_set_step_increment (StAdjustment *adjustment,
{ {
priv->step_increment = step; priv->step_increment = step;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_STEP_INC]); g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_STEP_INC]);
return TRUE; return TRUE;
@ -668,8 +691,6 @@ st_adjustment_set_page_increment (StAdjustment *adjustment,
{ {
priv->page_increment = page; priv->page_increment = page;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_PAGE_INC]); g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_PAGE_INC]);
return TRUE; return TRUE;
@ -700,8 +721,6 @@ st_adjustment_set_page_size (StAdjustment *adjustment,
{ {
priv->page_size = size; priv->page_size = size;
g_signal_emit (adjustment, signals[CHANGED], 0);
g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_PAGE_SIZE]); g_object_notify_by_pspec (G_OBJECT (adjustment), props[PROP_PAGE_SIZE]);
/* We'll explicitly clamp after construction. */ /* We'll explicitly clamp after construction. */
@ -728,8 +747,8 @@ st_adjustment_set_page_size (StAdjustment *adjustment,
* *
* Use this function to avoid multiple emissions of the #GObject::notify and * Use this function to avoid multiple emissions of the #GObject::notify and
* #StAdjustment::changed signals. See st_adjustment_set_lower() for an * #StAdjustment::changed signals. See st_adjustment_set_lower() for an
* alternative way of compressing multiple emissions of #GObject::notify into * alternative way of compressing multiple emissions of #GObject::notify and
* one. * #StAdjustmet::changed into one of each.
*/ */
void void
st_adjustment_set_values (StAdjustment *adjustment, st_adjustment_set_values (StAdjustment *adjustment,
@ -740,34 +759,19 @@ st_adjustment_set_values (StAdjustment *adjustment,
gdouble page_increment, gdouble page_increment,
gdouble page_size) gdouble page_size)
{ {
StAdjustmentPrivate *priv;
gboolean emit_changed = FALSE;
g_return_if_fail (ST_IS_ADJUSTMENT (adjustment)); g_return_if_fail (ST_IS_ADJUSTMENT (adjustment));
g_return_if_fail (page_size >= 0 && page_size <= G_MAXDOUBLE); g_return_if_fail (page_size >= 0 && page_size <= G_MAXDOUBLE);
g_return_if_fail (step_increment >= 0 && step_increment <= G_MAXDOUBLE); g_return_if_fail (step_increment >= 0 && step_increment <= G_MAXDOUBLE);
g_return_if_fail (page_increment >= 0 && page_increment <= G_MAXDOUBLE); g_return_if_fail (page_increment >= 0 && page_increment <= G_MAXDOUBLE);
priv = st_adjustment_get_instance_private (adjustment);
emit_changed = FALSE;
g_object_freeze_notify (G_OBJECT (adjustment)); g_object_freeze_notify (G_OBJECT (adjustment));
emit_changed |= st_adjustment_set_lower (adjustment, lower); st_adjustment_set_lower (adjustment, lower);
emit_changed |= st_adjustment_set_upper (adjustment, upper); st_adjustment_set_upper (adjustment, upper);
emit_changed |= st_adjustment_set_step_increment (adjustment, step_increment); st_adjustment_set_step_increment (adjustment, step_increment);
emit_changed |= st_adjustment_set_page_increment (adjustment, page_increment); st_adjustment_set_page_increment (adjustment, page_increment);
emit_changed |= st_adjustment_set_page_size (adjustment, page_size); st_adjustment_set_page_size (adjustment, page_size);
st_adjustment_set_value (adjustment, value);
if (value != priv->value)
{
st_adjustment_set_value (adjustment, value);
emit_changed = TRUE;
}
if (emit_changed)
g_signal_emit (G_OBJECT (adjustment), signals[CHANGED], 0);
g_object_thaw_notify (G_OBJECT (adjustment)); g_object_thaw_notify (G_OBJECT (adjustment));
} }