Fix #113154: Hang double-clicking on UI elements outside a text field

The logic to handle word selection from double clicking ran even when
the event wasn't inside the button. This would pass an invalid position
to BLI_str_cursor_step_bounds_utf8 which hung.

Resolve by limiting word-selection to when the event is inside
the text editing field as well as clamping the position to ensure
it's within the allowed range.
This commit is contained in:
Campbell Barton 2023-10-03 12:13:40 +11:00
parent 779239f5e1
commit 26bb029ad8
2 changed files with 27 additions and 11 deletions

View File

@ -345,6 +345,7 @@ void BLI_str_cursor_step_bounds_utf8(
const char *str, const int str_maxlen, const int pos, int *r_start, int *r_end)
{
BLI_assert(str_maxlen >= 0);
BLI_assert(pos >= 0 && pos <= str_maxlen);
/* Identify the type of characters are on either side of the current cursor position. */
const eStrCursorDelimType prev = (pos > 0) ? cursor_delim_type_utf8(str, str_maxlen, pos - 1) :
STRCUR_DELIM_NONE;
@ -373,6 +374,7 @@ void BLI_str_cursor_step_bounds_utf32(
const char32_t *str, const int str_maxlen, const int pos, int *r_start, int *r_end)
{
BLI_assert(str_maxlen >= 0);
BLI_assert(pos >= 0 && pos <= str_maxlen);
/* Identify the type of characters are on either side of the current cursor position. */
const eStrCursorDelimType prev = (pos > 0) ? cursor_delim_type_unicode(str[pos - 1]) :
STRCUR_DELIM_NONE;

View File

@ -3771,14 +3771,21 @@ static void ui_do_but_textedit(
inbox = ui_searchbox_inside(data->searchbox, event->xy);
}
/* for double click: we do a press again for when you first click on button
* (selects all text, no cursor pos) */
bool is_press_in_button = false;
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) {
float mx = event->xy[0];
float my = event->xy[1];
ui_window_to_block_fl(data->region, block, &mx, &my);
if (ui_but_contains_pt(but, mx, my)) {
is_press_in_button = true;
}
}
/* for double click: we do a press again for when you first click on button
* (selects all text, no cursor pos) */
if (ELEM(event->val, KM_PRESS, KM_DBL_CLICK)) {
if (is_press_in_button) {
ui_textedit_set_cursor_pos(but, data, event->xy[0]);
but->selsta = but->selend = but->pos;
data->sel_pos_init = but->pos;
@ -3798,15 +3805,22 @@ static void ui_do_but_textedit(
/* only select a word in button if there was no selection before */
if (event->val == KM_DBL_CLICK && had_selection == false) {
int selsta, selend;
BLI_str_cursor_step_bounds_utf8(data->str, strlen(data->str), but->pos, &selsta, &selend);
but->pos = short(selend);
but->selsta = short(selsta);
but->selend = short(selend);
/* Anchor selection to the left side unless the last word. */
data->sel_pos_init = ((selend == strlen(data->str)) && (selsta != 0)) ? selend : selsta;
retval = WM_UI_HANDLER_BREAK;
changed = true;
if (is_press_in_button) {
const int str_len = strlen(data->str);
/* This may not be necessary, additional check to ensure `pos` is never out of range,
* since negative values aren't acceptable, see: #113154. */
CLAMP(but->pos, 0, str_len);
int selsta, selend;
BLI_str_cursor_step_bounds_utf8(data->str, str_len, but->pos, &selsta, &selend);
but->pos = short(selend);
but->selsta = short(selsta);
but->selend = short(selend);
/* Anchor selection to the left side unless the last word. */
data->sel_pos_init = ((selend == str_len) && (selsta != 0)) ? selend : selsta;
retval = WM_UI_HANDLER_BREAK;
changed = true;
}
}
else if (inbox) {
/* if we allow activation on key press,