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