diff --git a/src/command/command.c b/src/command/command.c index f2ceaa82..ddcdf573 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -97,6 +97,7 @@ static char * _affiliation_autocomplete(char *input, int *size); static char * _role_autocomplete(char *input, int *size); static char * _resource_autocomplete(char *input, int *size); static char * _titlebar_autocomplete(char *input, int *size); +static char * _inpblock_autocomplete(char *input, int *size); GHashTable *commands = NULL; @@ -623,14 +624,18 @@ static struct cmd_t command_defs[] = NULL } } }, { "/inpblock", - cmd_inpblock, parse_args, 1, 1, &cons_inpblock_setting, - { "/inpblock millis", "Input blocking delay.", - { "/inpblock millis", - "----------------", - "Time to wait in milliseconds before reading input from the terminal buffer, defaults to 20.", - "Valid values are 1-1000.", - "A higher value will result in less CPU usage, but a noticable delay for response to input.", - "A lower value will result in higher CPU usage, but faster response to input.", + cmd_inpblock, parse_args, 2, 2, &cons_inpblock_setting, + { "/inpblock timeout|dynamic [millis|on|off]", "Input blocking delay (dynamic or static).", + { "/inpblock timeout|dynamic [millis|on|off]", + "-----------------------------------------", + "How long to wait for input before checking for new messages or checking for state changes such as 'idle'.", + "timeout : Time to wait in milliseconds before reading input from the terminal buffer, defaults to 500.", + " : Valid values are 1-1000.", + "dynamic : Start with a 0 timeout and increase the value dynamically up to the specified 'timeout'.", + " : on|off", + "A higher timeout will result in less CPU usage, but a noticable delay for response to input.", + "A lower timeout will result in higher CPU usage, but faster response to input.", + "Using the dynamic setting, higher CPU usage will occur during activity, but over time the CPU usage will decrease whilst there is no activity.", NULL } } }, { "/notify", @@ -1114,6 +1119,7 @@ static Autocomplete occupants_ac; static Autocomplete occupants_default_ac; static Autocomplete time_ac; static Autocomplete resource_ac; +static Autocomplete inpblock_ac; /* * Initialise command autocompleter and history @@ -1464,6 +1470,10 @@ cmd_init(void) autocomplete_add(resource_ac, "title"); autocomplete_add(resource_ac, "message"); + inpblock_ac = autocomplete_new(); + autocomplete_add(inpblock_ac, "timeout"); + autocomplete_add(inpblock_ac, "dynamic"); + cmd_history_init(); } @@ -1520,6 +1530,7 @@ cmd_uninit(void) autocomplete_free(occupants_default_ac); autocomplete_free(time_ac); autocomplete_free(resource_ac); + autocomplete_free(inpblock_ac); } gboolean @@ -1688,6 +1699,7 @@ cmd_reset_autocomplete() autocomplete_reset(occupants_default_ac); autocomplete_reset(time_ac); autocomplete_reset(resource_ac); + autocomplete_reset(inpblock_ac); if (ui_current_win_type() == WIN_CHAT) { ProfChatWin *chatwin = wins_get_current_chat(); @@ -2008,6 +2020,7 @@ _cmd_complete_parameters(char *input, int *size) g_hash_table_insert(ac_funcs, "/role", _role_autocomplete); g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete); g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete); + g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete); char parsed[*size+1]; i = 0; @@ -2513,6 +2526,24 @@ _titlebar_autocomplete(char *input, int *size) return NULL; } +static char * +_inpblock_autocomplete(char *input, int *size) +{ + char *found = NULL; + + found = autocomplete_param_with_func(input, size, "/inpblock dynamic", prefs_autocomplete_boolean_choice); + if (found != NULL) { + return found; + } + + found = autocomplete_param_with_ac(input, size, "/inpblock", inpblock_ac, FALSE); + if (found != NULL) { + return found; + } + + return NULL; +} + static char * _form_autocomplete(char *input, int *size) { diff --git a/src/command/commands.c b/src/command/commands.c index fba32b8b..18011454 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -3450,13 +3450,41 @@ cmd_notify(gchar **args, struct cmd_help_t help) gboolean cmd_inpblock(gchar **args, struct cmd_help_t help) { - char *value = args[0]; + char *subcmd = args[0]; + char *value = args[1]; int intval; - if (_strtoi(value, &intval, 1, 1000) == 0) { - cons_show("Input blocking set to %d milliseconds.", intval); - prefs_set_inpblock(intval); - ui_input_nonblocking(); + + if (g_strcmp0(subcmd, "timeout") == 0) { + if (value == NULL) { + cons_show("Usage: %s", help.usage); + return TRUE; + } + + if (_strtoi(value, &intval, 1, 1000) == 0) { + cons_show("Input blocking set to %d milliseconds.", intval); + prefs_set_inpblock(intval); + ui_input_nonblocking(FALSE); + } + + return TRUE; } + + if (g_strcmp0(subcmd, "dynamic") == 0) { + if (value == NULL) { + cons_show("Usage: %s", help.usage); + return TRUE; + } + + if (g_strcmp0(value, "on") != 0 && g_strcmp0(value, "off") != 0) { + cons_show("Dynamic must be one of 'on' or 'off'"); + return TRUE; + } + + return _cmd_set_boolean_preference(value, help, "Dynamic input blocking", PREF_INPBLOCK_DYNAMIC); + } + + cons_show("Usage: %s", help.usage); + return TRUE; } diff --git a/src/config/preferences.c b/src/config/preferences.c index 6e7ab576..5b683426 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -531,6 +531,7 @@ _get_group(preference_t pref) case PREF_ROSTER_BY: case PREF_RESOURCE_TITLE: case PREF_RESOURCE_MESSAGE: + case PREF_INPBLOCK_DYNAMIC: return PREF_GROUP_UI; case PREF_STATES: case PREF_OUTTYPE: @@ -672,6 +673,8 @@ _get_key(preference_t pref) return "resource.title"; case PREF_RESOURCE_MESSAGE: return "resource.message"; + case PREF_INPBLOCK_DYNAMIC: + return "inpblock.dynamic"; default: return NULL; } @@ -696,6 +699,7 @@ _get_default_boolean(preference_t pref) case PREF_MUC_PRIVILEGES: case PREF_PRESENCE: case PREF_WRAP: + case PREF_INPBLOCK_DYNAMIC: return TRUE; default: return FALSE; diff --git a/src/config/preferences.h b/src/config/preferences.h index a0ad2f84..9590eb64 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -100,7 +100,8 @@ typedef enum { PREF_OTR_WARN, PREF_OTR_POLICY, PREF_RESOURCE_TITLE, - PREF_RESOURCE_MESSAGE + PREF_RESOURCE_MESSAGE, + PREF_INPBLOCK_DYNAMIC } preference_t; typedef struct prof_alias_t { diff --git a/src/profanity.c b/src/profanity.c index 18bcc5f9..b28eae20 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -76,7 +76,7 @@ prof_run(const int disable_tls, char *log_level, char *account_name) { _init(disable_tls, log_level); log_info("Starting main event loop"); - ui_input_nonblocking(); + ui_input_nonblocking(TRUE); GTimer *timer = g_timer_new(); gboolean cmd_result = TRUE; jabber_conn_status_t conn_status = jabber_get_connection_status(); diff --git a/src/ui/console.c b/src/ui/console.c index d219a175..8d1f3173 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1182,7 +1182,12 @@ cons_show_chat_prefs(void) void cons_inpblock_setting(void) { - cons_show("Input block (/inpblock) : %d milliseconds", prefs_get_inpblock()); + cons_show("Input timeout (/inpblock) : %d milliseconds", prefs_get_inpblock()); + if (prefs_get_boolean(PREF_INPBLOCK_DYNAMIC)) { + cons_show("Dynamic timeout (/inpblock) : ON"); + } else { + cons_show("Dynamic timeout (/inpblock) : OFF"); + } } void diff --git a/src/ui/core.c b/src/ui/core.c index be16dfad..e0f46f6e 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -180,7 +180,11 @@ ui_get_char(char *input, int *size, int *result) wint_t ch = inp_get_char(input, size, result); if (ch != ERR && *result != ERR) { ui_reset_idle_time(); + ui_input_nonblocking(TRUE); + } else { + ui_input_nonblocking(FALSE); } + return ch; } @@ -197,9 +201,34 @@ ui_replace_input(char *input, const char * const new_input, int *size) } void -ui_input_nonblocking(void) +ui_input_nonblocking(gboolean reset) { - inp_non_block(); + static gint timeout = 0; + static gint no_input_count = 0; + + if (! prefs_get_boolean(PREF_INPBLOCK_DYNAMIC)) { + inp_non_block(prefs_get_inpblock()); + return; + } + + if (reset) { + timeout = 0; + no_input_count = 0; + } + + if (timeout < prefs_get_inpblock()) { + no_input_count++; + + if (no_input_count % 10 == 0) { + timeout += no_input_count; + + if (timeout > prefs_get_inpblock()) { + timeout = prefs_get_inpblock(); + } + } + } + + inp_non_block(timeout); } void @@ -2218,7 +2247,7 @@ ui_ask_password(void) status_bar_update_virtual(); inp_block(); inp_get_password(passwd); - inp_non_block(); + inp_non_block(prefs_get_inpblock()); return passwd; } diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index 19318745..a6877a86 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -120,9 +120,9 @@ inp_win_resize(void) } void -inp_non_block(void) +inp_non_block(gint timeout) { - wtimeout(inp_win, prefs_get_inpblock()); + wtimeout(inp_win, timeout); } void diff --git a/src/ui/inputwin.h b/src/ui/inputwin.h index eae20a51..b5a26c10 100644 --- a/src/ui/inputwin.h +++ b/src/ui/inputwin.h @@ -40,9 +40,9 @@ wint_t inp_get_char(char *input, int *size, int *result); void inp_win_reset(void); void inp_win_resize(void); void inp_put_back(void); -void inp_non_block(void); +void inp_non_block(gint); void inp_block(void); void inp_get_password(char *passwd); void inp_replace_input(char *input, const char * const new_input, int *size); -#endif \ No newline at end of file +#endif diff --git a/src/ui/ui.h b/src/ui/ui.h index 32484b9e..e28914ff 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -232,7 +232,7 @@ void ui_statusbar_new(const int win); wint_t ui_get_char(char *input, int *size, int *result); void ui_input_clear(void); -void ui_input_nonblocking(void); +void ui_input_nonblocking(gboolean); void ui_replace_input(char *input, const char * const new_input, int *size); void ui_invalid_command_usage(const char * const usage, void (*setting_func)(void)); diff --git a/src/ui/window.c b/src/ui/window.c index caef36df..3a45ab01 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -740,6 +740,8 @@ win_save_print(ProfWin *window, const char show_char, GTimeVal *tstamp, buffer_push(window->layout->buffer, show_char, time, flags, theme_item, from, message); _win_print(window, show_char, time, flags, theme_item, from, message); + // TODO: cross-reference.. this should be replaced by a real event-based system + ui_input_nonblocking(TRUE); } void @@ -952,4 +954,4 @@ win_printline_nowrap(WINDOW *win, char *msg) waddnstr(win, msg, maxx); wmove(win, cury+1, 0); -} \ No newline at end of file +} diff --git a/tests/ui/stub_ui.c b/tests/ui/stub_ui.c index ef0778d0..76b71265 100644 --- a/tests/ui/stub_ui.c +++ b/tests/ui/stub_ui.c @@ -331,7 +331,7 @@ wint_t ui_get_char(char *input, int *size, int *result) } void ui_input_clear(void) {} -void ui_input_nonblocking(void) {} +void ui_input_nonblocking(gboolean reset) {} void ui_replace_input(char *input, const char * const new_input, int *size) {} void ui_invalid_command_usage(const char * const usage, void (*setting_func)(void)) {}