diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/command/command.c | 7 | ||||
-rw-r--r-- | src/common.c | 14 | ||||
-rw-r--r-- | src/common.h | 8 | ||||
-rw-r--r-- | src/profanity.c | 34 | ||||
-rw-r--r-- | src/tools/history.c | 283 | ||||
-rw-r--r-- | src/tools/history.h | 45 | ||||
-rw-r--r-- | src/ui/console.c | 23 | ||||
-rw-r--r-- | src/ui/core.c | 161 | ||||
-rw-r--r-- | src/ui/inputwin.c | 982 | ||||
-rw-r--r-- | src/ui/inputwin.h | 16 | ||||
-rw-r--r-- | src/ui/ui.h | 9 | ||||
-rw-r--r-- | src/ui/window.c | 203 | ||||
-rw-r--r-- | src/ui/window.h | 7 |
13 files changed, 647 insertions, 1145 deletions
diff --git a/src/command/command.c b/src/command/command.c index f05d2a79..33e95459 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -1733,11 +1733,6 @@ cmd_process_input(char *inp) gboolean result = FALSE; g_strstrip(inp); - // add line to history if something typed - if (strlen(inp) > 0) { - ui_inp_history_append(inp); - } - // just carry on if no input if (strlen(inp) == 0) { result = TRUE; @@ -3051,4 +3046,4 @@ command_docgen(void) fclose(toc_fragment); fclose(main_fragment); g_list_free(cmds); -} \ No newline at end of file +} diff --git a/src/common.c b/src/common.c index 95deecbb..0c10a568 100644 --- a/src/common.c +++ b/src/common.c @@ -224,6 +224,18 @@ utf8_display_len(const char * const str) return len; } +gboolean +utf8_is_printable(const wint_t ch) +{ + char bytes[MB_CUR_MAX+1]; + size_t utf_len = wcrtomb(bytes, ch, NULL); + bytes[utf_len] = '\0'; + + gunichar unichar = g_utf8_get_char(bytes); + + return g_unichar_isprint(unichar) && (ch != KEY_MOUSE); +} + char * prof_getline(FILE *stream) { @@ -587,4 +599,4 @@ strip_arg_quotes(const char * const input) } return unquoted; -} \ No newline at end of file +} diff --git a/src/common.h b/src/common.h index c22706ec..a19b3ea2 100644 --- a/src/common.h +++ b/src/common.h @@ -36,6 +36,13 @@ #define COMMON_H #include <stdio.h> +#include <wchar.h> + +#ifdef HAVE_NCURSESW_NCURSES_H +#include <ncursesw/ncurses.h> +#elif HAVE_NCURSES_H +#include <ncurses.h> +#endif #include <glib.h> @@ -105,6 +112,7 @@ char * str_replace(const char *string, const char *substr, const char *replacement); int str_contains(const char str[], int size, char ch); int utf8_display_len(const char * const str); +gboolean utf8_is_printable(const wint_t ch); char * prof_getline(FILE *stream); char* release_get_latest(void); gboolean release_is_new(char *found_version); diff --git a/src/profanity.c b/src/profanity.c index 13297124..86730649 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -71,6 +71,7 @@ static void _create_directories(void); static void _connect_default(const char * const account); static gboolean idle = FALSE; +static gboolean cont = TRUE; void prof_run(const int disable_tls, char *log_level, char *account_name) @@ -79,25 +80,27 @@ prof_run(const int disable_tls, char *log_level, char *account_name) _connect_default(account_name); ui_update(); - char *line = NULL; - gboolean cmd_result = TRUE; - log_info("Starting main event loop"); - while(cmd_result) { - while(!line) { - _check_autoaway(); - line = ui_readline(); + char *line = NULL; + while(cont) { + _check_autoaway(); + + line = ui_readline(); + if (line) { + cont = cmd_process_input(line); + free(line); + line = NULL; + } else { + cont = TRUE; + } + #ifdef HAVE_LIBOTR - otr_poll(); + otr_poll(); #endif - notify_remind(); - jabber_process_events(); - ui_update(); - } - cmd_result = cmd_process_input(line); - ui_input_clear(); - FREE_SET_NULL(line); + notify_remind(); + jabber_process_events(); + ui_update(); } } @@ -209,6 +212,7 @@ _init(const int disable_tls, char *log_level) signal(SIGPIPE, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTSTP, SIG_IGN); + signal(SIGWINCH, ui_sigwinch_handler); _create_directories(); log_level_t prof_log_level = log_level_from_string(log_level); prefs_load(); diff --git a/src/tools/history.c b/src/tools/history.c deleted file mode 100644 index def10feb..00000000 --- a/src/tools/history.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * history.c - * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> - * - * This file is part of Profanity. - * - * Profanity is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Profanity is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Profanity. If not, see <http://www.gnu.org/licenses/>. - * - * In addition, as a special exception, the copyright holders give permission to - * link the code of portions of this program with the OpenSSL library under - * certain conditions as described in each individual source file, and - * distribute linked combinations including the two. - * - * You must obey the GNU General Public License in all respects for all of the - * code used other than OpenSSL. If you modify file(s) with this exception, you - * may extend this exception to your version of the file(s), but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. If you delete this exception statement from all - * source files in the program, then also delete it here. - * - */ - -#include <stdlib.h> -#include <string.h> - -#include <glib.h> - -#include "history.h" - -struct history_session_t { - GList *items; - GList *sess_curr; - GList *sess_new; - GList *orig_curr; -}; - -struct history_t { - GList *items; - guint max_size; - struct history_session_t session; -}; - -static void _replace_history_with_session(History history); -static gboolean _adding_new(History history); -static void _reset_session(History history); -static gboolean _has_session(History history); -static void _remove_first(History history); -static void _update_current_session_item(History history, char *item); -static void _add_to_history(History history, char *item); -static void _remove_last_session_item(History history); -static void _replace_current_with_original(History history); -static void _create_session(History history); -static void _session_previous(History history); -static void _session_next(History history); - -History -history_new(unsigned int size) -{ - History new_history = malloc(sizeof(struct history_t)); - new_history->items = NULL; - new_history->max_size = size; - - _reset_session(new_history); - - return new_history; -} - -void -history_append(History history, char *item) -{ - char *copied = ""; - if (item != NULL) { - copied = strdup(item); - } - - if (history->items == NULL) { - _add_to_history(history, copied); - return; - } - - if (!_has_session(history)) { - if (g_list_length(history->items) == history->max_size) { - _remove_first(history); - } - - _add_to_history(history, copied); - - } else { - _update_current_session_item(history, copied); - - if (_adding_new(history)) { - if (strcmp(history->session.sess_curr->data, "") == 0) { - _remove_last_session_item(history); - } - - _replace_history_with_session(history); - - } else { - _remove_last_session_item(history); - - char *new = strdup(history->session.sess_curr->data); - history->session.items = g_list_append(history->session.items, new); - - _replace_current_with_original(history); - _replace_history_with_session(history); - } - } -} - -char * -history_previous(History history, char *item) -{ - // no history - if (history->items == NULL) { - return NULL; - } - - char *copied = ""; - if (item != NULL) { - copied = strdup(item); - } - - if (!_has_session(history)) { - _create_session(history); - - // add the new item - history->session.items = g_list_append(history->session.items, copied); - history->session.sess_new = g_list_last(history->session.items); - - char *result = strdup(history->session.sess_curr->data); - return result; - } else { - _update_current_session_item(history, copied); - _session_previous(history); - } - - char *result = strdup(history->session.sess_curr->data); - return result; -} - -char * -history_next(History history, char *item) -{ - // no history, or no session, return NULL - if ((history->items == NULL) || (history->session.items == NULL)) { - return NULL; - } - - if (g_list_next(history->session.sess_curr) == NULL) { - return NULL; - } - - char *copied = ""; - if (item != NULL) { - copied = strdup(item); - } - - _update_current_session_item(history, copied); - _session_next(history); - - char *result = strdup(history->session.sess_curr->data); - return result; -} - -static void -_replace_history_with_session(History history) -{ - g_list_free(history->items); - history->items = g_list_copy(history->session.items); - - if (g_list_length(history->items) > history->max_size) { - _remove_first(history); - } - - _reset_session(history); -} - -static gboolean -_adding_new(History history) -{ - return (history->session.sess_curr == - g_list_last(history->session.items)); -} - -static void -_reset_session(History history) -{ - history->session.items = NULL; - history->session.sess_curr = NULL; - history->session.sess_new = NULL; - history->session.orig_curr = NULL; -} - -static gboolean -_has_session(History history) -{ - return (history->session.items != NULL); -} - -static void -_remove_first(History history) -{ - GList *first = g_list_first(history->items); - char *first_item = first->data; - history->items = g_list_remove(history->items, first_item); -} - -static void -_update_current_session_item(History history, char *item) -{ - history->session.sess_curr->data = item; -} - -static void -_add_to_history(History history, char *item) -{ - history->items = g_list_append(history->items, item); -} - -static void -_remove_last_session_item(History history) -{ - history->session.items = g_list_reverse(history->session.items); - GList *first = g_list_first(history->session.items); - history->session.items = - g_list_remove(history->session.items, first->data); - history->session.items = g_list_reverse(history->session.items); -} - -static void -_replace_current_with_original(History history) -{ - history->session.sess_curr->data = strdup(history->session.orig_curr->data); -} - -static void -_create_session(History history) -{ - history->session.items = g_list_copy(history->items); - history->session.sess_curr = g_list_last(history->session.items); - history->session.orig_curr = g_list_last(history->items); -} - -static void -_session_previous(History history) -{ - history->session.sess_curr = - g_list_previous(history->session.sess_curr); - if (history->session.orig_curr == NULL) - history->session.orig_curr = g_list_last(history->items); - else - history->session.orig_curr = - g_list_previous(history->session.orig_curr); - - if (history->session.sess_curr == NULL) { - history->session.sess_curr = g_list_first(history->session.items); - history->session.orig_curr = g_list_first(history->items); - } -} - -static void -_session_next(History history) -{ - history->session.sess_curr = g_list_next(history->session.sess_curr); - history->session.orig_curr = g_list_next(history->session.orig_curr); - - if (history->session.sess_curr == NULL) { - history->session.sess_curr = g_list_last(history->session.items); - history->session.orig_curr = NULL; - } -} diff --git a/src/tools/history.h b/src/tools/history.h deleted file mode 100644 index 7b334718..00000000 --- a/src/tools/history.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * history.h - * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> - * - * This file is part of Profanity. - * - * Profanity is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Profanity is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Profanity. If not, see <http://www.gnu.org/licenses/>. - * - * In addition, as a special exception, the copyright holders give permission to - * link the code of portions of this program with the OpenSSL library under - * certain conditions as described in each individual source file, and - * distribute linked combinations including the two. - * - * You must obey the GNU General Public License in all respects for all of the - * code used other than OpenSSL. If you modify file(s) with this exception, you - * may extend this exception to your version of the file(s), but you are not - * obligated to do so. If you do not wish to do so, delete this exception - * statement from your version. If you delete this exception statement from all - * source files in the program, then also delete it here. - * - */ - -#ifndef HISTORY_H -#define HISTORY_H - -typedef struct history_t *History; - -History history_new(unsigned int size); -char * history_previous(History history, char *item); -char * history_next(History history, char *item); -void history_append(History history, char *item); - -#endif diff --git a/src/ui/console.c b/src/ui/console.c index 2c37c40c..14ee7314 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1424,27 +1424,10 @@ cons_navigation_help(void) cons_show(""); cons_show("Navigation:"); cons_show(""); - cons_show("Alt-1 : This console window."); - cons_show("F1 : This console window."); - cons_show("Alt-2..Alt-0 : Chat windows."); - cons_show("F2..F10 : Chat windows."); + cons_show("Alt-1..Alt-0, F1..F10 : Choose window."); cons_show("Alt-LEFT, Alt-RIGHT : Previous/next chat window"); - cons_show("UP, DOWN : Navigate input history."); - cons_show("Ctrl-n, Ctrl-p : Navigate input history."); - cons_show("LEFT, RIGHT, HOME, END : Move cursor."); - cons_show("Ctrl-b, Ctrl-f, Ctrl-a, Ctrl-e : Move cursor."); - cons_show("Ctrl-LEFT, Ctrl-RIGHT : Jump word."); - cons_show("Ctrl-w : Delete previous word."); - cons_show("Alt-Backspace : Delete previous word."); - cons_show("Backspace : Delete previous character."); - cons_show("DEL : Delete next character."); - cons_show("Ctrl-d : Delete next character."); - cons_show("ESC : Clear current input."); - cons_show("Ctrl-u : Delete all previous characters."); - cons_show("TAB : Autocomplete."); - cons_show("PAGE UP, PAGE DOWN : Page the main window."); - cons_show("Shift-UP, Shift-DOWN : Page occupants/roster panel."); - cons_show("Ctrl-UP, Ctrl-DOWN : Page occupants/roster panel."); + cons_show("PAGEUP, PAGEDOWN : Page the main window."); + cons_show("Alt-PAGEUP, Alt-PAGEDOWN : Page occupants/roster panel."); cons_show(""); cons_alert(); diff --git a/src/ui/core.c b/src/ui/core.c index 85d5748a..0fde3387 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -41,6 +41,9 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include <sys/ioctl.h> +#include <unistd.h> + #ifdef HAVE_LIBXSS #include <X11/extensions/scrnsaver.h> #endif @@ -76,13 +79,15 @@ static char *win_title; static int inp_size; +static gboolean perform_resize = FALSE; + #ifdef HAVE_LIBXSS static Display *display; #endif static GTimer *ui_idle_time; -static void _win_handle_switch(const wint_t ch); +//static void _win_handle_switch(const wint_t ch); static void _win_show_history(int win_index, const char * const contact); static void _ui_draw_term_title(void); @@ -91,7 +96,9 @@ ui_init(void) { log_info("Initialising UI"); initscr(); - raw(); + nonl(); + cbreak(); + noecho(); keypad(stdscr, TRUE); if (prefs_get_boolean(PREF_MOUSE)) { mousemask(ALL_MOUSE_EVENTS, NULL); @@ -116,6 +123,12 @@ ui_init(void) } void +ui_sigwinch_handler(int sig) +{ + perform_resize = TRUE; +} + +void ui_update(void) { ProfWin *current = wins_get_current(); @@ -132,6 +145,13 @@ ui_update(void) status_bar_update_virtual(); inp_put_back(); doupdate(); + + if (perform_resize) { + signal(SIGWINCH, SIG_IGN); + ui_resize(); + perform_resize = FALSE; + signal(SIGWINCH, ui_sigwinch_handler); + } } void @@ -174,84 +194,66 @@ ui_close(void) { notifier_uninit(); wins_destroy(); + inp_close(); endwin(); } -char* +char * ui_readline(void) { - int key_type; - wint_t ch; - - char *line = inp_read(&key_type, &ch); - _win_handle_switch(ch); + return inp_readline(); +} +void +ui_page_up(void) +{ ProfWin *current = wins_get_current(); - win_handle_page(current, ch, key_type); - - if (ch == KEY_RESIZE) { - ui_resize(); - } + win_page_up(current); +} - if (ch != ERR && key_type != ERR) { - ui_reset_idle_time(); - ui_input_nonblocking(TRUE); - } else { - ui_input_nonblocking(FALSE); - } +void +ui_page_down(void) +{ + ProfWin *current = wins_get_current(); + win_page_down(current); +} - return line; +void +ui_subwin_page_up(void) +{ + ProfWin *current = wins_get_current(); + win_sub_page_up(current); } void -ui_inp_history_append(char *inp) +ui_subwin_page_down(void) { - inp_history_append(inp); + ProfWin *current = wins_get_current(); + win_sub_page_down(current); } void ui_input_clear(void) { - inp_win_reset(); + inp_win_clear(); } void ui_input_nonblocking(gboolean reset) { - 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); + inp_nonblocking(reset); } void ui_resize(void) { - log_info("Resizing UI"); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); erase(); + resizeterm(w.ws_row, w.ws_col); refresh(); + + log_info("Resizing UI"); title_bar_resize(); wins_resize_all(); status_bar_resize(); @@ -2247,14 +2249,9 @@ ui_win_unread(int index) char * ui_ask_password(void) { - char *passwd = malloc(sizeof(char) * (MAX_PASSWORD_SIZE + 1)); status_bar_get_password(); status_bar_update_virtual(); - inp_block(); - inp_get_password(passwd); - inp_non_block(prefs_get_inpblock()); - - return passwd; + return inp_get_password(); } void @@ -2939,32 +2936,32 @@ ui_hide_roster(void) } } -static void -_win_handle_switch(const wint_t ch) -{ - if (ch == KEY_F(1)) { - ui_switch_win(1); - } else if (ch == KEY_F(2)) { - ui_switch_win(2); - } else if (ch == KEY_F(3)) { - ui_switch_win(3); - } else if (ch == KEY_F(4)) { - ui_switch_win(4); - } else if (ch == KEY_F(5)) { - ui_switch_win(5); - } else if (ch == KEY_F(6)) { - ui_switch_win(6); - } else if (ch == KEY_F(7)) { - ui_switch_win(7); - } else if (ch == KEY_F(8)) { - ui_switch_win(8); - } else if (ch == KEY_F(9)) { - ui_switch_win(9); - } else if (ch == KEY_F(10)) { - ui_switch_win(0); - } -} - +//static void +//_win_handle_switch(const wint_t ch) +//{ +// if (ch == KEY_F(1)) { +// ui_switch_win(1); +// } else if (ch == KEY_F(2)) { +// ui_switch_win(2); +// } else if (ch == KEY_F(3)) { +// ui_switch_win(3); +// } else if (ch == KEY_F(4)) { +// ui_switch_win(4); +// } else if (ch == KEY_F(5)) { +// ui_switch_win(5); +// } else if (ch == KEY_F(6)) { +// ui_switch_win(6); +// } else if (ch == KEY_F(7)) { +// ui_switch_win(7); +// } else if (ch == KEY_F(8)) { +// ui_switch_win(8); +// } else if (ch == KEY_F(9)) { +// ui_switch_win(9); +// } else if (ch == KEY_F(10)) { +// ui_switch_win(0); +// } +//} +// static void _win_show_history(int win_index, const char * const contact) { diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index b2d5e420..328b92d6 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -38,6 +38,11 @@ #include <stdlib.h> #include <string.h> #include <wchar.h> +#include <sys/time.h> +#include <errno.h> + +#include <readline/readline.h> +#include <readline/history.h> #ifdef HAVE_NCURSESW_NCURSES_H #include <ncursesw/ncurses.h> @@ -50,7 +55,6 @@ #include "config/accounts.h" #include "config/preferences.h" #include "config/theme.h" -#include "tools/history.h" #include "log.h" #include "muc.h" #include "profanity.h" @@ -61,37 +65,45 @@ #include "ui/windows.h" #include "xmpp/xmpp.h" -#define _inp_win_update_virtual() pnoutrefresh(inp_win, 0, pad_start, rows-1, 0, rows-1, cols-1) - -#define KEY_CTRL_A 0001 -#define KEY_CTRL_B 0002 -#define KEY_CTRL_D 0004 -#define KEY_CTRL_E 0005 -#define KEY_CTRL_F 0006 -#define KEY_CTRL_N 0016 -#define KEY_CTRL_P 0020 -#define KEY_CTRL_U 0025 -#define KEY_CTRL_W 0027 - -#define MAX_HISTORY 100 -#define INP_WIN_MAX 1000 - static WINDOW *inp_win; -static History history; - -static char input[INP_WIN_MAX]; -static int input_len_bytes; - static int pad_start = 0; -static int rows, cols; -static int _handle_edit(int key_type, const wint_t ch); -static int _handle_alt_key(int key); -static void _handle_backspace(void); -static int _printable(const wint_t ch); -static void _clear_input(void); -static void _go_to_end(void); -static void _delete_previous_word(void); +static struct timeval p_rl_timeout; +static gint inp_timeout = 0; +static gint no_input_count = 0; + +static fd_set fds; +static int r; +static char *inp_line = NULL; +static gboolean get_password = FALSE; + +static void _inp_win_update_virtual(void); +static int _inp_printable(const wint_t ch); +static void _inp_win_handle_scroll(void); +static int _inp_offset_to_col(char *str, int offset); +static void _inp_write(char *line, int offset); + +static int _inp_rl_getc(FILE *stream); +static void _inp_rl_linehandler(char *line); +static int _inp_rl_tab_handler(int count, int key); +static int _inp_rl_clear_handler(int count, int key); +static int _inp_rl_win1_handler(int count, int key); +static int _inp_rl_win2_handler(int count, int key); +static int _inp_rl_win3_handler(int count, int key); +static int _inp_rl_win4_handler(int count, int key); +static int _inp_rl_win5_handler(int count, int key); +static int _inp_rl_win6_handler(int count, int key); +static int _inp_rl_win7_handler(int count, int key); +static int _inp_rl_win8_handler(int count, int key); +static int _inp_rl_win9_handler(int count, int key); +static int _inp_rl_win0_handler(int count, int key); +static int _inp_rl_altleft_handler(int count, int key); +static int _inp_rl_altright_handler(int count, int key); +static int _inp_rl_pageup_handler(int count, int key); +static int _inp_rl_pagedown_handler(int count, int key); +static int _inp_rl_altpageup_handler(int count, int key); +static int _inp_rl_altpagedown_handler(int count, int key); +static int _inp_rl_startup_hook(void); void create_input_window(void) @@ -101,25 +113,84 @@ create_input_window(void) #else ESCDELAY = 25; #endif - getmaxyx(stdscr, rows, cols); + if (inp_timeout == 1000) { + p_rl_timeout.tv_sec = 1; + p_rl_timeout.tv_usec = 0; + } else { + p_rl_timeout.tv_sec = 0; + p_rl_timeout.tv_usec = inp_timeout * 1000; + } + + rl_readline_name = "profanity"; + rl_getc_function = _inp_rl_getc; + rl_startup_hook = _inp_rl_startup_hook; + rl_callback_handler_install(NULL, _inp_rl_linehandler); + inp_win = newpad(1, INP_WIN_MAX); wbkgd(inp_win, theme_attrs(THEME_INPUT_TEXT));; keypad(inp_win, TRUE); wmove(inp_win, 0, 0); + _inp_win_update_virtual(); - history = history_new(MAX_HISTORY); +} + +char * +inp_readline(void) +{ + free(inp_line); + inp_line = NULL; + FD_ZERO(&fds); + FD_SET(fileno(rl_instream), &fds); + errno = 0; + r = select(FD_SETSIZE, &fds, NULL, NULL, &p_rl_timeout); + if (r < 0) { + char *err_msg = strerror(errno); + log_error("Readline failed: %s", err_msg); + return NULL; + } + + if (FD_ISSET(fileno(rl_instream), &fds)) { + rl_callback_read_char(); + + if (rl_line_buffer && + rl_line_buffer[0] != '/' && + rl_line_buffer[0] != '\0' && + rl_line_buffer[0] != '\n') { + prof_handle_activity(); + } + + ui_reset_idle_time(); + _inp_write(rl_line_buffer, rl_point); + inp_nonblocking(TRUE); + } else { + inp_nonblocking(FALSE); + prof_handle_idle(); + } + + if (inp_timeout == 1000) { + p_rl_timeout.tv_sec = 1; + p_rl_timeout.tv_usec = 0; + } else { + p_rl_timeout.tv_sec = 0; + p_rl_timeout.tv_usec = inp_timeout * 1000; + } + + if (inp_line) { + return strdup(inp_line); + } else { + return NULL; + } } void inp_win_resize(void) { - int inp_x; - getmaxyx(stdscr, rows, cols); - inp_x = getcurx(inp_win); + int col = getcurx(inp_win); + int wcols = getmaxx(stdscr); // if lost cursor off screen, move contents to show it - if (inp_x >= pad_start + cols) { - pad_start = inp_x - (cols / 2); + if (col >= pad_start + wcols) { + pad_start = col - (wcols / 2); if (pad_start < 0) { pad_start = 0; } @@ -130,127 +201,60 @@ inp_win_resize(void) } void -inp_non_block(gint timeout) -{ - wtimeout(inp_win, timeout); -} - -void -inp_block(void) +inp_nonblocking(gboolean reset) { - wtimeout(inp_win, -1); -} - -char * -inp_read(int *key_type, wint_t *ch) -{ - int display_size = utf8_display_len(input); - - // echo off, and get some more input - noecho(); - *key_type = wget_wch(inp_win, ch); - - gboolean in_command = FALSE; - if ((display_size > 0 && input[0] == '/') || - (display_size == 0 && *ch == '/')) { - in_command = TRUE; + if (! prefs_get_boolean(PREF_INPBLOCK_DYNAMIC)) { + inp_timeout = prefs_get_inpblock(); + return; } - if (*key_type == ERR) { - prof_handle_idle(); - } - if ((*key_type != ERR) && (*key_type != KEY_CODE_YES) && !in_command && _printable(*ch)) { - prof_handle_activity(); + if (reset) { + inp_timeout = 0; + no_input_count = 0; } - // if it wasn't an arrow key etc - if (!_handle_edit(*key_type, *ch)) { - if (_printable(*ch) && *key_type != KEY_CODE_YES) { - if (input_len_bytes >= INP_WIN_MAX) { - *ch = ERR; - return NULL; - } + if (inp_timeout < prefs_get_inpblock()) { + no_input_count++; - int inp_x = getcurx(inp_win); - - // handle insert if not at end of input - if (inp_x < display_size) { - char bytes[MB_CUR_MAX]; - size_t utf_len = wcrtomb(bytes, *ch, NULL); - - char *next_ch = g_utf8_offset_to_pointer(input, inp_x); - char *offset; - for (offset = &input[input_len_bytes - 1]; offset >= next_ch; offset--) { - *(offset + utf_len) = *offset; - } - int i; - for (i = 0; i < utf_len; i++) { - *(next_ch + i) = bytes[i]; - } - - input_len_bytes += utf_len; - input[input_len_bytes] = '\0'; - waddstr(inp_win, next_ch); - wmove(inp_win, 0, inp_x + 1); - - if (inp_x - pad_start > cols-3) { - pad_start++; - _inp_win_update_virtual(); - } - - // otherwise just append - } else { - char bytes[MB_CUR_MAX+1]; - size_t utf_len = wcrtomb(bytes, *ch, NULL); - - // wcrtomb can return (size_t) -1 - if (utf_len < MB_CUR_MAX) { - int i; - for (i = 0 ; i < utf_len; i++) { - input[input_len_bytes++] = bytes[i]; - } - input[input_len_bytes] = '\0'; - - bytes[utf_len] = '\0'; - waddstr(inp_win, bytes); - display_size++; - - // if gone over screen size follow input - int rows, cols; - getmaxyx(stdscr, rows, cols); - if (display_size - pad_start > cols-2) { - pad_start++; - _inp_win_update_virtual(); - } - } - } + if (no_input_count % 10 == 0) { + inp_timeout += no_input_count; - cmd_reset_autocomplete(); + if (inp_timeout > prefs_get_inpblock()) { + inp_timeout = prefs_get_inpblock(); + } } } - - echo(); - - if (*ch == '\n') { - input[input_len_bytes] = '\0'; - input_len_bytes = 0; - return strdup(input); - } else { - return NULL; - } } void -inp_get_password(char *passwd) +inp_close(void) +{ + rl_callback_handler_remove(); +} + +char* +inp_get_password(void) { - _clear_input(); + werase(inp_win); + wmove(inp_win, 0, 0); + pad_start = 0; _inp_win_update_virtual(); doupdate(); - noecho(); - mvwgetnstr(inp_win, 0, 1, passwd, MAX_PASSWORD_SIZE); - wmove(inp_win, 0, 0); - echo(); + char *password = NULL; + get_password = TRUE; + while (!password) { + password = inp_readline(); + ui_update(); + werase(inp_win); + wmove(inp_win, 0, 0); + pad_start = 0; + _inp_win_update_virtual(); + doupdate(); + } + get_password = FALSE; + status_bar_clear(); + return password; } void @@ -260,528 +264,292 @@ inp_put_back(void) } void -inp_replace_input(const char * const new_input) -{ - strncpy(input, new_input, INP_WIN_MAX); - input_len_bytes = strlen(input); - inp_win_reset(); - input[input_len_bytes] = '\0'; - waddstr(inp_win, input); - _go_to_end(); -} - -void -inp_win_reset(void) +inp_win_clear(void) { - _clear_input(); + werase(inp_win); + wmove(inp_win, 0, 0); pad_start = 0; _inp_win_update_virtual(); } -void -inp_history_append(char *inp) +static void +_inp_win_update_virtual(void) { - history_append(history, inp); + int wrows, wcols; + getmaxyx(stdscr, wrows, wcols); + pnoutrefresh(inp_win, 0, pad_start, wrows-1, 0, wrows-1, wcols-2); } static void -_clear_input(void) +_inp_write(char *line, int offset) { + int col = _inp_offset_to_col(line, offset); werase(inp_win); - wmove(inp_win, 0, 0); + waddstr(inp_win, line); + wmove(inp_win, 0, col); + _inp_win_handle_scroll(); + + _inp_win_update_virtual(); } -/* - * Deal with command editing, return 1 if ch was an edit - * key press: up, down, left, right or backspace - * return 0 if it wasn't - */ static int -_handle_edit(int key_type, const wint_t ch) -{ - char *prev = NULL; - char *next = NULL; - int inp_x = getcurx(inp_win); - int next_ch; - int display_size = utf8_display_len(input); - - // CTRL-LEFT - if ((key_type == KEY_CODE_YES) && (ch == 547 || ch == 545 || ch == 544 || ch == 540 || ch == 539) && (inp_x > 0)) { - input[input_len_bytes] = '\0'; - gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x); - curr_ch = g_utf8_find_prev_char(input, curr_ch); - gchar *prev_ch; - gunichar curr_uni; - gunichar prev_uni; - - while (curr_ch != NULL) { - curr_uni = g_utf8_get_char(curr_ch); - - if (g_unichar_isspace(curr_uni)) { - curr_ch = g_utf8_find_prev_char(input, curr_ch); - } else { - prev_ch = g_utf8_find_prev_char(input, curr_ch); - if (prev_ch == NULL) { - curr_ch = NULL; - break; - } else { - prev_uni = g_utf8_get_char(prev_ch); - if (g_unichar_isspace(prev_uni)) { - break; - } else { - curr_ch = prev_ch; - } - } - } - } +_inp_printable(const wint_t ch) +{ + char bytes[MB_CUR_MAX+1]; + size_t utf_len = wcrtomb(bytes, ch, NULL); + bytes[utf_len] = '\0'; + gunichar unichar = g_utf8_get_char(bytes); - if (curr_ch == NULL) { - inp_x = 0; - wmove(inp_win, 0, inp_x); - } else { - glong offset = g_utf8_pointer_to_offset(input, curr_ch); - inp_x = offset; - wmove(inp_win, 0, inp_x); + return g_unichar_isprint(unichar) && (ch != KEY_MOUSE); +} + +static int +_inp_offset_to_col(char *str, int offset) +{ + int i = 0; + int col = 0; + + while (i < offset && str[i] != '\0') { + gunichar uni = g_utf8_get_char(&str[i]); + size_t ch_len = mbrlen(&str[i], 4, NULL); + i += ch_len; + col++; + if (g_unichar_iswide(uni)) { + col++; } + } - // if gone off screen to left, jump left (half a screen worth) - if (inp_x <= pad_start) { - pad_start = pad_start - (cols / 2); - if (pad_start < 0) { - pad_start = 0; - } + return col; +} - _inp_win_update_virtual(); - } - return 1; - - // CTRL-RIGHT - } else if ((key_type == KEY_CODE_YES) && (ch == 562 || ch == 560 || ch == 555 || ch == 559 || ch == 554) && (inp_x < display_size)) { - input[input_len_bytes] = '\0'; - gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x); - gchar *next_ch = g_utf8_find_next_char(curr_ch, NULL); - gunichar curr_uni; - gunichar next_uni; - gboolean moved = FALSE; - - while (g_utf8_pointer_to_offset(input, next_ch) < display_size) { - curr_uni = g_utf8_get_char(curr_ch); - next_uni = g_utf8_get_char(next_ch); - curr_ch = next_ch; - next_ch = g_utf8_find_next_char(next_ch, NULL); - - if (!g_unichar_isspace(curr_uni) && g_unichar_isspace(next_uni) && moved) { - break; - } else { - moved = TRUE; - } - } +static void +_inp_win_handle_scroll(void) +{ + int col = getcurx(inp_win); + int wcols = getmaxx(stdscr); - if (next_ch == NULL) { - inp_x = display_size; - wmove(inp_win, 0, inp_x); - } else { - glong offset = g_utf8_pointer_to_offset(input, curr_ch); - if (offset == display_size - 1) { - inp_x = offset + 1; - } else { - inp_x = offset; - } - wmove(inp_win, 0, inp_x); + if (col == 0) { + pad_start = 0; + } else if (col >= pad_start + (wcols -2)) { + pad_start = col - (wcols / 2); + if (pad_start < 0) { + pad_start = 0; } - - // if gone off screen to right, jump right (half a screen worth) - if (inp_x > pad_start + cols) { - pad_start = pad_start + (cols / 2); - _inp_win_update_virtual(); + } else if (col <= pad_start) { + pad_start = pad_start - (wcols / 2); + if (pad_start < 0) { + pad_start = 0; } + } +} - return 1; - - // ALT-LEFT - } else if ((key_type == KEY_CODE_YES) && (ch == 537 || ch == 542)) { - ui_previous_win(); - return 1; - - // ALT-RIGHT - } else if ((key_type == KEY_CODE_YES) && (ch == 552 || ch == 557)) { - ui_next_win(); - return 1; - - // other editing keys - } else { - switch(ch) { - - case 27: // ESC - // check for ALT-key - next_ch = wgetch(inp_win); - if (next_ch != ERR) { - return _handle_alt_key(next_ch); - } else { - input_len_bytes = 0; - inp_win_reset(); - return 1; - } - - case 127: - _handle_backspace(); - return 1; - case KEY_BACKSPACE: - if (key_type != KEY_CODE_YES) { - return 0; - } - _handle_backspace(); - return 1; - - case KEY_DC: // DEL - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_D: - if (inp_x == display_size-1) { - gchar *start = g_utf8_substring(input, 0, inp_x); - for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) { - input[input_len_bytes] = start[input_len_bytes]; - } - input[input_len_bytes] = '\0'; - - g_free(start); - - _clear_input(); - waddstr(inp_win, input); - } else if (inp_x < display_size-1) { - gchar *start = g_utf8_substring(input, 0, inp_x); - gchar *end = g_utf8_substring(input, inp_x+1, input_len_bytes); - GString *new = g_string_new(start); - g_string_append(new, end); - - for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) { - input[input_len_bytes] = new->str[input_len_bytes]; - } - input[input_len_bytes] = '\0'; - - g_free(start); - g_free(end); - g_string_free(new, FALSE); - - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, inp_x); - } - return 1; - - case KEY_LEFT: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_B: - if (inp_x > 0) { - wmove(inp_win, 0, inp_x-1); - - // current position off screen to left - if (inp_x - 1 < pad_start) { - pad_start--; - _inp_win_update_virtual(); - } - } - return 1; - - case KEY_RIGHT: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_F: - if (inp_x < display_size) { - wmove(inp_win, 0, inp_x+1); - - // current position off screen to right - if ((inp_x + 1 - pad_start) >= cols) { - pad_start++; - _inp_win_update_virtual(); - } - } - return 1; - - case KEY_UP: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_P: - input[input_len_bytes] = '\0'; - prev = history_previous(history, input); - if (prev) { - inp_replace_input(prev); - } - return 1; - - case KEY_DOWN: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_N: - input[input_len_bytes] = '\0'; - next = history_next(history, input); - if (next) { - inp_replace_input(next); - } else if (input_len_bytes != 0) { - input[input_len_bytes] = '\0'; - history_append(history, input); - inp_replace_input(""); - } - return 1; - - case KEY_HOME: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_A: - wmove(inp_win, 0, 0); - pad_start = 0; - _inp_win_update_virtual(); - return 1; +// Readline callbacks - case KEY_END: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_E: - _go_to_end(); - return 1; - - case 9: // tab - if (input_len_bytes != 0) { - input[input_len_bytes] = '\0'; - if ((strncmp(input, "/", 1) != 0) && (ui_current_win_type() == WIN_MUC)) { - char *result = muc_autocomplete(input); - if (result) { - inp_replace_input(result); - free(result); - } - } else if (strncmp(input, "/", 1) == 0) { - char *result = cmd_autocomplete(input); - if (result) { - inp_replace_input(result); - free(result); - } - } - } - return 1; +static int +_inp_rl_startup_hook(void) +{ + rl_bind_keyseq("\\e1", _inp_rl_win1_handler); + rl_bind_keyseq("\\e2", _inp_rl_win2_handler); + rl_bind_keyseq("\\e3", _inp_rl_win3_handler); + rl_bind_keyseq("\\e4", _inp_rl_win4_handler); + rl_bind_keyseq("\\e5", _inp_rl_win5_handler); + rl_bind_keyseq("\\e6", _inp_rl_win6_handler); + rl_bind_keyseq("\\e7", _inp_rl_win7_handler); + rl_bind_keyseq("\\e8", _inp_rl_win8_handler); + rl_bind_keyseq("\\e9", _inp_rl_win9_handler); + rl_bind_keyseq("\\e0", _inp_rl_win0_handler); + + rl_bind_keyseq("\\eOP", _inp_rl_win1_handler); + rl_bind_keyseq("\\eOQ", _inp_rl_win2_handler); + rl_bind_keyseq("\\eOR", _inp_rl_win3_handler); + rl_bind_keyseq("\\eOS", _inp_rl_win4_handler); + rl_bind_keyseq("\\e[15~", _inp_rl_win5_handler); + rl_bind_keyseq("\\e[17~", _inp_rl_win6_handler); + rl_bind_keyseq("\\e[18~", _inp_rl_win7_handler); + rl_bind_keyseq("\\e[19~", _inp_rl_win8_handler); + rl_bind_keyseq("\\e[20~", _inp_rl_win9_handler); + rl_bind_keyseq("\\e[21~", _inp_rl_win0_handler); + +#ifdef PLATFORM_OSX + rl_bind_keyseq("\\e[1;9D", _inp_rl_altleft_handler); + rl_bind_keyseq("\\e[1;9C", _inp_rl_altright_handler); + rl_bind_keyseq("\\e\\e[5~", _inp_rl_altpageup_handler); + rl_bind_keyseq("\\e\\e[6~", _inp_rl_altpagedown_handler); +#else + rl_bind_keyseq("\\e[1;3D", _inp_rl_altleft_handler); + rl_bind_keyseq("\\e[1;3C", _inp_rl_altright_handler); + rl_bind_keyseq("\\e[5;3~", _inp_rl_altpageup_handler); + rl_bind_keyseq("\\e[6;3~", _inp_rl_altpagedown_handler); +#endif + rl_bind_keyseq("\\e[5~", _inp_rl_pageup_handler); + rl_bind_keyseq("\\e[6~", _inp_rl_pagedown_handler); - case KEY_CTRL_W: - _delete_previous_word(); - return 1; - break; + rl_bind_key('\t', _inp_rl_tab_handler); + rl_bind_key(CTRL('L'), _inp_rl_clear_handler); - case KEY_CTRL_U: - while (getcurx(inp_win) > 0) { - _delete_previous_word(); - } - return 1; - break; + return 0; +} - default: - return 0; +static void +_inp_rl_linehandler(char *line) +{ + if (line && *line) { + if (!get_password) { + add_history(line); } } + inp_line = line; } -static void -_handle_backspace(void) -{ - int inp_x = getcurx(inp_win); - int display_size = utf8_display_len(input); - roster_reset_search_attempts(); - if (display_size > 0) { - - // if at end, delete last char - if (inp_x >= display_size) { - gchar *start = g_utf8_substring(input, 0, inp_x-1); - for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) { - input[input_len_bytes] = start[input_len_bytes]; - } - input[input_len_bytes] = '\0'; - - g_free(start); +static int +_inp_rl_getc(FILE *stream) +{ + int ch = rl_getc(stream); + if (_inp_printable(ch)) { + cmd_reset_autocomplete(); + } + return ch; +} - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, inp_x -1); +static int +_inp_rl_clear_handler(int count, int key) +{ + ui_clear_current(); + return 0; +} - // if in middle, delete and shift chars left - } else if (inp_x > 0 && inp_x < display_size) { - gchar *start = g_utf8_substring(input, 0, inp_x - 1); - gchar *end = g_utf8_substring(input, inp_x, input_len_bytes); - GString *new = g_string_new(start); - g_string_append(new, end); +static int +_inp_rl_tab_handler(int count, int key) +{ + if (rl_point != rl_end || !rl_line_buffer) { + return 0; + } - for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) { - input[input_len_bytes] = new->str[input_len_bytes]; - } - input[input_len_bytes] = '\0'; + if ((strncmp(rl_line_buffer, "/", 1) != 0) && (ui_current_win_type() == WIN_MUC)) { + char *result = muc_autocomplete(rl_line_buffer); + if (result) { + rl_replace_line(result, 0); + rl_point = rl_end; + } + } else if (strncmp(rl_line_buffer, "/", 1) == 0) { + char *result = cmd_autocomplete(rl_line_buffer); + if (result) { + rl_replace_line(result, 0); + rl_point = rl_end; + } + } - g_free(start); - g_free(end); - g_string_free(new, FALSE); + return 0; +} - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, inp_x -1); - } +static int +_inp_rl_win1_handler(int count, int key) +{ + ui_switch_win(1); + return 0; +} - // if gone off screen to left, jump left (half a screen worth) - if (inp_x <= pad_start) { - pad_start = pad_start - (cols / 2); - if (pad_start < 0) { - pad_start = 0; - } +static int +_inp_rl_win2_handler(int count, int key) +{ + ui_switch_win(2); + return 0; +} - _inp_win_update_virtual(); - } - } +static int +_inp_rl_win3_handler(int count, int key) +{ + ui_switch_win(3); + return 0; +} +static int +_inp_rl_win4_handler(int count, int key) +{ + ui_switch_win(4); + return 0; } static int -_handle_alt_key(int key) -{ - switch (key) - { - case '1': - ui_switch_win(1); - break; - case '2': - ui_switch_win(2); - break; - case '3': - ui_switch_win(3); - break; - case '4': - ui_switch_win(4); - break; - case '5': - ui_switch_win(5); - break; - case '6': - ui_switch_win(6); - break; - case '7': - ui_switch_win(7); - break; - case '8': - ui_switch_win(8); - break; - case '9': - ui_switch_win(9); - break; - case '0': - ui_switch_win(0); - break; - case KEY_LEFT: - ui_previous_win(); - break; - case KEY_RIGHT: - ui_next_win(); - break; - case 263: - case 127: - _delete_previous_word(); - break; - default: - break; - } - return 1; +_inp_rl_win5_handler(int count, int key) +{ + ui_switch_win(5); + return 0; } -static void -_delete_previous_word(void) -{ - int end_del = getcurx(inp_win); - int start_del = end_del; - - input[input_len_bytes] = '\0'; - gchar *curr_ch = g_utf8_offset_to_pointer(input, end_del); - curr_ch = g_utf8_find_prev_char(input, curr_ch); - gchar *prev_ch; - gunichar curr_uni; - gunichar prev_uni; - - while (curr_ch != NULL) { - curr_uni = g_utf8_get_char(curr_ch); - - if (g_unichar_isspace(curr_uni)) { - curr_ch = g_utf8_find_prev_char(input, curr_ch); - } else { - prev_ch = g_utf8_find_prev_char(input, curr_ch); - if (prev_ch == NULL) { - curr_ch = NULL; - break; - } else { - prev_uni = g_utf8_get_char(prev_ch); - if (g_unichar_isspace(prev_uni)) { - break; - } else { - curr_ch = prev_ch; - } - } - } - } +static int +_inp_rl_win6_handler(int count, int key) +{ + ui_switch_win(6); + return 0; +} - if (curr_ch == NULL) { - start_del = 0; - } else { - start_del = g_utf8_pointer_to_offset(input, curr_ch); - } +static int +_inp_rl_win7_handler(int count, int key) +{ + ui_switch_win(7); + return 0; +} - gint len = g_utf8_strlen(input, -1); - gchar *start_string = g_utf8_substring(input, 0, start_del); - gchar *end_string = g_utf8_substring(input, end_del, len); +static int +_inp_rl_win8_handler(int count, int key) +{ + ui_switch_win(8); + return 0; +} - int i; - for (i = 0; i < strlen(start_string); i++) { - input[i] = start_string[i]; - } - for (i = 0; i < strlen(end_string); i++) { - input[strlen(start_string)+i] = end_string[i]; - } +static int +_inp_rl_win9_handler(int count, int key) +{ + ui_switch_win(9); + return 0; +} - input_len_bytes = strlen(start_string)+i; - input[input_len_bytes] = '\0'; +static int +_inp_rl_win0_handler(int count, int key) +{ + ui_switch_win(0); + return 0; +} - g_free(start_string); - g_free(end_string); +static int +_inp_rl_altleft_handler(int count, int key) +{ + ui_previous_win(); + return 0; +} - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, start_del); +static int +_inp_rl_altright_handler(int count, int key) +{ + ui_next_win(); + return 0; +} - // if gone off screen to left, jump left (half a screen worth) - if (start_del <= pad_start) { - pad_start = pad_start - (cols / 2); - if (pad_start < 0) { - pad_start = 0; - } +static int +_inp_rl_pageup_handler(int count, int key) +{ + ui_page_up(); + return 0; +} - _inp_win_update_virtual(); - } +static int +_inp_rl_pagedown_handler(int count, int key) +{ + ui_page_down(); + return 0; } -static void -_go_to_end(void) +static int +_inp_rl_altpageup_handler(int count, int key) { - int display_size = utf8_display_len(input); - wmove(inp_win, 0, display_size); - if (display_size > cols-2) { - pad_start = display_size - cols + 1; - _inp_win_update_virtual(); - } + ui_subwin_page_up(); + return 0; } static int -_printable(const wint_t ch) +_inp_rl_altpagedown_handler(int count, int key) { - char bytes[MB_CUR_MAX+1]; - size_t utf_len = wcrtomb(bytes, ch, NULL); - bytes[utf_len] = '\0'; - gunichar unichar = g_utf8_get_char(bytes); - return g_unichar_isprint(unichar) && (ch != KEY_MOUSE); + ui_subwin_page_down(); + return 0; } diff --git a/src/ui/inputwin.h b/src/ui/inputwin.h index 39fde720..91cbb0b2 100644 --- a/src/ui/inputwin.h +++ b/src/ui/inputwin.h @@ -35,15 +35,17 @@ #ifndef UI_INPUTWIN_H #define UI_INPUTWIN_H +#include <glib.h> + +#define INP_WIN_MAX 1000 + void create_input_window(void); -char* inp_read(int *key_type, wint_t *ch); -void inp_win_reset(void); +char* inp_readline(void); +void inp_nonblocking(gboolean reset); +void inp_close(void); +void inp_win_clear(void); void inp_win_resize(void); void inp_put_back(void); -void inp_non_block(gint); -void inp_block(void); -void inp_get_password(char *passwd); -void inp_replace_input(const char * const new_input); -void inp_history_append(char *inp); +char* inp_get_password(void); #endif diff --git a/src/ui/ui.h b/src/ui/ui.h index 99e73b4a..1062eac1 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -62,6 +62,7 @@ GSList* ui_get_chat_recipients(void); gboolean ui_switch_win(const int i); void ui_next_win(void); void ui_previous_win(void); +void ui_sigwinch_handler(int sig); void ui_gone_secure(const char * const barejid, gboolean trusted); void ui_gone_insecure(const char * const barejid); @@ -218,6 +219,11 @@ void ui_tidy_wins(void); void ui_prune_wins(void); gboolean ui_swap_wins(int source_win, int target_win); +void ui_page_up(void); +void ui_page_down(void); +void ui_subwin_page_up(void); +void ui_subwin_page_down(void); + void ui_auto_away(void); void ui_end_auto_away(void); void ui_titlebar_presence(contact_presence_t presence); @@ -227,9 +233,10 @@ void ui_update_presence(const resource_presence_t resource_presence, void ui_about(void); void ui_statusbar_new(const int win); -char * ui_readline(void); +char* ui_readline(void); void ui_input_clear(void); void ui_input_nonblocking(gboolean); +void ui_write(char *line, int offset); 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 aba2f40a..585e0955 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -37,6 +37,7 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include <wchar.h> #include <glib.h> #ifdef HAVE_NCURSESW_NCURSES_H @@ -359,7 +360,101 @@ win_free(ProfWin* window) } void -win_handle_page(ProfWin *window, const wint_t ch, const int result) +win_page_up(ProfWin *window) +{ + int rows = getmaxy(stdscr); + int y = getcury(window->layout->win); + int page_space = rows - 4; + int *page_start = &(window->layout->y_pos); + + *page_start -= page_space; + + // went past beginning, show first page + if (*page_start < 0) + *page_start = 0; + + window->layout->paged = 1; + win_update_virtual(window); + + // switch off page if last line and space line visible + if ((y) - *page_start == page_space) { + window->layout->paged = 0; + } +} + +void +win_page_down(ProfWin *window) +{ + int rows = getmaxy(stdscr); + int y = getcury(window->layout->win); + int page_space = rows - 4; + int *page_start = &(window->layout->y_pos); + + *page_start += page_space; + + // only got half a screen, show full screen + if ((y - (*page_start)) < page_space) + *page_start = y - page_space; + + // went past end, show full screen + else if (*page_start >= y) + *page_start = y - page_space - 1; + + window->layout->paged = 1; + win_update_virtual(window); + + // switch off page if last line and space line visible + if ((y) - *page_start == page_space) { + window->layout->paged = 0; + } +} + +void +win_sub_page_down(ProfWin *window) +{ + + if (window->layout->type == LAYOUT_SPLIT) { + int rows = getmaxy(stdscr); + int page_space = rows - 4; + ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; + int sub_y = getcury(split_layout->subwin); + int *sub_y_pos = &(split_layout->sub_y_pos); + + *sub_y_pos += page_space; + + // only got half a screen, show full screen + if ((sub_y- (*sub_y_pos)) < page_space) + *sub_y_pos = sub_y - page_space; + + // went past end, show full screen + else if (*sub_y_pos >= sub_y) + *sub_y_pos = sub_y - page_space - 1; + + win_update_virtual(window); + } +} + +void +win_sub_page_up(ProfWin *window) +{ + if (window->layout->type == LAYOUT_SPLIT) { + int rows = getmaxy(stdscr); + int page_space = rows - 4; + ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; + int *sub_y_pos = &(split_layout->sub_y_pos); + + *sub_y_pos -= page_space; + + // went past beginning, show first page + if (*sub_y_pos < 0) + *sub_y_pos = 0; + + win_update_virtual(window); + } +} + +void +win_mouse(ProfWin *window, const wint_t ch, const int result) { int rows = getmaxy(stdscr); int y = getcury(window->layout->win); @@ -403,69 +498,6 @@ win_handle_page(ProfWin *window, const wint_t ch, const int result) } } } - - // page up - if (ch == KEY_PPAGE) { - *page_start -= page_space; - - // went past beginning, show first page - if (*page_start < 0) - *page_start = 0; - - window->layout->paged = 1; - win_update_virtual(window); - - // page down - } else if (ch == KEY_NPAGE) { - *page_start += page_space; - - // only got half a screen, show full screen - if ((y - (*page_start)) < page_space) - *page_start = y - page_space; - - // went past end, show full screen - else if (*page_start >= y) - *page_start = y - page_space - 1; - - window->layout->paged = 1; - win_update_virtual(window); - } - - // switch off page if last line and space line visible - if ((y) - *page_start == page_space) { - window->layout->paged = 0; - } - - if (window->layout->type == LAYOUT_SPLIT) { - ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; - int sub_y = getcury(split_layout->subwin); - int *sub_y_pos = &(split_layout->sub_y_pos); - - // alt up arrow - if ((result == KEY_CODE_YES) && ((ch == 565) || (ch == 337))) { - *sub_y_pos -= page_space; - - // went past beginning, show first page - if (*sub_y_pos < 0) - *sub_y_pos = 0; - - win_update_virtual(window); - - // alt down arrow - } else if ((result == KEY_CODE_YES) && ((ch == 524) || (ch == 336))) { - *sub_y_pos += page_space; - - // only got half a screen, show full screen - if ((sub_y- (*sub_y_pos)) < page_space) - *sub_y_pos = sub_y - page_space; - - // went past end, show full screen - else if (*sub_y_pos >= sub_y) - *sub_y_pos = sub_y - page_space - 1; - - win_update_virtual(window); - } - } } void @@ -959,7 +991,6 @@ _win_indent(WINDOW *win, int size) static void _win_print_wrapped(WINDOW *win, const char * const message) { - int linei = 0; int wordi = 0; char *word = malloc(strlen(message) + 1); @@ -972,18 +1003,26 @@ _win_print_wrapped(WINDOW *win, const char * const message) } free(time_pref); - while (message[linei] != '\0') { - if (message[linei] == ' ') { + gchar *curr_ch = g_utf8_offset_to_pointer(message, 0); + + while (*curr_ch != '\0') { + if (*curr_ch == ' ') { waddch(win, ' '); - linei++; - } else if (message[linei] == '\n') { + curr_ch = g_utf8_next_char(curr_ch); + } else if (*curr_ch == '\n') { waddch(win, '\n'); _win_indent(win, indent); - linei++; + curr_ch = g_utf8_next_char(curr_ch); } else { + // get word wordi = 0; - while (message[linei] != ' ' && message[linei] != '\n' && message[linei] != '\0') { - word[wordi++] = message[linei++]; + while (*curr_ch != ' ' && *curr_ch != '\n' && *curr_ch != '\0') { + size_t ch_len = mbrlen(curr_ch, 4, NULL); + int offset = 0; + while (offset < ch_len) { + word[wordi++] = curr_ch[offset++]; + } + curr_ch = g_utf8_next_char(curr_ch); } word[wordi] = '\0'; @@ -991,17 +1030,27 @@ _win_print_wrapped(WINDOW *win, const char * const message) int maxx = getmaxx(win); // word larger than line - if (strlen(word) > (maxx - indent)) { - int i; - for (i = 0; i < wordi; i++) { + if (utf8_display_len(word) > (maxx - indent)) { + gchar *word_ch = g_utf8_offset_to_pointer(word, 0); + while(*word_ch != '\0') { curx = getcurx(win); if (curx < indent) { _win_indent(win, indent); } - waddch(win, word[i]); + + gchar copy[wordi++]; + g_utf8_strncpy(copy, word_ch, 1); + + if (curx + utf8_display_len(copy) > maxx) { + waddch(win, '\n'); + _win_indent(win, indent); + } + waddstr(win, copy); + + word_ch = g_utf8_next_char(word_ch); } } else { - if (curx + strlen(word) > maxx) { + if (curx + utf8_display_len(word) > maxx) { waddch(win, '\n'); _win_indent(win, indent); } diff --git a/src/ui/window.h b/src/ui/window.h index fd10a1d7..66e4a5f2 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -178,9 +178,14 @@ void win_show_subwin(ProfWin *window); int win_roster_cols(void); int win_occpuants_cols(void); void win_printline_nowrap(WINDOW *win, char *msg); -void win_handle_page(ProfWin *current, const wint_t ch, const int result); +void win_mouse(ProfWin *current, const wint_t ch, const int result); int win_unread(ProfWin *window); gboolean win_has_active_subwin(ProfWin *window); +void win_page_up(ProfWin *window); +void win_page_down(ProfWin *window); +void win_sub_page_down(ProfWin *window); +void win_sub_page_up(ProfWin *window); + #endif |