GTK spinbutton does not "snap" to precise range limits (unless step is a binary fraction)
Submitted by Jonathan Tait
Link to original bug (#748392)
Description
Created attachment 302271 Patch for gtkspinbutton.c
Steps to reproduce:
- create a GtkSpinButton with {value=1.0, lower=0.0, upper=10.0, step=1.0, digits=1}
- use down-arrow to decrement from initial value of 1.0 to (indicated) 0.0
Result: value returned by gtk_spin_button_get_value() or passed to callback procedure is actually 0.0000000000000001 (to 16 decimal places)
Cause: in file gtkspinbutton.c, procedure gtk_spin_button_real_spin() does not properly apply the EPSILON factor (defined at the start of the file) to the range-limits.
The putative new value is first calculated thus: new_value = adj->value + increment;
Then, in the case of a negative increment with wrap disabled, the procedure simply decides the actual new value to be adopted thus: new_value = MAX (new_value, adj->lower);
This will correctly limit the new value to the specified range but it does not cater for the scenario where the new value is just a gnat's whisker above the lower limit due to the accumulation of floating-point errors. (If wrap is disabled, the down-arrow will be greyed-out after this last negative increment by the procedure gtk_spin_button_draw_arrow(); the limit test is effected by subroutine spin_button_at_limit() which does apply EPSILON correctly. The user will not, therefore, have another chance to down-step to the actual lower limit.)
What the above procedure should be doing is to test whether the putative new value is within-EPSILON-of-or-below the lower limit and, if so, then adopt the lower limit as the new value. Similarly for the upper limit.
If we also apply the same rationale to the cases where wrap is enabled (and eliminate some duplicated and unnecessary code), we are left with the code as presented in the attached patch.
I have tested this patch in GTK+-2.24.27 on Ubuntu 14.04 x64 (with Gimp 2.8.14 as the sole app.) and the new logic seems to cater properly with all circumstances arising (both with and without wrap enabled). However, this will need thorough testing with a range of application programs.
Please note that this also applies to GTK+3 - the data structures have changed, so too some of the names, but the logic is still the same!
Patch 302271, "Patch for gtkspinbutton.c":
gtkspinbutton.patch
Version: 2.24.x